MATH-1469: Removal of codes ported to "Commons Geometry".

Classes "FieldVector3D" and "FieldRotation" were not ported as they depend on "RealFieldElement".
diff --git a/pom.xml b/pom.xml
index ad44243..c868737 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,6 +64,7 @@
     <math.mathjax.version>2.7.2</math.mathjax.version>
     <math.commons.numbers.version>1.0-SNAPSHOT</math.commons.numbers.version>
     <math.commons.rng.version>1.2</math.commons.rng.version>
+    <math.commons.geometry.version>1.0-SNAPSHOT</math.commons.geometry.version>
 
     <commons.site.path>math</commons.site.path>
     <commons.scmPubUrl>https://svn.apache.org/repos/infra/websites/production/commons/content/proper/commons-math</commons.scmPubUrl>
@@ -169,6 +170,12 @@
 
     <dependency>
       <groupId>org.apache.commons</groupId>
+      <artifactId>commons-numbers-quaternion</artifactId>
+      <version>${math.commons.numbers.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.commons</groupId>
       <artifactId>commons-rng-client-api</artifactId>
       <version>${math.commons.rng.version}</version>
     </dependency>
@@ -186,6 +193,12 @@
     </dependency>
 
     <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-geometry-euclidean</artifactId>
+      <version>${math.commons.geometry.version}</version>
+    </dependency>
+
+    <dependency>
       <groupId>org.openjdk.jmh</groupId>
       <artifactId>jmh-core</artifactId>
       <version>${jmh.version}</version>
diff --git a/src/main/java/org/apache/commons/math4/geometry/Point.java b/src/main/java/org/apache/commons/math4/geometry/Point.java
deleted file mode 100644
index d45421a..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/Point.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.io.Serializable;
-
-/** This interface represents a generic geometrical point.
- * @param <S> Type of the space.
- * @see Space
- * @see Vector
- * @since 3.3
- */
-public interface Point<S extends Space> extends Serializable {
-
-    /** Get the space to which the point belongs.
-     * @return containing space
-     */
-    Space getSpace();
-
-    /**
-     * Returns true if any coordinate of this point is NaN; false otherwise
-     * @return  true if any coordinate of this point is NaN; false otherwise
-     */
-    boolean isNaN();
-
-    /** Compute the distance between the instance and another point.
-     * @param p second point
-     * @return the distance between the instance and p
-     */
-    double distance(Point<S> p);
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/Space.java b/src/main/java/org/apache/commons/math4/geometry/Space.java
deleted file mode 100644
index 8413c7c..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/Space.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.io.Serializable;
-
-import org.apache.commons.math4.exception.MathUnsupportedOperationException;
-
-/** This interface represents a generic space, with affine and vectorial counterparts.
- * @see Vector
- * @since 3.0
- */
-public interface Space extends Serializable {
-
-    /** Get the dimension of the space.
-     * @return dimension of the space
-     */
-    int getDimension();
-
-    /** Get the n-1 dimension subspace of this space.
-     * @return n-1 dimension sub-space of this space
-     * @see #getDimension()
-     * @exception MathUnsupportedOperationException for dimension-1 spaces
-     * which do not have sub-spaces
-     */
-    Space getSubSpace() throws MathUnsupportedOperationException;
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/Vector.java b/src/main/java/org/apache/commons/math4/geometry/Vector.java
deleted file mode 100644
index fad858e..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/Vector.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * 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.text.NumberFormat;
-
-import org.apache.commons.math4.exception.MathArithmeticException;
-
-/** This interface represents a generic vector in a vectorial space or a point in an affine space.
- * @param <S> Type of the space.
- * @see Space
- * @see Point
- * @since 3.0
- */
-public interface Vector<S extends Space> {
-
-    /** Get the space to which the point belongs.
-     * @return containing space
-     */
-    Space getSpace();
-
-    /** Get the null vector of the vectorial space or origin point of the affine space.
-     * @return null vector of the vectorial space or origin point of the affine space
-     */
-    Vector<S> getZero();
-
-    /** Get the L<sub>1</sub> norm for the vector.
-     * @return L<sub>1</sub> norm for the vector
-     */
-    double getNorm1();
-
-    /** Get the L<sub>2</sub> norm for the vector.
-     * @return Euclidean norm for the vector
-     */
-    double getNorm();
-
-    /** Get the square of the norm for the vector.
-     * @return square of the Euclidean norm for the vector
-     */
-    double getNormSq();
-
-    /** Get the L<sub>&infin;</sub> norm for the vector.
-     * @return L<sub>&infin;</sub> norm for the vector
-     */
-    double getNormInf();
-
-    /** Add a vector to the instance.
-     * @param v vector to add
-     * @return a new vector
-     */
-    Vector<S> add(Vector<S> v);
-
-    /** Add a scaled vector to the instance.
-     * @param factor scale factor to apply to v before adding it
-     * @param v vector to add
-     * @return a new vector
-     */
-    Vector<S> add(double factor, Vector<S> v);
-
-    /** Subtract a vector from the instance.
-     * @param v vector to subtract
-     * @return a new vector
-     */
-    Vector<S> subtract(Vector<S> v);
-
-    /** Subtract a scaled vector from the instance.
-     * @param factor scale factor to apply to v before subtracting it
-     * @param v vector to subtract
-     * @return a new vector
-     */
-    Vector<S> subtract(double factor, Vector<S> v);
-
-    /** Get the opposite of the instance.
-     * @return a new vector which is opposite to the instance
-     */
-    Vector<S> negate();
-
-    /** Get a normalized vector aligned with the instance.
-     * @return a new normalized vector
-     * @exception MathArithmeticException if the norm is zero
-     */
-    Vector<S> normalize() throws MathArithmeticException;
-
-    /** Multiply the instance by a scalar.
-     * @param a scalar
-     * @return a new vector
-     */
-    Vector<S> scalarMultiply(double a);
-
-    /**
-     * Returns true if any coordinate of this point is NaN; false otherwise
-     * @return  true if any coordinate of this point is NaN; false otherwise
-     */
-    boolean isNaN();
-
-    /**
-     * Returns true if any coordinate of this vector is infinite and none are NaN;
-     * false otherwise
-     * @return  true if any coordinate of this vector is infinite and none are NaN;
-     * false otherwise
-     */
-    boolean isInfinite();
-
-    /** Compute the distance between the instance and another vector according to the L<sub>1</sub> norm.
-     * <p>Calling this method is equivalent to calling:
-     * <code>q.subtract(p).getNorm1()</code> except that no intermediate
-     * vector is built</p>
-     * @param v second vector
-     * @return the distance between the instance and p according to the L<sub>1</sub> norm
-     */
-    double distance1(Vector<S> v);
-
-    /** Compute the distance between the instance and another vector.
-     * @param v second vector
-     * @return the distance between the instance and v
-     */
-    double distance(Vector<S> v);
-
-    /** Compute the distance between the instance and another vector according to the L<sub>&infin;</sub> norm.
-     * <p>Calling this method is equivalent to calling:
-     * <code>q.subtract(p).getNormInf()</code> except that no intermediate
-     * vector is built</p>
-     * @param v second vector
-     * @return the distance between the instance and p according to the L<sub>&infin;</sub> norm
-     */
-    double distanceInf(Vector<S> v);
-
-    /** Compute the square of the distance between the instance and another vector.
-     * <p>Calling this method is equivalent to calling:
-     * <code>q.subtract(p).getNormSq()</code> except that no intermediate
-     * vector is built</p>
-     * @param v second vector
-     * @return the square of the distance between the instance and p
-     */
-    double distanceSq(Vector<S> v);
-
-    /** Compute the dot-product of the instance and another vector.
-     * @param v second vector
-     * @return the dot product this.v
-     */
-    double dotProduct(Vector<S> v);
-
-    /** Get a string representation of this vector.
-     * @param format the custom format for components
-     * @return a string representation of this vector
-     */
-    String toString(final NumberFormat format);
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/VectorFormat.java b/src/main/java/org/apache/commons/math4/geometry/VectorFormat.java
deleted file mode 100644
index 7278a2f..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/VectorFormat.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * 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.text.FieldPosition;
-import java.text.NumberFormat;
-import java.text.ParsePosition;
-import java.util.Locale;
-
-import org.apache.commons.math4.exception.MathParseException;
-import org.apache.commons.math4.util.CompositeFormat;
-
-/**
- * Formats a vector in components list format "{x; y; ...}".
- * <p>The prefix and suffix "{" and "}" and the separator "; " can be replaced by
- * any user-defined strings. The number format for components can be configured.</p>
- * <p>White space is ignored at parse time, even if it is in the prefix, suffix
- * or separator specifications. So even if the default separator does include a space
- * character that is used at format time, both input string "{1;1;1}" and
- * " { 1 ; 1 ; 1 } " will be parsed without error and the same vector will be
- * returned. In the second case, however, the parse position after parsing will be
- * just after the closing curly brace, i.e. just before the trailing space.</p>
- * <p><b>Note:</b> using "," as a separator may interfere with the grouping separator
- * of the default {@link NumberFormat} for the current locale. Thus it is advised
- * to use a {@link NumberFormat} instance with disabled grouping in such a case.</p>
- *
- * @param <S> Type of the space.
- * @since 3.0
- */
-public abstract class VectorFormat<S extends Space> {
-
-    /** The default prefix: "{". */
-    public static final String DEFAULT_PREFIX = "{";
-
-    /** The default suffix: "}". */
-    public static final String DEFAULT_SUFFIX = "}";
-
-    /** The default separator: ", ". */
-    public static final String DEFAULT_SEPARATOR = "; ";
-
-    /** Prefix. */
-    private final String prefix;
-
-    /** Suffix. */
-    private final String suffix;
-
-    /** Separator. */
-    private final String separator;
-
-    /** Trimmed prefix. */
-    private final String trimmedPrefix;
-
-    /** Trimmed suffix. */
-    private final String trimmedSuffix;
-
-    /** Trimmed separator. */
-    private final String trimmedSeparator;
-
-    /** The format used for components. */
-    private final NumberFormat format;
-
-    /**
-     * Create an instance with default settings.
-     * <p>The instance uses the default prefix, suffix and separator:
-     * "{", "}", and "; " and the default number format for components.</p>
-     */
-    protected VectorFormat() {
-        this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR,
-             CompositeFormat.getDefaultNumberFormat());
-    }
-
-    /**
-     * Create an instance with a custom number format for components.
-     * @param format the custom format for components.
-     */
-    protected VectorFormat(final NumberFormat format) {
-        this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, format);
-    }
-
-    /**
-     * Create an instance with custom prefix, suffix and separator.
-     * @param prefix prefix to use instead of the default "{"
-     * @param suffix suffix to use instead of the default "}"
-     * @param separator separator to use instead of the default "; "
-     */
-    protected VectorFormat(final String prefix, final String suffix,
-                          final String separator) {
-        this(prefix, suffix, separator, CompositeFormat.getDefaultNumberFormat());
-    }
-
-    /**
-     * Create an instance with custom prefix, suffix, separator and format
-     * for components.
-     * @param prefix prefix to use instead of the default "{"
-     * @param suffix suffix to use instead of the default "}"
-     * @param separator separator to use instead of the default "; "
-     * @param format the custom format for components.
-     */
-    protected VectorFormat(final String prefix, final String suffix,
-                          final String separator, final NumberFormat format) {
-        this.prefix      = prefix;
-        this.suffix      = suffix;
-        this.separator   = separator;
-        trimmedPrefix    = prefix.trim();
-        trimmedSuffix    = suffix.trim();
-        trimmedSeparator = separator.trim();
-        this.format      = format;
-    }
-
-    /**
-     * Get the set of locales for which point/vector formats are available.
-     * <p>This is the same set as the {@link NumberFormat} set.</p>
-     * @return available point/vector format locales.
-     */
-    public static Locale[] getAvailableLocales() {
-        return NumberFormat.getAvailableLocales();
-    }
-
-    /**
-     * Get the format prefix.
-     * @return format prefix.
-     */
-    public String getPrefix() {
-        return prefix;
-    }
-
-    /**
-     * Get the format suffix.
-     * @return format suffix.
-     */
-    public String getSuffix() {
-        return suffix;
-    }
-
-    /**
-     * Get the format separator between components.
-     * @return format separator.
-     */
-    public String getSeparator() {
-        return separator;
-    }
-
-    /**
-     * Get the components format.
-     * @return components format.
-     */
-    public NumberFormat getFormat() {
-        return format;
-    }
-
-    /**
-     * Formats a {@link Vector} object to produce a string.
-     * @param vector the object to format.
-     * @return a formatted string.
-     */
-    public String format(Vector<S> vector) {
-        return format(vector, new StringBuffer(), new FieldPosition(0)).toString();
-    }
-
-    /**
-     * Formats a {@link Vector} object to produce a string.
-     * @param vector the object to format.
-     * @param toAppendTo where the text is to be appended
-     * @param pos On input: an alignment field, if desired. On output: the
-     *            offsets of the alignment field
-     * @return the value passed in as toAppendTo.
-     */
-    public abstract StringBuffer format(Vector<S> vector,
-                                        StringBuffer toAppendTo, FieldPosition pos);
-
-    /**
-     * Formats the coordinates of a {@link Vector} to produce a string.
-     * @param toAppendTo where the text is to be appended
-     * @param pos On input: an alignment field, if desired. On output: the
-     *            offsets of the alignment field
-     * @param coordinates coordinates of the object to format.
-     * @return the value passed in as toAppendTo.
-     */
-    protected StringBuffer format(StringBuffer toAppendTo, FieldPosition pos,
-                                  double ... coordinates) {
-
-        pos.setBeginIndex(0);
-        pos.setEndIndex(0);
-
-        // format prefix
-        toAppendTo.append(prefix);
-
-        // format components
-        for (int i = 0; i < coordinates.length; ++i) {
-            if (i > 0) {
-                toAppendTo.append(separator);
-            }
-            CompositeFormat.formatDouble(coordinates[i], format, toAppendTo, pos);
-        }
-
-        // format suffix
-        toAppendTo.append(suffix);
-
-        return toAppendTo;
-
-    }
-
-    /**
-     * Parses a string to produce a {@link Vector} object.
-     * @param source the string to parse
-     * @return the parsed {@link Vector} object.
-     * @throws MathParseException if the beginning of the specified string
-     * cannot be parsed.
-     */
-    public abstract Vector<S> parse(String source) throws MathParseException;
-
-    /**
-     * Parses a string to produce a {@link Vector} object.
-     * @param source the string to parse
-     * @param pos input/output parsing parameter.
-     * @return the parsed {@link Vector} object.
-     */
-    public abstract Vector<S> parse(String source, ParsePosition pos);
-
-    /**
-     * Parses a string to produce an array of coordinates.
-     * @param dimension dimension of the space
-     * @param source the string to parse
-     * @param pos input/output parsing parameter.
-     * @return coordinates array.
-     */
-    protected double[] parseCoordinates(int dimension, String source, ParsePosition pos) {
-
-        int initialIndex = pos.getIndex();
-        double[] coordinates = new double[dimension];
-
-        // parse prefix
-        CompositeFormat.parseAndIgnoreWhitespace(source, pos);
-        if (!CompositeFormat.parseFixedstring(source, trimmedPrefix, pos)) {
-            return null;
-        }
-
-        for (int i = 0; i < dimension; ++i) {
-
-            // skip whitespace
-            CompositeFormat.parseAndIgnoreWhitespace(source, pos);
-
-            // parse separator
-            if (i > 0 && !CompositeFormat.parseFixedstring(source, trimmedSeparator, pos)) {
-                return null;
-            }
-
-            // skip whitespace
-            CompositeFormat.parseAndIgnoreWhitespace(source, pos);
-
-            // parse coordinate
-            Number c = CompositeFormat.parseNumber(source, format, pos);
-            if (c == null) {
-                // invalid coordinate
-                // set index back to initial, error index should already be set
-                pos.setIndex(initialIndex);
-                return null;
-            }
-
-            // store coordinate
-            coordinates[i] = c.doubleValue();
-
-        }
-
-        // parse suffix
-        CompositeFormat.parseAndIgnoreWhitespace(source, pos);
-        if (!CompositeFormat.parseFixedstring(source, trimmedSuffix, pos)) {
-            return null;
-        }
-
-        return coordinates;
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/enclosing/Encloser.java b/src/main/java/org/apache/commons/math4/geometry/enclosing/Encloser.java
deleted file mode 100644
index 5997779..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/enclosing/Encloser.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.enclosing;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-
-/** Interface for algorithms computing enclosing balls.
- * @param <S> Space type.
- * @param <P> Point type.
- * @see EnclosingBall
- * @since 3.3
- */
-public interface Encloser<S extends Space, P extends Point<S>> {
-
-    /** Find a ball enclosing a list of points.
-     * @param points points to enclose
-     * @return enclosing ball
-     */
-    EnclosingBall<S, P> enclose(Iterable<P> points);
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/enclosing/EnclosingBall.java b/src/main/java/org/apache/commons/math4/geometry/enclosing/EnclosingBall.java
deleted file mode 100644
index 9279377..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/enclosing/EnclosingBall.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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.enclosing;
-
-import java.io.Serializable;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-
-/** This class represents a ball enclosing some points.
- * @param <S> Space type.
- * @param <P> Point type.
- * @see Space
- * @see Point
- * @see Encloser
- * @since 3.3
- */
-public class EnclosingBall<S extends Space, P extends Point<S>> implements Serializable {
-
-    /** Serializable UID. */
-    private static final long serialVersionUID = 20140126L;
-
-    /** Center of the ball. */
-    private final P center;
-
-    /** Radius of the ball. */
-    private final double radius;
-
-    /** Support points used to define the ball. */
-    private final P[] support;
-
-    /** Simple constructor.
-     * @param center center of the ball
-     * @param radius radius of the ball
-     * @param support support points used to define the ball
-     */
-    @SafeVarargs
-    public EnclosingBall(final P center, final double radius, final P ... support) {
-        this.center  = center;
-        this.radius  = radius;
-        this.support = support.clone();
-    }
-
-    /** Get the center of the ball.
-     * @return center of the ball
-     */
-    public P getCenter() {
-        return center;
-    }
-
-    /** Get the radius of the ball.
-     * @return radius of the ball (can be negative if the ball is empty)
-     */
-    public double getRadius() {
-        return radius;
-    }
-
-    /** Get the support points used to define the ball.
-     * @return support points used to define the ball
-     */
-    public P[] getSupport() {
-        return support.clone();
-    }
-
-    /** Get the number of support points used to define the ball.
-     * @return number of support points used to define the ball
-     */
-    public int getSupportSize() {
-        return support.length;
-    }
-
-    /** Check if a point is within the ball or at boundary.
-     * @param point point to test
-     * @return true if the point is within the ball or at boundary
-     */
-    public boolean contains(final P point) {
-        return point.distance(center) <= radius;
-    }
-
-    /** Check if a point is within an enlarged ball or at boundary.
-     * @param point point to test
-     * @param margin margin to consider
-     * @return true if the point is within the ball enlarged
-     * by the margin or at boundary
-     */
-    public boolean contains(final P point, final double margin) {
-        return point.distance(center) <= radius + margin;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/enclosing/SupportBallGenerator.java b/src/main/java/org/apache/commons/math4/geometry/enclosing/SupportBallGenerator.java
deleted file mode 100644
index 9886d97..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/enclosing/SupportBallGenerator.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.enclosing;
-
-import java.util.List;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-
-/** Interface for generating balls based on support points.
- * <p>
- * This generator is used in the {@link WelzlEncloser Emo Welzl} algorithm
- * and its derivatives.
- * </p>
- * @param <S> Space type.
- * @param <P> Point type.
- * @see EnclosingBall
- * @since 3.3
- */
-public interface SupportBallGenerator<S extends Space, P extends Point<S>> {
-
-    /** Create a ball whose boundary lies on prescribed support points.
-     * @param support support points (may be empty)
-     * @return ball whose boundary lies on the prescribed support points
-     */
-    EnclosingBall<S, P> ballOnSupport(List<P> support);
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/enclosing/WelzlEncloser.java b/src/main/java/org/apache/commons/math4/geometry/enclosing/WelzlEncloser.java
deleted file mode 100644
index 924fa83..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/enclosing/WelzlEncloser.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * 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.enclosing;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.math4.exception.MathInternalError;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-
-/** Class implementing Emo Welzl algorithm to find the smallest enclosing ball in linear time.
- * <p>
- * The class implements the algorithm described in paper <a
- * href="http://www.inf.ethz.ch/personal/emo/PublFiles/SmallEnclDisk_LNCS555_91.pdf">Smallest
- * Enclosing Disks (Balls and Ellipsoids)</a> by Emo Welzl, Lecture Notes in Computer Science
- * 555 (1991) 359-370. The pivoting improvement published in the paper <a
- * href="http://www.inf.ethz.ch/personal/gaertner/texts/own_work/esa99_final.pdf">Fast and
- * Robust Smallest Enclosing Balls</a>, by Bernd Gärtner and further modified in
- * paper <a
- * href="http://www.idt.mdh.se/kurser/ct3340/ht12/MINICONFERENCE/FinalPapers/ircse12_submission_30.pdf">
- * Efficient Computation of Smallest Enclosing Balls in Three Dimensions</a> by Linus Källberg
- * to avoid performing local copies of data have been included.
- * </p>
- * @param <S> Space type.
- * @param <P> Point type.
- * @since 3.3
- */
-public class WelzlEncloser<S extends Space, P extends Point<S>> implements Encloser<S, P> {
-
-    /** Tolerance below which points are consider to be identical. */
-    private final double tolerance;
-
-    /** Generator for balls on support. */
-    private final SupportBallGenerator<S, P> generator;
-
-    /** Simple constructor.
-     * @param tolerance below which points are consider to be identical
-     * @param generator generator for balls on support
-     */
-    public WelzlEncloser(final double tolerance, final SupportBallGenerator<S, P> generator) {
-        this.tolerance = tolerance;
-        this.generator = generator;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public EnclosingBall<S, P> enclose(final Iterable<P> points) {
-
-        if (points == null || !points.iterator().hasNext()) {
-            // return an empty ball
-            return generator.ballOnSupport(new ArrayList<P>());
-        }
-
-        // Emo Welzl algorithm with Bernd Gärtner and Linus Källberg improvements
-        return pivotingBall(points);
-
-    }
-
-    /** Compute enclosing ball using Gärtner's pivoting heuristic.
-     * @param points points to be enclosed
-     * @return enclosing ball
-     */
-    private EnclosingBall<S, P> pivotingBall(final Iterable<P> points) {
-
-        final P first = points.iterator().next();
-        final List<P> extreme = new ArrayList<>(first.getSpace().getDimension() + 1);
-        final List<P> support = new ArrayList<>(first.getSpace().getDimension() + 1);
-
-        // start with only first point selected as a candidate support
-        extreme.add(first);
-        EnclosingBall<S, P> ball = moveToFrontBall(extreme, extreme.size(), support);
-
-        while (true) {
-
-            // select the point farthest to current ball
-            final P farthest = selectFarthest(points, ball);
-
-            if (ball.contains(farthest, tolerance)) {
-                // we have found a ball containing all points
-                return ball;
-            }
-
-            // recurse search, restricted to the small subset containing support and farthest point
-            support.clear();
-            support.add(farthest);
-            EnclosingBall<S, P> savedBall = ball;
-            ball = moveToFrontBall(extreme, extreme.size(), support);
-            if (ball.getRadius() < savedBall.getRadius()) {
-                // this should never happen
-                throw new MathInternalError();
-            }
-
-            // it was an interesting point, move it to the front
-            // according to Gärtner's heuristic
-            extreme.add(0, farthest);
-
-            // prune the least interesting points
-            extreme.subList(ball.getSupportSize(), extreme.size()).clear();
-
-
-        }
-    }
-
-    /** Compute enclosing ball using Welzl's move to front heuristic.
-     * @param extreme subset of extreme points
-     * @param nbExtreme number of extreme points to consider
-     * @param support points that must belong to the ball support
-     * @return enclosing ball, for the extreme subset only
-     */
-    private EnclosingBall<S, P> moveToFrontBall(final List<P> extreme, final int nbExtreme,
-                                                final List<P> support) {
-
-        // create a new ball on the prescribed support
-        EnclosingBall<S, P> ball = generator.ballOnSupport(support);
-
-        if (ball.getSupportSize() <= ball.getCenter().getSpace().getDimension()) {
-
-            for (int i = 0; i < nbExtreme; ++i) {
-                final P pi = extreme.get(i);
-                if (!ball.contains(pi, tolerance)) {
-
-                    // we have found an outside point,
-                    // enlarge the ball by adding it to the support
-                    support.add(pi);
-                    ball = moveToFrontBall(extreme, i, support);
-                    support.remove(support.size() - 1);
-
-                    // it was an interesting point, move it to the front
-                    // according to Welzl's heuristic
-                    for (int j = i; j > 0; --j) {
-                        extreme.set(j, extreme.get(j - 1));
-                    }
-                    extreme.set(0, pi);
-
-                }
-            }
-
-        }
-
-        return ball;
-
-    }
-
-    /** Select the point farthest to the current ball.
-     * @param points points to be enclosed
-     * @param ball current ball
-     * @return farthest point
-     */
-    public P selectFarthest(final Iterable<P> points, final EnclosingBall<S, P> ball) {
-
-        final P center = ball.getCenter();
-        P farthest   = null;
-        double dMax  = -1.0;
-
-        for (final P point : points) {
-            final double d = point.distance(center);
-            if (d > dMax) {
-                farthest = point;
-                dMax     = d;
-            }
-        }
-
-        return farthest;
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/enclosing/package-info.java b/src/main/java/org/apache/commons/math4/geometry/enclosing/package-info.java
deleted file mode 100644
index 7456a41..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/enclosing/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- *
- * <p>
- * This package provides interfaces and classes related to the smallest enclosing ball problem.
- * </p>
- *
- */
-package org.apache.commons.math4.geometry.enclosing;
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Cartesian1D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Cartesian1D.java
deleted file mode 100644
index de3f7d2..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Cartesian1D.java
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * 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 java.text.NumberFormat;
-
-import org.apache.commons.math4.exception.MathArithmeticException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-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.math4.util.MathUtils;
-
-/** This class represents a 1D point or a 1D vector.
- * <p>An instance of Cartesian1D represents the point with the corresponding
- * Cartesian coordinates.</p>
- * <p>An instance of Cartesian1D also represents the vector which begins at
- * the origin and ends at the point corresponding to the coordinates.</p>
- * <p>Instances of this class are guaranteed to be immutable.</p>
- * @since 4.0
- */
-public class Cartesian1D extends Vector1D implements Point<Euclidean1D> {
-
-    /** Origin (coordinates: 0). */
-    public static final Cartesian1D ZERO = new Cartesian1D(0.0);
-
-    /** Unit (coordinates: 1). */
-    public static final Cartesian1D ONE  = new Cartesian1D(1.0);
-
-    // CHECKSTYLE: stop ConstantName
-    /** A vector with all coordinates set to NaN. */
-    public static final Cartesian1D NaN = new Cartesian1D(Double.NaN);
-    // CHECKSTYLE: resume ConstantName
-
-    /** A vector with all coordinates set to positive infinity. */
-    public static final Cartesian1D POSITIVE_INFINITY =
-        new Cartesian1D(Double.POSITIVE_INFINITY);
-
-    /** A vector with all coordinates set to negative infinity. */
-    public static final Cartesian1D NEGATIVE_INFINITY =
-        new Cartesian1D(Double.NEGATIVE_INFINITY);
-
-    /** Serializable UID. */
-    private static final long serialVersionUID = 7556674948671647925L;
-
-    /** Abscissa. */
-    private final double x;
-
-    /** Simple constructor.
-     * Build a vector from its coordinates
-     * @param x abscissa
-     * @see #getX()
-     */
-    public Cartesian1D(double x) {
-        this.x = x;
-    }
-
-    /** Multiplicative constructor
-     * Build a vector from another one and a scale factor.
-     * The vector built will be a * u
-     * @param a scale factor
-     * @param u base (unscaled) vector
-     */
-    public Cartesian1D(double a, Cartesian1D u) {
-        this.x = a * u.x;
-    }
-
-    /** Linear constructor
-     * Build a vector from two other ones and corresponding scale factors.
-     * The vector built will be a1 * u1 + a2 * u2
-     * @param a1 first scale factor
-     * @param u1 first base (unscaled) vector
-     * @param a2 second scale factor
-     * @param u2 second base (unscaled) vector
-     */
-    public Cartesian1D(double a1, Cartesian1D u1, double a2, Cartesian1D u2) {
-        this.x = a1 * u1.x + a2 * u2.x;
-    }
-
-    /** Linear constructor
-     * Build a vector from three other ones and corresponding scale factors.
-     * The vector built will be a1 * u1 + a2 * u2 + a3 * u3
-     * @param a1 first scale factor
-     * @param u1 first base (unscaled) vector
-     * @param a2 second scale factor
-     * @param u2 second base (unscaled) vector
-     * @param a3 third scale factor
-     * @param u3 third base (unscaled) vector
-     */
-    public Cartesian1D(double a1, Cartesian1D u1, double a2, Cartesian1D u2,
-                   double a3, Cartesian1D u3) {
-        this.x = a1 * u1.x + a2 * u2.x + a3 * u3.x;
-    }
-
-    /** Linear constructor
-     * Build a vector from four other ones and corresponding scale factors.
-     * The vector built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4
-     * @param a1 first scale factor
-     * @param u1 first base (unscaled) vector
-     * @param a2 second scale factor
-     * @param u2 second base (unscaled) vector
-     * @param a3 third scale factor
-     * @param u3 third base (unscaled) vector
-     * @param a4 fourth scale factor
-     * @param u4 fourth base (unscaled) vector
-     */
-    public Cartesian1D(double a1, Cartesian1D u1, double a2, Cartesian1D u2,
-                   double a3, Cartesian1D u3, double a4, Cartesian1D u4) {
-        this.x = a1 * u1.x + a2 * u2.x + a3 * u3.x + a4 * u4.x;
-    }
-
-    /** Get the abscissa of the vector.
-     * @return abscissa of the vector
-     * @see #Cartesian1D(double)
-     */
-    @Override
-    public double getX() {
-        return x;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Space getSpace() {
-        return Euclidean1D.getInstance();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian1D getZero() {
-        return ZERO;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNorm1() {
-        return FastMath.abs(x);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNorm() {
-        return FastMath.abs(x);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNormSq() {
-        return x * x;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNormInf() {
-        return FastMath.abs(x);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian1D add(Vector<Euclidean1D> v) {
-        Cartesian1D v1 = (Cartesian1D) v;
-        return new Cartesian1D(x + v1.getX());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian1D add(double factor, Vector<Euclidean1D> v) {
-        Cartesian1D v1 = (Cartesian1D) v;
-        return new Cartesian1D(x + factor * v1.getX());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian1D subtract(Vector<Euclidean1D> p) {
-        Cartesian1D p3 = (Cartesian1D) p;
-        return new Cartesian1D(x - p3.x);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian1D subtract(double factor, Vector<Euclidean1D> v) {
-        Cartesian1D v1 = (Cartesian1D) v;
-        return new Cartesian1D(x - factor * v1.getX());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian1D normalize() throws MathArithmeticException {
-        double s = getNorm();
-        if (s == 0) {
-            throw new MathArithmeticException(LocalizedFormats.CANNOT_NORMALIZE_A_ZERO_NORM_VECTOR);
-        }
-        return scalarMultiply(1 / s);
-    }
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian1D negate() {
-        return new Cartesian1D(-x);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian1D scalarMultiply(double a) {
-        return new Cartesian1D(a * x);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isNaN() {
-        return Double.isNaN(x);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isInfinite() {
-        return !isNaN() && Double.isInfinite(x);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distance1(Vector<Euclidean1D> p) {
-        Cartesian1D p1 = (Cartesian1D) p;
-        final double dx = FastMath.abs(p1.x - x);
-        return dx;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distance(Point<Euclidean1D> p) {
-        return distance((Cartesian1D) p);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distance(Vector<Euclidean1D> v) {
-        return distance((Cartesian1D) v);
-    }
-
-    /** Compute the distance between the instance and other coordinates.
-     * @param c other coordinates
-     * @return the distance between the instance and c
-     */
-    public double distance(Cartesian1D c) {
-        final double dx = c.x - x;
-        return FastMath.abs(dx);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distanceInf(Vector<Euclidean1D> p) {
-        Cartesian1D p1 = (Cartesian1D) p;
-        final double dx = FastMath.abs(p1.x - x);
-        return dx;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distanceSq(Vector<Euclidean1D> p) {
-        Cartesian1D p1 = (Cartesian1D) p;
-        final double dx = p1.x - x;
-        return dx * dx;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double dotProduct(final Vector<Euclidean1D> v) {
-        final Cartesian1D v1 = (Cartesian1D) v;
-        return x * v1.x;
-    }
-
-    /** Compute the distance between two points according to the L<sub>2</sub> norm.
-     * <p>Calling this method is equivalent to calling:
-     * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
-     * vector is built</p>
-     * @param p1 first vector
-     * @param p2 second vector
-     * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
-     */
-    public static double distance(Cartesian1D p1, Cartesian1D p2) {
-        return p1.distance(p2);
-    }
-
-    /** Compute the distance between two points according to the L<sub>&infin;</sub> norm.
-     * <p>Calling this method is equivalent to calling:
-     * <code>p1.subtract(p2).getNormInf()</code> except that no intermediate
-     * vector is built</p>
-     * @param p1 first vector
-     * @param p2 second vector
-     * @return the distance between p1 and p2 according to the L<sub>&infin;</sub> norm
-     */
-    public static double distanceInf(Cartesian1D p1, Cartesian1D p2) {
-        return p1.distanceInf(p2);
-    }
-
-    /** Compute the square of the distance between two points.
-     * <p>Calling this method is equivalent to calling:
-     * <code>p1.subtract(p2).getNormSq()</code> except that no intermediate
-     * vector is built</p>
-     * @param p1 first vector
-     * @param p2 second vector
-     * @return the square of the distance between p1 and p2
-     */
-    public static double distanceSq(Cartesian1D p1, Cartesian1D p2) {
-        return p1.distanceSq(p2);
-    }
-
-    /**
-     * Test for the equality of two 1D vectors.
-     * <p>
-     * If all coordinates of two 1D vectors are exactly the same, and none are
-     * <code>Double.NaN</code>, the two 1D vectors are considered to be equal.
-     * </p>
-     * <p>
-     * <code>NaN</code> coordinates are considered to affect globally the vector
-     * and be equals to each other - i.e, if either (or all) coordinates of the
-     * 1D vector are equal to <code>Double.NaN</code>, the 1D vector is equal to
-     * {@link #NaN}.
-     * </p>
-     *
-     * @param other Object to test for equality to this
-     * @return true if two 1D vector objects are equal, false if
-     *         object is null, not an instance of Cartesian1D, or
-     *         not equal to this Cartesian1D instance
-     *
-     */
-    @Override
-    public boolean equals(Object other) {
-
-        if (this == other) {
-            return true;
-        }
-
-        if (other instanceof Cartesian1D) {
-            final Cartesian1D rhs = (Cartesian1D)other;
-            if (rhs.isNaN()) {
-                return this.isNaN();
-            }
-
-            return x == rhs.x;
-        }
-        return false;
-    }
-
-    /**
-     * Get a hashCode for the 1D vector.
-     * <p>
-     * All NaN values have the same hash code.</p>
-     *
-     * @return a hash code value for this object
-     */
-    @Override
-    public int hashCode() {
-        if (isNaN()) {
-            return 7785;
-        }
-        return 997 * MathUtils.hash(x);
-    }
-
-    /** Get a string representation of this vector.
-     * @return a string representation of this vector
-     */
-    @Override
-    public String toString() {
-        return Vector1DFormat.getInstance().format(this);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public String toString(final NumberFormat format) {
-        return new Vector1DFormat(format).format(this);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Euclidean1D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Euclidean1D.java
deleted file mode 100644
index 91e97f5..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Euclidean1D.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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 java.io.Serializable;
-
-import org.apache.commons.math4.exception.MathUnsupportedOperationException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.Space;
-
-/**
- * This class implements a one-dimensional space.
- * @since 3.0
- */
-public class Euclidean1D implements Serializable, Space {
-
-    /** Serializable version identifier. */
-    private static final long serialVersionUID = -1178039568877797126L;
-
-    /** Private constructor for the singleton.
-     */
-    private Euclidean1D() {
-    }
-
-    /** Get the unique instance.
-     * @return the unique instance
-     */
-    public static Euclidean1D getInstance() {
-        return LazyHolder.INSTANCE;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int getDimension() {
-        return 1;
-    }
-
-    /** {@inheritDoc}
-     * <p>
-     * As the 1-dimension Euclidean space does not have proper sub-spaces,
-     * this method always throws a {@link NoSubSpaceException}
-     * </p>
-     * @return nothing
-     * @throws NoSubSpaceException in all cases
-     */
-    @Override
-    public Space getSubSpace() throws NoSubSpaceException {
-        throw new NoSubSpaceException();
-    }
-
-    // CHECKSTYLE: stop HideUtilityClassConstructor
-    /** Holder for the instance.
-     * <p>We use here the Initialization On Demand Holder Idiom.</p>
-     */
-    private static class LazyHolder {
-        /** Cached field instance. */
-        private static final Euclidean1D INSTANCE = new Euclidean1D();
-    }
-    // CHECKSTYLE: resume HideUtilityClassConstructor
-
-    /** Handle deserialization of the singleton.
-     * @return the singleton instance
-     */
-    private Object readResolve() {
-        // return the singleton instance
-        return LazyHolder.INSTANCE;
-    }
-
-    /** Specialized exception for inexistent sub-space.
-     * <p>
-     * This exception is thrown when attempting to get the sub-space of a one-dimensional space
-     * </p>
-     */
-    public static class NoSubSpaceException extends MathUnsupportedOperationException {
-
-        /** Serializable UID. */
-        private static final long serialVersionUID = 20140225L;
-
-        /** Simple constructor.
-         */
-        public NoSubSpaceException() {
-            super(LocalizedFormats.NOT_SUPPORTED_IN_DIMENSION_N, 1);
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Interval.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Interval.java
deleted file mode 100644
index 87dbba1..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Interval.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.apache.commons.math4.geometry.partitioning.Region.Location;
-import org.apache.commons.math4.exception.NumberIsTooSmallException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-
-
-/** This class represents a 1D interval.
- * @see IntervalsSet
- * @since 3.0
- */
-public class Interval {
-
-    /** The lower bound of the interval. */
-    private final double lower;
-
-    /** The upper bound of the interval. */
-    private final double upper;
-
-    /** Simple constructor.
-     * @param lower lower bound of the interval
-     * @param upper upper bound of the interval
-     */
-    public Interval(final double lower, final double upper) {
-        if (upper < lower) {
-            throw new NumberIsTooSmallException(LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
-                                                upper, lower, true);
-        }
-        this.lower = lower;
-        this.upper = upper;
-    }
-
-    /** Get the lower bound of the interval.
-     * @return lower bound of the interval
-     * @since 3.1
-     */
-    public double getInf() {
-        return lower;
-    }
-
-    /** Get the upper bound of the interval.
-     * @return upper bound of the interval
-     * @since 3.1
-     */
-    public double getSup() {
-        return upper;
-    }
-
-    /** Get the size of the interval.
-     * @return size of the interval
-     * @since 3.1
-     */
-    public double getSize() {
-        return upper - lower;
-    }
-
-    /** Get the barycenter of the interval.
-     * @return barycenter of the interval
-     * @since 3.1
-     */
-    public double getBarycenter() {
-        return 0.5 * (lower + upper);
-    }
-
-    /** Check a point with respect to the interval.
-     * @param point point to check
-     * @param tolerance tolerance below which points are considered to
-     * belong to the boundary
-     * @return a code representing the point status: either {@link
-     * Location#INSIDE}, {@link Location#OUTSIDE} or {@link Location#BOUNDARY}
-     * @since 3.1
-     */
-    public Location checkPoint(final double point, final double tolerance) {
-        if (point < lower - tolerance || point > upper + tolerance) {
-            return Location.OUTSIDE;
-        } else if (point > lower + tolerance && point < upper - tolerance) {
-            return Location.INSIDE;
-        } else {
-            return Location.BOUNDARY;
-        }
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalsSet.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalsSet.java
deleted file mode 100644
index 2c50558..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalsSet.java
+++ /dev/null
@@ -1,627 +0,0 @@
-/*
- * 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 java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.partitioning.AbstractRegion;
-import org.apache.commons.math4.geometry.partitioning.BSPTree;
-import org.apache.commons.math4.geometry.partitioning.BoundaryProjection;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-import org.apache.commons.numbers.core.Precision;
-
-/** This class represents a 1D region: a set of intervals.
- * @since 3.0
- */
-public class IntervalsSet extends AbstractRegion<Euclidean1D, Euclidean1D> implements Iterable<double[]> {
-
-    /** Build an intervals set representing the whole real line.
-     * @param tolerance tolerance below which points are considered identical.
-     * @since 3.3
-     */
-    public IntervalsSet(final double tolerance) {
-        super(tolerance);
-    }
-
-    /** Build an intervals set corresponding to a single interval.
-     * @param lower lower bound of the interval, must be lesser or equal
-     * to {@code upper} (may be {@code Double.NEGATIVE_INFINITY})
-     * @param upper upper bound of the interval, must be greater or equal
-     * to {@code lower} (may be {@code Double.POSITIVE_INFINITY})
-     * @param tolerance tolerance below which points are considered identical.
-     * @since 3.3
-     */
-    public IntervalsSet(final double lower, final double upper, final double tolerance) {
-        super(buildTree(lower, upper, tolerance), tolerance);
-    }
-
-    /** Build an intervals set from an inside/outside BSP tree.
-     * <p>The leaf nodes of the BSP tree <em>must</em> have a
-     * {@code Boolean} attribute representing the inside status of
-     * the corresponding cell (true for inside cells, false for outside
-     * cells). In order to avoid building too many small objects, it is
-     * recommended to use the predefined constants
-     * {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
-     * @param tree inside/outside BSP tree representing the intervals set
-     * @param tolerance tolerance below which points are considered identical.
-     * @since 3.3
-     */
-    public IntervalsSet(final BSPTree<Euclidean1D> tree, final double tolerance) {
-        super(tree, tolerance);
-    }
-
-    /** Build an intervals set from a Boundary REPresentation (B-rep).
-     * <p>The boundary is provided as a collection of {@link
-     * SubHyperplane sub-hyperplanes}. Each sub-hyperplane has the
-     * interior part of the region on its minus side and the exterior on
-     * its plus side.</p>
-     * <p>The boundary elements can be in any order, and can form
-     * several non-connected sets (like for example polygons with holes
-     * or a set of disjoints polyhedrons considered as a whole). In
-     * fact, the elements do not even need to be connected together
-     * (their topological connections are not used here). However, if the
-     * boundary does not really separate an inside open from an outside
-     * open (open having here its topological meaning), then subsequent
-     * calls to the {@link
-     * org.apache.commons.math4.geometry.partitioning.Region#checkPoint(org.apache.commons.math4.geometry.Point)
-     * checkPoint} method will not be meaningful anymore.</p>
-     * <p>If the boundary is empty, the region will represent the whole
-     * space.</p>
-     * @param boundary collection of boundary elements
-     * @param tolerance tolerance below which points are considered identical.
-     * @since 3.3
-     */
-    public IntervalsSet(final Collection<SubHyperplane<Euclidean1D>> boundary,
-                        final double tolerance) {
-        super(boundary, tolerance);
-    }
-
-    /** Build an inside/outside tree representing a single interval.
-     * @param lower lower bound of the interval, must be lesser or equal
-     * to {@code upper} (may be {@code Double.NEGATIVE_INFINITY})
-     * @param upper upper bound of the interval, must be greater or equal
-     * to {@code lower} (may be {@code Double.POSITIVE_INFINITY})
-     * @param tolerance tolerance below which points are considered identical.
-     * @return the built tree
-     */
-    private static BSPTree<Euclidean1D> buildTree(final double lower, final double upper,
-                                                  final double tolerance) {
-        if (Double.isInfinite(lower) && (lower < 0)) {
-            if (Double.isInfinite(upper) && (upper > 0)) {
-                // the tree must cover the whole real line
-                return new BSPTree<>(Boolean.TRUE);
-            }
-            // the tree must be open on the negative infinity side
-            final SubHyperplane<Euclidean1D> upperCut =
-                new OrientedPoint(new Cartesian1D(upper), true, tolerance).wholeHyperplane();
-            return new BSPTree<>(upperCut,
-                               new BSPTree<Euclidean1D>(Boolean.FALSE),
-                               new BSPTree<Euclidean1D>(Boolean.TRUE),
-                               null);
-        }
-        final SubHyperplane<Euclidean1D> lowerCut =
-            new OrientedPoint(new Cartesian1D(lower), false, tolerance).wholeHyperplane();
-        if (Double.isInfinite(upper) && (upper > 0)) {
-            // the tree must be open on the positive infinity side
-            return new BSPTree<>(lowerCut,
-                                            new BSPTree<Euclidean1D>(Boolean.FALSE),
-                                            new BSPTree<Euclidean1D>(Boolean.TRUE),
-                                            null);
-        }
-
-        // the tree must be bounded on the two sides
-        final SubHyperplane<Euclidean1D> upperCut =
-            new OrientedPoint(new Cartesian1D(upper), true, tolerance).wholeHyperplane();
-        return new BSPTree<>(lowerCut,
-                                        new BSPTree<Euclidean1D>(Boolean.FALSE),
-                                        new BSPTree<>(upperCut,
-                                                                 new BSPTree<Euclidean1D>(Boolean.FALSE),
-                                                                 new BSPTree<Euclidean1D>(Boolean.TRUE),
-                                                                 null),
-                                        null);
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public IntervalsSet buildNew(final BSPTree<Euclidean1D> tree) {
-        return new IntervalsSet(tree, getTolerance());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void computeGeometricalProperties() {
-        if (getTree(false).getCut() == null) {
-            setBarycenter((Point<Euclidean1D>) Cartesian1D.NaN);
-            setSize(((Boolean) getTree(false).getAttribute()) ? Double.POSITIVE_INFINITY : 0);
-        } else {
-            double size = 0.0;
-            double sum = 0.0;
-            for (final Interval interval : asList()) {
-                size += interval.getSize();
-                sum  += interval.getSize() * interval.getBarycenter();
-            }
-            setSize(size);
-            if (Double.isInfinite(size)) {
-                setBarycenter((Point<Euclidean1D>) Cartesian1D.NaN);
-            } else if (size >= Precision.SAFE_MIN) {
-                setBarycenter((Point<Euclidean1D>) new Cartesian1D(sum / size));
-            } else {
-                setBarycenter((Point<Euclidean1D>) ((OrientedPoint) getTree(false).getCut().getHyperplane()).getLocation());
-            }
-        }
-    }
-
-    /** Get the lowest value belonging to the instance.
-     * @return lowest value belonging to the instance
-     * ({@code Double.NEGATIVE_INFINITY} if the instance doesn't
-     * have any low bound, {@code Double.POSITIVE_INFINITY} if the
-     * instance is empty)
-     */
-    public double getInf() {
-        BSPTree<Euclidean1D> node = getTree(false);
-        double  inf  = Double.POSITIVE_INFINITY;
-        while (node.getCut() != null) {
-            final OrientedPoint op = (OrientedPoint) node.getCut().getHyperplane();
-            inf  = op.getLocation().getX();
-            node = op.isDirect() ? node.getMinus() : node.getPlus();
-        }
-        return ((Boolean) node.getAttribute()) ? Double.NEGATIVE_INFINITY : inf;
-    }
-
-    /** Get the highest value belonging to the instance.
-     * @return highest value belonging to the instance
-     * ({@code Double.POSITIVE_INFINITY} if the instance doesn't
-     * have any high bound, {@code Double.NEGATIVE_INFINITY} if the
-     * instance is empty)
-     */
-    public double getSup() {
-        BSPTree<Euclidean1D> node = getTree(false);
-        double  sup  = Double.NEGATIVE_INFINITY;
-        while (node.getCut() != null) {
-            final OrientedPoint op = (OrientedPoint) node.getCut().getHyperplane();
-            sup  = op.getLocation().getX();
-            node = op.isDirect() ? node.getPlus() : node.getMinus();
-        }
-        return ((Boolean) node.getAttribute()) ? Double.POSITIVE_INFINITY : sup;
-    }
-
-    /** {@inheritDoc}
-     * @since 3.3
-     */
-    @Override
-    public BoundaryProjection<Euclidean1D> projectToBoundary(final Point<Euclidean1D> point) {
-
-        // get position of test point
-        final double x = ((Cartesian1D) point).getX();
-
-        double previous = Double.NEGATIVE_INFINITY;
-        for (final double[] a : this) {
-            if (x < a[0]) {
-                // the test point lies between the previous and the current intervals
-                // offset will be positive
-                final double previousOffset = x - previous;
-                final double currentOffset  = a[0] - x;
-                if (previousOffset < currentOffset) {
-                    return new BoundaryProjection<>(point, finiteOrNullPoint(previous), previousOffset);
-                } else {
-                    return new BoundaryProjection<>(point, finiteOrNullPoint(a[0]), currentOffset);
-                }
-            } else if (x <= a[1]) {
-                // the test point lies within the current interval
-                // offset will be negative
-                final double offset0 = a[0] - x;
-                final double offset1 = x - a[1];
-                if (offset0 < offset1) {
-                    return new BoundaryProjection<>(point, finiteOrNullPoint(a[1]), offset1);
-                } else {
-                    return new BoundaryProjection<>(point, finiteOrNullPoint(a[0]), offset0);
-                }
-            }
-            previous = a[1];
-        }
-
-        // the test point if past the last sub-interval
-        return new BoundaryProjection<>(point, finiteOrNullPoint(previous), x - previous);
-
-    }
-
-    /** Build a finite point.
-     * @param x abscissa of the point
-     * @return a new point for finite abscissa, null otherwise
-     */
-    private Cartesian1D finiteOrNullPoint(final double x) {
-        return Double.isInfinite(x) ? null : new Cartesian1D(x);
-    }
-
-    /** Build an ordered list of intervals representing the instance.
-     * <p>This method builds this intervals set as an ordered list of
-     * {@link Interval Interval} elements. If the intervals set has no
-     * lower limit, the first interval will have its low bound equal to
-     * {@code Double.NEGATIVE_INFINITY}. If the intervals set has
-     * no upper limit, the last interval will have its upper bound equal
-     * to {@code Double.POSITIVE_INFINITY}. An empty tree will
-     * build an empty list while a tree representing the whole real line
-     * will build a one element list with both bounds being
-     * infinite.</p>
-     * @return a new ordered list containing {@link Interval Interval}
-     * elements
-     */
-    public List<Interval> asList() {
-        final List<Interval> list = new ArrayList<>();
-        for (final double[] a : this) {
-            list.add(new Interval(a[0], a[1]));
-        }
-        return list;
-    }
-
-    /** Get the first leaf node of a tree.
-     * @param root tree root
-     * @return first leaf node
-     */
-    private BSPTree<Euclidean1D> getFirstLeaf(final BSPTree<Euclidean1D> root) {
-
-        if (root.getCut() == null) {
-            return root;
-        }
-
-        // find the smallest internal node
-        BSPTree<Euclidean1D> smallest = null;
-        for (BSPTree<Euclidean1D> n = root; n != null; n = previousInternalNode(n)) {
-            smallest = n;
-        }
-
-        return leafBefore(smallest);
-
-    }
-
-    /** Get the node corresponding to the first interval boundary.
-     * @return smallest internal node,
-     * or null if there are no internal nodes (i.e. the set is either empty or covers the real line)
-     */
-    private BSPTree<Euclidean1D> getFirstIntervalBoundary() {
-
-        // start search at the tree root
-        BSPTree<Euclidean1D> node = getTree(false);
-        if (node.getCut() == null) {
-            return null;
-        }
-
-        // walk tree until we find the smallest internal node
-        node = getFirstLeaf(node).getParent();
-
-        // walk tree until we find an interval boundary
-        while (node != null && !(isIntervalStart(node) || isIntervalEnd(node))) {
-            node = nextInternalNode(node);
-        }
-
-        return node;
-
-    }
-
-    /** Check if an internal node corresponds to the start abscissa of an interval.
-     * @param node internal node to check
-     * @return true if the node corresponds to the start abscissa of an interval
-     */
-    private boolean isIntervalStart(final BSPTree<Euclidean1D> node) {
-
-        if ((Boolean) leafBefore(node).getAttribute()) {
-            // it has an inside cell before it, it may end an interval but not start it
-            return false;
-        }
-
-        if (!(Boolean) leafAfter(node).getAttribute()) {
-            // it has an outside cell after it, it is a dummy cut away from real intervals
-            return false;
-        }
-
-        // the cell has an outside before and an inside after it
-        // it is the start of an interval
-        return true;
-
-    }
-
-    /** Check if an internal node corresponds to the end abscissa of an interval.
-     * @param node internal node to check
-     * @return true if the node corresponds to the end abscissa of an interval
-     */
-    private boolean isIntervalEnd(final BSPTree<Euclidean1D> node) {
-
-        if (!(Boolean) leafBefore(node).getAttribute()) {
-            // it has an outside cell before it, it may start an interval but not end it
-            return false;
-        }
-
-        if ((Boolean) leafAfter(node).getAttribute()) {
-            // it has an inside cell after it, it is a dummy cut in the middle of an interval
-            return false;
-        }
-
-        // the cell has an inside before and an outside after it
-        // it is the end of an interval
-        return true;
-
-    }
-
-    /** Get the next internal node.
-     * @param node current internal node
-     * @return next internal node in ascending order, or null
-     * if this is the last internal node
-     */
-    private BSPTree<Euclidean1D> nextInternalNode(BSPTree<Euclidean1D> node) {
-
-        if (childAfter(node).getCut() != null) {
-            // the next node is in the sub-tree
-            return leafAfter(node).getParent();
-        }
-
-        // there is nothing left deeper in the tree, we backtrack
-        while (isAfterParent(node)) {
-            node = node.getParent();
-        }
-        return node.getParent();
-
-    }
-
-    /** Get the previous internal node.
-     * @param node current internal node
-     * @return previous internal node in ascending order, or null
-     * if this is the first internal node
-     */
-    private BSPTree<Euclidean1D> previousInternalNode(BSPTree<Euclidean1D> node) {
-
-        if (childBefore(node).getCut() != null) {
-            // the next node is in the sub-tree
-            return leafBefore(node).getParent();
-        }
-
-        // there is nothing left deeper in the tree, we backtrack
-        while (isBeforeParent(node)) {
-            node = node.getParent();
-        }
-        return node.getParent();
-
-    }
-
-    /** Find the leaf node just before an internal node.
-     * @param node internal node at which the sub-tree starts
-     * @return leaf node just before the internal node
-     */
-    private BSPTree<Euclidean1D> leafBefore(BSPTree<Euclidean1D> node) {
-
-        node = childBefore(node);
-        while (node.getCut() != null) {
-            node = childAfter(node);
-        }
-
-        return node;
-
-    }
-
-    /** Find the leaf node just after an internal node.
-     * @param node internal node at which the sub-tree starts
-     * @return leaf node just after the internal node
-     */
-    private BSPTree<Euclidean1D> leafAfter(BSPTree<Euclidean1D> node) {
-
-        node = childAfter(node);
-        while (node.getCut() != null) {
-            node = childBefore(node);
-        }
-
-        return node;
-
-    }
-
-    /** Check if a node is the child before its parent in ascending order.
-     * @param node child node considered
-     * @return true is the node has a parent end is before it in ascending order
-     */
-    private boolean isBeforeParent(final BSPTree<Euclidean1D> node) {
-        final BSPTree<Euclidean1D> parent = node.getParent();
-        if (parent == null) {
-            return false;
-        } else {
-            return node == childBefore(parent);
-        }
-    }
-
-    /** Check if a node is the child after its parent in ascending order.
-     * @param node child node considered
-     * @return true is the node has a parent end is after it in ascending order
-     */
-    private boolean isAfterParent(final BSPTree<Euclidean1D> node) {
-        final BSPTree<Euclidean1D> parent = node.getParent();
-        if (parent == null) {
-            return false;
-        } else {
-            return node == childAfter(parent);
-        }
-    }
-
-    /** Find the child node just before an internal node.
-     * @param node internal node at which the sub-tree starts
-     * @return child node just before the internal node
-     */
-    private BSPTree<Euclidean1D> childBefore(BSPTree<Euclidean1D> node) {
-        if (isDirect(node)) {
-            // smaller abscissas are on minus side, larger abscissas are on plus side
-            return node.getMinus();
-        } else {
-            // smaller abscissas are on plus side, larger abscissas are on minus side
-            return node.getPlus();
-        }
-    }
-
-    /** Find the child node just after an internal node.
-     * @param node internal node at which the sub-tree starts
-     * @return child node just after the internal node
-     */
-    private BSPTree<Euclidean1D> childAfter(BSPTree<Euclidean1D> node) {
-        if (isDirect(node)) {
-            // smaller abscissas are on minus side, larger abscissas are on plus side
-            return node.getPlus();
-        } else {
-            // smaller abscissas are on plus side, larger abscissas are on minus side
-            return node.getMinus();
-        }
-    }
-
-    /** Check if an internal node has a direct oriented point.
-     * @param node internal node to check
-     * @return true if the oriented point is direct
-     */
-    private boolean isDirect(final BSPTree<Euclidean1D> node) {
-        return ((OrientedPoint) node.getCut().getHyperplane()).isDirect();
-    }
-
-    /** Get the abscissa of an internal node.
-     * @param node internal node to check
-     * @return abscissa
-     */
-    private double getAngle(final BSPTree<Euclidean1D> node) {
-        return ((OrientedPoint) node.getCut().getHyperplane()).getLocation().getX();
-    }
-
-    /** {@inheritDoc}
-     * <p>
-     * The iterator returns the limit values of sub-intervals in ascending order.
-     * </p>
-     * <p>
-     * The iterator does <em>not</em> support the optional {@code remove} operation.
-     * </p>
-     * @since 3.3
-     */
-    @Override
-    public Iterator<double[]> iterator() {
-        return new SubIntervalsIterator();
-    }
-
-    /** Local iterator for sub-intervals. */
-    private class SubIntervalsIterator implements Iterator<double[]> {
-
-        /** Current node. */
-        private BSPTree<Euclidean1D> current;
-
-        /** Sub-interval no yet returned. */
-        private double[] pending;
-
-        /** Simple constructor.
-         */
-        SubIntervalsIterator() {
-
-            current = getFirstIntervalBoundary();
-
-            if (current == null) {
-                // all the leaf tree nodes share the same inside/outside status
-                if ((Boolean) getFirstLeaf(getTree(false)).getAttribute()) {
-                    // it is an inside node, it represents the full real line
-                    pending = new double[] {
-                        Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY
-                    };
-                } else {
-                    pending = null;
-                }
-            } else if (isIntervalEnd(current)) {
-                // the first boundary is an interval end,
-                // so the first interval starts at infinity
-                pending = new double[] {
-                    Double.NEGATIVE_INFINITY, getAngle(current)
-                };
-            } else {
-                selectPending();
-            }
-        }
-
-        /** Walk the tree to select the pending sub-interval.
-         */
-        private void selectPending() {
-
-            // look for the start of the interval
-            BSPTree<Euclidean1D> start = current;
-            while (start != null && !isIntervalStart(start)) {
-                start = nextInternalNode(start);
-            }
-
-            if (start == null) {
-                // we have exhausted the iterator
-                current = null;
-                pending = null;
-                return;
-            }
-
-            // look for the end of the interval
-            BSPTree<Euclidean1D> end = start;
-            while (end != null && !isIntervalEnd(end)) {
-                end = nextInternalNode(end);
-            }
-
-            if (end != null) {
-
-                // we have identified the interval
-                pending = new double[] {
-                    getAngle(start), getAngle(end)
-                };
-
-                // prepare search for next interval
-                current = end;
-
-            } else {
-
-                // the final interval is open toward infinity
-                pending = new double[] {
-                    getAngle(start), Double.POSITIVE_INFINITY
-                };
-
-                // there won't be any other intervals
-                current = null;
-
-            }
-
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public boolean hasNext() {
-            return pending != null;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public double[] next() {
-            if (pending == null) {
-                throw new NoSuchElementException();
-            }
-            final double[] next = pending;
-            selectPending();
-            return next;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/OrientedPoint.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/OrientedPoint.java
deleted file mode 100644
index f917bcc..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/OrientedPoint.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Vector;
-import org.apache.commons.math4.geometry.partitioning.Hyperplane;
-
-/** This class represents a 1D oriented hyperplane.
- * <p>An hyperplane in 1D is a simple point, its orientation being a
- * boolean.</p>
- * <p>Instances of this class are guaranteed to be immutable.</p>
- * @since 3.0
- */
-public class OrientedPoint implements Hyperplane<Euclidean1D> {
-
-    /** Vector location. */
-    private final Cartesian1D location;
-
-    /** Orientation. */
-    private boolean direct;
-
-    /** Tolerance below which points are considered to belong to the hyperplane. */
-    private final double tolerance;
-
-    /** Simple constructor.
-     * @param location location of the hyperplane
-     * @param direct if true, the plus side of the hyperplane is towards
-     * abscissas greater than {@code location}
-     * @param tolerance tolerance below which points are considered to belong to the hyperplane
-     * @since 3.3
-     */
-    public OrientedPoint(final Cartesian1D location, final boolean direct, final double tolerance) {
-        this.location  = location;
-        this.direct    = direct;
-        this.tolerance = tolerance;
-    }
-
-    /** Copy the instance.
-     * <p>Since instances are immutable, this method directly returns
-     * the instance.</p>
-     * @return the instance itself
-     */
-    @Override
-    public OrientedPoint copySelf() {
-        return this;
-    }
-
-    /** Get the offset (oriented distance) of a vector.
-     * @param vector vector to check
-     * @return offset of the vector
-     */
-    public double getOffset(Vector<Euclidean1D> vector) {
-        return getOffset((Point<Euclidean1D>) vector);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getOffset(final Point<Euclidean1D> point) {
-        final double delta = ((Cartesian1D) point).getX() - location.getX();
-        return direct ? delta : -delta;
-    }
-
-    /** Build a region covering the whole hyperplane.
-     * <p>Since this class represent zero dimension spaces which does
-     * not have lower dimension sub-spaces, this method returns a dummy
-     * implementation of a {@link
-     * org.apache.commons.math4.geometry.partitioning.SubHyperplane SubHyperplane}.
-     * This implementation is only used to allow the {@link
-     * org.apache.commons.math4.geometry.partitioning.SubHyperplane
-     * SubHyperplane} class implementation to work properly, it should
-     * <em>not</em> be used otherwise.</p>
-     * @return a dummy sub hyperplane
-     */
-    @Override
-    public SubOrientedPoint wholeHyperplane() {
-        return new SubOrientedPoint(this, null);
-    }
-
-    /** Build a region covering the whole space.
-     * @return a region containing the instance (really an {@link
-     * IntervalsSet IntervalsSet} instance)
-     */
-    @Override
-    public IntervalsSet wholeSpace() {
-        return new IntervalsSet(tolerance);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean sameOrientationAs(final Hyperplane<Euclidean1D> other) {
-        return !(direct ^ ((OrientedPoint) other).direct);
-    }
-
-    /** {@inheritDoc}
-     * @since 3.3
-     */
-    @Override
-    public Point<Euclidean1D> project(Point<Euclidean1D> point) {
-        return location;
-    }
-
-    /** {@inheritDoc}
-     * @since 3.3
-     */
-    @Override
-    public double getTolerance() {
-        return tolerance;
-    }
-
-    /** Get the hyperplane location on the real line.
-     * @return the hyperplane location
-     */
-    public Cartesian1D getLocation() {
-        return location;
-    }
-
-    /** Check if the hyperplane orientation is direct.
-     * @return true if the plus side of the hyperplane is towards
-     * abscissae greater than hyperplane location
-     */
-    public boolean isDirect() {
-        return direct;
-    }
-
-    /** Revert the instance.
-     */
-    public void revertSelf() {
-        direct = !direct;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPoint.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPoint.java
deleted file mode 100644
index b6c90e9..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPoint.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.apache.commons.math4.geometry.partitioning.AbstractSubHyperplane;
-import org.apache.commons.math4.geometry.partitioning.Hyperplane;
-import org.apache.commons.math4.geometry.partitioning.Region;
-
-/** This class represents sub-hyperplane for {@link OrientedPoint}.
- * <p>An hyperplane in 1D is a simple point, its orientation being a
- * boolean.</p>
- * <p>Instances of this class are guaranteed to be immutable.</p>
- * @since 3.0
- */
-public class SubOrientedPoint extends AbstractSubHyperplane<Euclidean1D, Euclidean1D> {
-
-    /** Simple constructor.
-     * @param hyperplane underlying hyperplane
-     * @param remainingRegion remaining region of the hyperplane
-     */
-    public SubOrientedPoint(final Hyperplane<Euclidean1D> hyperplane,
-                            final Region<Euclidean1D> remainingRegion) {
-        super(hyperplane, remainingRegion);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getSize() {
-        return 0;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isEmpty() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected AbstractSubHyperplane<Euclidean1D, Euclidean1D> buildNew(final Hyperplane<Euclidean1D> hyperplane,
-                                                                       final Region<Euclidean1D> remainingRegion) {
-        return new SubOrientedPoint(hyperplane, remainingRegion);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public SplitSubHyperplane<Euclidean1D> split(final Hyperplane<Euclidean1D> hyperplane) {
-        final OrientedPoint thisHyperplane = (OrientedPoint) getHyperplane();
-        final double global = hyperplane.getOffset(thisHyperplane.getLocation());
-
-        // use the tolerance value from our parent hyperplane to determine equality
-        final double tolerance = thisHyperplane.getTolerance();
-
-        if (global < -tolerance) {
-            return new SplitSubHyperplane<Euclidean1D>(null, this);
-        } else if (global > tolerance) {
-            return new SplitSubHyperplane<Euclidean1D>(this, null);
-        } else {
-            return new SplitSubHyperplane<Euclidean1D>(null, null);
-        }
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1D.java
deleted file mode 100644
index 7411dd6..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1D.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.apache.commons.math4.geometry.Vector;
-
-/** This class represents a 1D vector.
- *
- * @since 3.0
- */
-public abstract class Vector1D implements Vector<Euclidean1D> {
-
-    /** Get the abscissa of the vector.
-     * @return abscissa of the vector
-     * @see Cartesian1D#Cartesian1D(double)
-     */
-    public abstract double getX();
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1DFormat.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1DFormat.java
deleted file mode 100644
index 911d6f4..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1DFormat.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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 java.text.FieldPosition;
-import java.text.NumberFormat;
-import java.text.ParsePosition;
-import java.util.Locale;
-
-import org.apache.commons.math4.exception.MathParseException;
-import org.apache.commons.math4.geometry.Vector;
-import org.apache.commons.math4.geometry.VectorFormat;
-import org.apache.commons.math4.util.CompositeFormat;
-
-/**
- * Formats a 1D vector in components list format "{x}".
- * <p>The prefix and suffix "{" and "}" can be replaced by
- * any user-defined strings. The number format for components can be configured.</p>
- * <p>White space is ignored at parse time, even if it is in the prefix, suffix
- * or separator specifications. So even if the default separator does include a space
- * character that is used at format time, both input string "{1}" and
- * " { 1 } " will be parsed without error and the same vector will be
- * returned. In the second case, however, the parse position after parsing will be
- * just after the closing curly brace, i.e. just before the trailing space.</p>
- * <p><b>Note:</b> using "," as a separator may interfere with the grouping separator
- * of the default {@link NumberFormat} for the current locale. Thus it is advised
- * to use a {@link NumberFormat} instance with disabled grouping in such a case.</p>
- *
- * @since 3.0
- */
-public class Vector1DFormat extends VectorFormat<Euclidean1D> {
-
-    /**
-     * Create an instance with default settings.
-     * <p>The instance uses the default prefix, suffix and separator:
-     * "{", "}", and "; " and the default number format for components.</p>
-     */
-    public Vector1DFormat() {
-        super(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR,
-              CompositeFormat.getDefaultNumberFormat());
-    }
-
-    /**
-     * Create an instance with a custom number format for components.
-     * @param format the custom format for components.
-     */
-    public Vector1DFormat(final NumberFormat format) {
-        super(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, format);
-    }
-
-    /**
-     * Create an instance with custom prefix, suffix and separator.
-     * @param prefix prefix to use instead of the default "{"
-     * @param suffix suffix to use instead of the default "}"
-     */
-    public Vector1DFormat(final String prefix, final String suffix) {
-        super(prefix, suffix, DEFAULT_SEPARATOR, CompositeFormat.getDefaultNumberFormat());
-    }
-
-    /**
-     * Create an instance with custom prefix, suffix, separator and format
-     * for components.
-     * @param prefix prefix to use instead of the default "{"
-     * @param suffix suffix to use instead of the default "}"
-     * @param format the custom format for components.
-     */
-    public Vector1DFormat(final String prefix, final String suffix,
-                         final NumberFormat format) {
-        super(prefix, suffix, DEFAULT_SEPARATOR, format);
-    }
-
-    /**
-     * Returns the default 1D vector format for the current locale.
-     * @return the default 1D vector format.
-     */
-    public static Vector1DFormat getInstance() {
-        return getInstance(Locale.getDefault());
-    }
-
-    /**
-     * Returns the default 1D vector format for the given locale.
-     * @param locale the specific locale used by the format.
-     * @return the 1D vector format specific to the given locale.
-     */
-    public static Vector1DFormat getInstance(final Locale locale) {
-        return new Vector1DFormat(CompositeFormat.getDefaultNumberFormat(locale));
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public StringBuffer format(final Vector<Euclidean1D> vector, final StringBuffer toAppendTo,
-                               final FieldPosition pos) {
-        final Vector1D p1 = (Vector1D) vector;
-        return format(toAppendTo, pos, p1.getX());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Vector1D parse(final String source) throws MathParseException {
-        ParsePosition parsePosition = new ParsePosition(0);
-        Vector1D result = parse(source, parsePosition);
-        if (parsePosition.getIndex() == 0) {
-            throw new MathParseException(source,
-                                         parsePosition.getErrorIndex(),
-                                         Vector1D.class);
-        }
-        return result;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Vector1D parse(final String source, final ParsePosition pos) {
-        final double[] coordinates = parseCoordinates(1, source, pos);
-        if (coordinates == null) {
-            return null;
-        }
-        return new Cartesian1D(coordinates[0]);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/package-info.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/package-info.java
deleted file mode 100644
index 9ec9d8b..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/oned/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- *
- * <p>
- * This package provides basic 1D geometry components.
- * </p>
- *
- */
-package org.apache.commons.math4.geometry.euclidean.oned;
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Cartesian3D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Cartesian3D.java
deleted file mode 100644
index 774a5ba..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Cartesian3D.java
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * 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.Serializable;
-import java.text.NumberFormat;
-
-import org.apache.commons.numbers.arrays.LinearCombination;
-import org.apache.commons.math4.exception.DimensionMismatchException;
-import org.apache.commons.math4.exception.MathArithmeticException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-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.math4.util.MathUtils;
-
-/**
- * This class represents points or vectors in a three-dimensional space.
- * <p>An instance of Cartesian3D represents the point with the corresponding
- * coordinates.</p>
- * <p>An instance of Cartesian3D also represents the vector which begins at
- * the origin and ends at the point corresponding to the coordinates.</p>
- * <p>Instance of this class are guaranteed to be immutable.</p>
- * @since 4.0
- */
-public class Cartesian3D extends Vector3D implements Serializable, Point<Euclidean3D> {
-
-    /** Null vector (coordinates: 0, 0, 0). */
-    public static final Cartesian3D ZERO   = new Cartesian3D(0, 0, 0);
-
-    /** First canonical vector (coordinates: 1, 0, 0). */
-    public static final Cartesian3D PLUS_I = new Cartesian3D(1, 0, 0);
-
-    /** Opposite of the first canonical vector (coordinates: -1, 0, 0). */
-    public static final Cartesian3D MINUS_I = new Cartesian3D(-1, 0, 0);
-
-    /** Second canonical vector (coordinates: 0, 1, 0). */
-    public static final Cartesian3D PLUS_J = new Cartesian3D(0, 1, 0);
-
-    /** Opposite of the second canonical vector (coordinates: 0, -1, 0). */
-    public static final Cartesian3D MINUS_J = new Cartesian3D(0, -1, 0);
-
-    /** Third canonical vector (coordinates: 0, 0, 1). */
-    public static final Cartesian3D PLUS_K = new Cartesian3D(0, 0, 1);
-
-    /** Opposite of the third canonical vector (coordinates: 0, 0, -1).  */
-    public static final Cartesian3D MINUS_K = new Cartesian3D(0, 0, -1);
-
-    // CHECKSTYLE: stop ConstantName
-    /** A vector with all coordinates set to NaN. */
-    public static final Cartesian3D NaN = new Cartesian3D(Double.NaN, Double.NaN, Double.NaN);
-    // CHECKSTYLE: resume ConstantName
-
-    /** A vector with all coordinates set to positive infinity. */
-    public static final Cartesian3D POSITIVE_INFINITY =
-        new Cartesian3D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
-
-    /** A vector with all coordinates set to negative infinity. */
-    public static final Cartesian3D NEGATIVE_INFINITY =
-        new Cartesian3D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
-
-    /** Serializable version identifier. */
-    private static final long serialVersionUID = 1313493323784566947L;
-
-    /** Abscissa. */
-    private final double x;
-
-    /** Ordinate. */
-    private final double y;
-
-    /** Height. */
-    private final double z;
-
-    /** Simple constructor.
-     * Build a vector from its coordinates
-     * @param x abscissa
-     * @param y ordinate
-     * @param z height
-     * @see #getX()
-     * @see #getY()
-     * @see #getZ()
-     */
-    public Cartesian3D(double x, double y, double z) {
-        this.x = x;
-        this.y = y;
-        this.z = z;
-    }
-
-    /** Simple constructor.
-     * Build a vector from its coordinates
-     * @param v coordinates array
-     * @exception DimensionMismatchException if array does not have 3 elements
-     * @see #toArray()
-     */
-    public Cartesian3D(double[] v) throws DimensionMismatchException {
-        if (v.length != 3) {
-            throw new DimensionMismatchException(v.length, 3);
-        }
-        this.x = v[0];
-        this.y = v[1];
-        this.z = v[2];
-    }
-
-    /** Simple constructor.
-     * Build a vector from its azimuthal coordinates
-     * @param alpha azimuth (&alpha;) around Z
-     *              (0 is +X, &pi;/2 is +Y, &pi; is -X and 3&pi;/2 is -Y)
-     * @param delta elevation (&delta;) above (XY) plane, from -&pi;/2 to +&pi;/2
-     * @see #getAlpha()
-     * @see #getDelta()
-     */
-    public Cartesian3D(double alpha, double delta) {
-        double cosDelta = FastMath.cos(delta);
-        this.x = FastMath.cos(alpha) * cosDelta;
-        this.y = FastMath.sin(alpha) * cosDelta;
-        this.z = FastMath.sin(delta);
-    }
-
-    /** Multiplicative constructor
-     * Build a vector from another one and a scale factor.
-     * The vector built will be a * u
-     * @param a scale factor
-     * @param u base (unscaled) vector
-     */
-    public Cartesian3D(double a, Cartesian3D u) {
-        this.x = a * u.x;
-        this.y = a * u.y;
-        this.z = a * u.z;
-    }
-
-    /** Linear constructor
-     * Build a vector from two other ones and corresponding scale factors.
-     * The vector built will be a1 * u1 + a2 * u2
-     * @param a1 first scale factor
-     * @param u1 first base (unscaled) vector
-     * @param a2 second scale factor
-     * @param u2 second base (unscaled) vector
-     */
-    public Cartesian3D(double a1, Cartesian3D u1, double a2, Cartesian3D u2) {
-        this.x = LinearCombination.value(a1, u1.x, a2, u2.x);
-        this.y = LinearCombination.value(a1, u1.y, a2, u2.y);
-        this.z = LinearCombination.value(a1, u1.z, a2, u2.z);
-    }
-
-    /** Linear constructor
-     * Build a vector from three other ones and corresponding scale factors.
-     * The vector built will be a1 * u1 + a2 * u2 + a3 * u3
-     * @param a1 first scale factor
-     * @param u1 first base (unscaled) vector
-     * @param a2 second scale factor
-     * @param u2 second base (unscaled) vector
-     * @param a3 third scale factor
-     * @param u3 third base (unscaled) vector
-     */
-    public Cartesian3D(double a1, Cartesian3D u1, double a2, Cartesian3D u2,
-                    double a3, Cartesian3D u3) {
-        this.x = LinearCombination.value(a1, u1.x, a2, u2.x, a3, u3.x);
-        this.y = LinearCombination.value(a1, u1.y, a2, u2.y, a3, u3.y);
-        this.z = LinearCombination.value(a1, u1.z, a2, u2.z, a3, u3.z);
-    }
-
-    /** Linear constructor
-     * Build a vector from four other ones and corresponding scale factors.
-     * The vector built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4
-     * @param a1 first scale factor
-     * @param u1 first base (unscaled) vector
-     * @param a2 second scale factor
-     * @param u2 second base (unscaled) vector
-     * @param a3 third scale factor
-     * @param u3 third base (unscaled) vector
-     * @param a4 fourth scale factor
-     * @param u4 fourth base (unscaled) vector
-     */
-    public Cartesian3D(double a1, Cartesian3D u1, double a2, Cartesian3D u2,
-                    double a3, Cartesian3D u3, double a4, Cartesian3D u4) {
-        this.x = LinearCombination.value(a1, u1.x, a2, u2.x, a3, u3.x, a4, u4.x);
-        this.y = LinearCombination.value(a1, u1.y, a2, u2.y, a3, u3.y, a4, u4.y);
-        this.z = LinearCombination.value(a1, u1.z, a2, u2.z, a3, u3.z, a4, u4.z);
-    }
-
-    /** Get the abscissa of the vector.
-     * @return abscissa of the vector
-     * @see #Cartesian3D(double, double, double)
-     */
-    public double getX() {
-        return x;
-    }
-
-    /** Get the ordinate of the vector.
-     * @return ordinate of the vector
-     * @see #Cartesian3D(double, double, double)
-     */
-    public double getY() {
-        return y;
-    }
-
-    /** Get the height of the vector.
-     * @return height of the vector
-     * @see #Cartesian3D(double, double, double)
-     */
-    public double getZ() {
-        return z;
-    }
-
-    /** Get the vector coordinates as a dimension 3 array.
-     * @return vector coordinates
-     * @see #Cartesian3D(double[])
-     */
-    public double[] toArray() {
-        return new double[] { x, y, z };
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Space getSpace() {
-        return Euclidean3D.getInstance();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian3D getZero() {
-        return ZERO;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNorm1() {
-        return FastMath.abs(x) + FastMath.abs(y) + FastMath.abs(z);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNorm() {
-        // there are no cancellation problems here, so we use the straightforward formula
-        return FastMath.sqrt (x * x + y * y + z * z);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNormSq() {
-        // there are no cancellation problems here, so we use the straightforward formula
-        return x * x + y * y + z * z;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNormInf() {
-        return FastMath.max(FastMath.max(FastMath.abs(x), FastMath.abs(y)), FastMath.abs(z));
-    }
-
-    /** Get the azimuth of the vector.
-     * @return azimuth (&alpha;) of the vector, between -&pi; and +&pi;
-     * @see #Cartesian3D(double, double)
-     */
-    public double getAlpha() {
-        return FastMath.atan2(y, x);
-    }
-
-    /** Get the elevation of the vector.
-     * @return elevation (&delta;) of the vector, between -&pi;/2 and +&pi;/2
-     * @see #Cartesian3D(double, double)
-     */
-    public double getDelta() {
-        return FastMath.asin(z / getNorm());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian3D add(final Vector<Euclidean3D> v) {
-        final Cartesian3D v3 = (Cartesian3D) v;
-        return new Cartesian3D(x + v3.x, y + v3.y, z + v3.z);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian3D add(double factor, final Vector<Euclidean3D> v) {
-        return new Cartesian3D(1, this, factor, (Cartesian3D) v);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian3D subtract(final Vector<Euclidean3D> v) {
-        final Cartesian3D v3 = (Cartesian3D) v;
-        return new Cartesian3D(x - v3.x, y - v3.y, z - v3.z);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian3D subtract(final double factor, final Vector<Euclidean3D> v) {
-        return new Cartesian3D(1, this, -factor, (Cartesian3D) v);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian3D normalize() throws MathArithmeticException {
-        double s = getNorm();
-        if (s == 0) {
-            throw new MathArithmeticException(LocalizedFormats.CANNOT_NORMALIZE_A_ZERO_NORM_VECTOR);
-        }
-        return scalarMultiply(1 / s);
-    }
-
-    /** Get a vector orthogonal to the instance.
-     * <p>There are an infinite number of normalized vectors orthogonal
-     * to the instance. This method picks up one of them almost
-     * arbitrarily. It is useful when one needs to compute a reference
-     * frame with one of the axes in a predefined direction. The
-     * following example shows how to build a frame having the k axis
-     * aligned with the known vector u :
-     * <pre><code>
-     *   Cartesian3D k = u.normalize();
-     *   Cartesian3D i = k.orthogonal();
-     *   Cartesian3D j = Cartesian3D.crossProduct(k, i);
-     * </code></pre>
-     * @return a new normalized vector orthogonal to the instance
-     * @exception MathArithmeticException if the norm of the instance is null
-     */
-    public Cartesian3D orthogonal() throws MathArithmeticException {
-
-        double threshold = 0.6 * getNorm();
-        if (threshold == 0) {
-            throw new MathArithmeticException(LocalizedFormats.ZERO_NORM);
-        }
-
-        if (FastMath.abs(x) <= threshold) {
-            double inverse  = 1 / FastMath.sqrt(y * y + z * z);
-            return new Cartesian3D(0, inverse * z, -inverse * y);
-        } else if (FastMath.abs(y) <= threshold) {
-            double inverse  = 1 / FastMath.sqrt(x * x + z * z);
-            return new Cartesian3D(-inverse * z, 0, inverse * x);
-        }
-        double inverse  = 1 / FastMath.sqrt(x * x + y * y);
-        return new Cartesian3D(inverse * y, -inverse * x, 0);
-
-    }
-
-    /** Compute the angular separation between two vectors.
-     * <p>This method computes the angular separation between two
-     * vectors using the dot product for well separated vectors and the
-     * cross product for almost aligned vectors. This allows to have a
-     * good accuracy in all cases, even for vectors very close to each
-     * other.</p>
-     * @param v1 first vector
-     * @param v2 second vector
-     * @return angular separation between v1 and v2
-     * @exception MathArithmeticException if either vector has a null norm
-     */
-    public static double angle(Cartesian3D v1, Cartesian3D v2) throws MathArithmeticException {
-
-        double normProduct = v1.getNorm() * v2.getNorm();
-        if (normProduct == 0) {
-            throw new MathArithmeticException(LocalizedFormats.ZERO_NORM);
-        }
-
-        double dot = v1.dotProduct(v2);
-        double threshold = normProduct * 0.9999;
-        if ((dot < -threshold) || (dot > threshold)) {
-            // the vectors are almost aligned, compute using the sine
-            Cartesian3D v3 = crossProduct(v1, v2);
-            if (dot >= 0) {
-                return FastMath.asin(v3.getNorm() / normProduct);
-            }
-            return FastMath.PI - FastMath.asin(v3.getNorm() / normProduct);
-        }
-
-        // the vectors are sufficiently separated to use the cosine
-        return FastMath.acos(dot / normProduct);
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian3D negate() {
-        return new Cartesian3D(-x, -y, -z);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian3D scalarMultiply(double a) {
-        return new Cartesian3D(a * x, a * y, a * z);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isNaN() {
-        return Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(z);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isInfinite() {
-        return !isNaN() && (Double.isInfinite(x) || Double.isInfinite(y) || Double.isInfinite(z));
-    }
-
-    /**
-     * Test for the equality of two 3D vectors.
-     * <p>
-     * If all coordinates of two 3D vectors are exactly the same, and none are
-     * <code>Double.NaN</code>, the two 3D vectors are considered to be equal.
-     * </p>
-     * <p>
-     * <code>NaN</code> coordinates are considered to affect globally the vector
-     * and be equals to each other - i.e, if either (or all) coordinates of the
-     * 3D vector are equal to <code>Double.NaN</code>, the 3D vector is equal to
-     * {@link #NaN}.
-     * </p>
-     *
-     * @param other Object to test for equality to this
-     * @return true if two 3D vector objects are equal, false if
-     *         object is null, not an instance of Cartesian3D, or
-     *         not equal to this Cartesian3D instance
-     *
-     */
-    @Override
-    public boolean equals(Object other) {
-
-        if (this == other) {
-            return true;
-        }
-
-        if (other instanceof Cartesian3D) {
-            final Cartesian3D rhs = (Cartesian3D)other;
-            if (rhs.isNaN()) {
-                return this.isNaN();
-            }
-
-            return (x == rhs.x) && (y == rhs.y) && (z == rhs.z);
-        }
-        return false;
-    }
-
-    /**
-     * Get a hashCode for the 3D vector.
-     * <p>
-     * All NaN values have the same hash code.</p>
-     *
-     * @return a hash code value for this object
-     */
-    @Override
-    public int hashCode() {
-        if (isNaN()) {
-            return 642;
-        }
-        return 643 * (164 * MathUtils.hash(x) +  3 * MathUtils.hash(y) +  MathUtils.hash(z));
-    }
-
-    /** {@inheritDoc}
-     * <p>
-     * The implementation uses specific multiplication and addition
-     * algorithms to preserve accuracy and reduce cancellation effects.
-     * It should be very accurate even for nearly orthogonal vectors.
-     * </p>
-     * @see LinearCombination#value(double, double, double, double, double, double)
-     */
-    @Override
-    public double dotProduct(final Vector<Euclidean3D> v) {
-        final Cartesian3D v3 = (Cartesian3D) v;
-        return LinearCombination.value(x, v3.x, y, v3.y, z, v3.z);
-    }
-
-    /** Compute the cross-product of the instance with another vector.
-     * @param v other vector
-     * @return the cross product this ^ v as a new Cartesian3D
-     */
-    public Cartesian3D crossProduct(final Vector<Euclidean3D> v) {
-        final Cartesian3D v3 = (Cartesian3D) v;
-        return new Cartesian3D(LinearCombination.value(y, v3.z, -z, v3.y),
-                            LinearCombination.value(z, v3.x, -x, v3.z),
-                            LinearCombination.value(x, v3.y, -y, v3.x));
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distance1(Vector<Euclidean3D> v) {
-        final Cartesian3D v3 = (Cartesian3D) v;
-        final double dx = FastMath.abs(v3.x - x);
-        final double dy = FastMath.abs(v3.y - y);
-        final double dz = FastMath.abs(v3.z - z);
-        return dx + dy + dz;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distance(Point<Euclidean3D> p) {
-        return distance((Cartesian3D) p);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distance(Vector<Euclidean3D> v) {
-        return distance((Cartesian3D) v);
-    }
-
-    /** Compute the distance between the instance and other coordinates.
-     * @param c other coordinates
-     * @return the distance between the instance and c
-     */
-    public double distance(Cartesian3D c) {
-        final double dx = c.x - x;
-        final double dy = c.y - y;
-        final double dz = c.z - z;
-        return FastMath.sqrt(dx * dx + dy * dy + dz * dz);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distanceInf(Vector<Euclidean3D> v) {
-        final Cartesian3D v3 = (Cartesian3D) v;
-        final double dx = FastMath.abs(v3.x - x);
-        final double dy = FastMath.abs(v3.y - y);
-        final double dz = FastMath.abs(v3.z - z);
-        return FastMath.max(FastMath.max(dx, dy), dz);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distanceSq(Vector<Euclidean3D> v) {
-        final Cartesian3D v3 = (Cartesian3D) v;
-        final double dx = v3.x - x;
-        final double dy = v3.y - y;
-        final double dz = v3.z - z;
-        return dx * dx + dy * dy + dz * dz;
-    }
-
-    /** Compute the dot-product of two vectors.
-     * @param v1 first vector
-     * @param v2 second vector
-     * @return the dot product v1.v2
-     */
-    public static double dotProduct(Cartesian3D v1, Cartesian3D v2) {
-        return v1.dotProduct(v2);
-    }
-
-    /** Compute the cross-product of two vectors.
-     * @param v1 first vector
-     * @param v2 second vector
-     * @return the cross product v1 ^ v2 as a new Vector
-     */
-    public static Cartesian3D crossProduct(final Cartesian3D v1, final Cartesian3D v2) {
-        return v1.crossProduct(v2);
-    }
-
-    /** Compute the distance between two vectors according to the L<sub>1</sub> norm.
-     * <p>Calling this method is equivalent to calling:
-     * <code>v1.subtract(v2).getNorm1()</code> except that no intermediate
-     * vector is built</p>
-     * @param v1 first vector
-     * @param v2 second vector
-     * @return the distance between v1 and v2 according to the L<sub>1</sub> norm
-     */
-    public static double distance1(Cartesian3D v1, Cartesian3D v2) {
-        return v1.distance1(v2);
-    }
-
-    /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
-     * <p>Calling this method is equivalent to calling:
-     * <code>v1.subtract(v2).getNorm()</code> except that no intermediate
-     * vector is built</p>
-     * @param v1 first vector
-     * @param v2 second vector
-     * @return the distance between v1 and v2 according to the L<sub>2</sub> norm
-     */
-    public static double distance(Cartesian3D v1, Cartesian3D v2) {
-        return v1.distance(v2);
-    }
-
-    /** Compute the distance between two vectors according to the L<sub>&infin;</sub> norm.
-     * <p>Calling this method is equivalent to calling:
-     * <code>v1.subtract(v2).getNormInf()</code> except that no intermediate
-     * vector is built</p>
-     * @param v1 first vector
-     * @param v2 second vector
-     * @return the distance between v1 and v2 according to the L<sub>&infin;</sub> norm
-     */
-    public static double distanceInf(Cartesian3D v1, Cartesian3D v2) {
-        return v1.distanceInf(v2);
-    }
-
-    /** Compute the square of the distance between two vectors.
-     * <p>Calling this method is equivalent to calling:
-     * <code>v1.subtract(v2).getNormSq()</code> except that no intermediate
-     * vector is built</p>
-     * @param v1 first vector
-     * @param v2 second vector
-     * @return the square of the distance between v1 and v2
-     */
-    public static double distanceSq(Cartesian3D v1, Cartesian3D v2) {
-        return v1.distanceSq(v2);
-    }
-
-    /** Get a string representation of this vector.
-     * @return a string representation of this vector
-     */
-    @Override
-    public String toString() {
-        return Vector3DFormat.getInstance().format(this);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public String toString(final NumberFormat format) {
-        return new Vector3DFormat(format).format(this);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Euclidean3D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Euclidean3D.java
deleted file mode 100644
index cde306f..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Euclidean3D.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.Serializable;
-
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.euclidean.twod.Euclidean2D;
-
-/**
- * This class implements a three-dimensional space.
- * @since 3.0
- */
-public class Euclidean3D implements Serializable, Space {
-
-    /** Serializable version identifier. */
-    private static final long serialVersionUID = 6249091865814886817L;
-
-    /** Private constructor for the singleton.
-     */
-    private Euclidean3D() {
-    }
-
-    /** Get the unique instance.
-     * @return the unique instance
-     */
-    public static Euclidean3D getInstance() {
-        return LazyHolder.INSTANCE;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int getDimension() {
-        return 3;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Euclidean2D getSubSpace() {
-        return Euclidean2D.getInstance();
-    }
-
-    // CHECKSTYLE: stop HideUtilityClassConstructor
-    /** Holder for the instance.
-     * <p>We use here the Initialization On Demand Holder Idiom.</p>
-     */
-    private static class LazyHolder {
-        /** Cached field instance. */
-        private static final Euclidean3D INSTANCE = new Euclidean3D();
-    }
-    // CHECKSTYLE: resume HideUtilityClassConstructor
-
-    /** Handle deserialization of the singleton.
-     * @return the singleton instance
-     */
-    private Object readResolve() {
-        // return the singleton instance
-        return LazyHolder.INSTANCE;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotation.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotation.java
index d4c7a18..2ed4b59 100644
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotation.java
+++ b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotation.java
@@ -19,6 +19,9 @@
 
 import java.io.Serializable;
 
+import org.apache.commons.numbers.quaternion.Quaternion;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
 import org.apache.commons.math4.Field;
 import org.apache.commons.math4.RealFieldElement;
 import org.apache.commons.math4.exception.MathArithmeticException;
@@ -28,7 +31,7 @@
 import org.apache.commons.math4.util.MathArrays;
 
 /**
- * This class is a re-implementation of {@link Rotation} using {@link RealFieldElement}.
+ * Implementation of rotation using {@link RealFieldElement}.
  * <p>Instance of this class are guaranteed to be immutable.</p>
  *
  * @param <T> the type of the field elements
@@ -820,8 +823,8 @@
                 // (-r) (Cartesian3D.plusK) coordinates are :
                 // sin (theta), -sin (phi) cos (theta), cos (phi) cos (theta)
                 // and we can choose to have theta in the interval [-PI/2 ; +PI/2]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_I);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_K);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_X);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_Z);
                 if ((v2.getX().getReal() < -0.9999999999) || (v2.getX().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(true);
                 }
@@ -836,8 +839,8 @@
                 // (-r) (Cartesian3D.plusJ) coordinates are :
                 // -sin (psi), cos (phi) cos (psi), sin (phi) cos (psi)
                 // and we can choose to have psi in the interval [-PI/2 ; +PI/2]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_I);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_J);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_X);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_Y);
                 if ((v2.getX().getReal() < -0.9999999999) || (v2.getX().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(true);
                 }
@@ -852,8 +855,8 @@
                 // (-r) (Cartesian3D.plusK) coordinates are :
                 // sin (theta) cos (phi), -sin (phi), cos (theta) cos (phi)
                 // and we can choose to have phi in the interval [-PI/2 ; +PI/2]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_J);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_K);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_Y);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_Z);
                 if ((v2.getY().getReal() < -0.9999999999) || (v2.getY().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(true);
                 }
@@ -868,8 +871,8 @@
                 // (-r) (Cartesian3D.plusI) coordinates are :
                 // cos (theta) cos (psi), sin (psi), -sin (theta) cos (psi)
                 // and we can choose to have psi in the interval [-PI/2 ; +PI/2]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_J);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_I);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_Y);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_X);
                 if ((v2.getY().getReal() < -0.9999999999) || (v2.getY().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(true);
                 }
@@ -884,8 +887,8 @@
                 // (-r) (Cartesian3D.plusJ) coordinates are :
                 // -sin (psi) cos (phi), cos (psi) cos (phi), sin (phi)
                 // and we can choose to have phi in the interval [-PI/2 ; +PI/2]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_K);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_J);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_Z);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_Y);
                 if ((v2.getZ().getReal() < -0.9999999999) || (v2.getZ().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(true);
                 }
@@ -900,8 +903,8 @@
                 // (-r) (Cartesian3D.plusI) coordinates are :
                 // cos (psi) cos (theta), sin (psi) cos (theta), -sin (theta)
                 // and we can choose to have theta in the interval [-PI/2 ; +PI/2]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_K);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_I);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_Z);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_X);
                 if  ((v2.getZ().getReal() < -0.9999999999) || (v2.getZ().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(true);
                 }
@@ -916,8 +919,8 @@
                 // (-r) (Cartesian3D.plusI) coordinates are :
                 // cos (theta), sin (theta) sin (phi1), -sin (theta) cos (phi1)
                 // and we can choose to have theta in the interval [0 ; PI]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_I);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_I);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_X);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_X);
                 if ((v2.getX().getReal() < -0.9999999999) || (v2.getX().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(false);
                 }
@@ -932,8 +935,8 @@
                 // (-r) (Cartesian3D.plusI) coordinates are :
                 // cos (psi), sin (psi) cos (phi1), sin (psi) sin (phi1)
                 // and we can choose to have psi in the interval [0 ; PI]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_I);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_I);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_X);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_X);
                 if ((v2.getX().getReal() < -0.9999999999) || (v2.getX().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(false);
                 }
@@ -948,8 +951,8 @@
                 // (-r) (Cartesian3D.plusJ) coordinates are :
                 //  sin (theta1) sin (phi), cos (phi), cos (theta1) sin (phi)
                 // and we can choose to have phi in the interval [0 ; PI]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_J);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_J);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_Y);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_Y);
                 if ((v2.getY().getReal() < -0.9999999999) || (v2.getY().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(false);
                 }
@@ -964,8 +967,8 @@
                 // (-r) (Cartesian3D.plusJ) coordinates are :
                 //  -cos (theta1) sin (psi), cos (psi), sin (theta1) sin (psi)
                 // and we can choose to have psi in the interval [0 ; PI]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_J);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_J);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_Y);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_Y);
                 if ((v2.getY().getReal() < -0.9999999999) || (v2.getY().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(false);
                 }
@@ -980,8 +983,8 @@
                 // (-r) (Cartesian3D.plusK) coordinates are :
                 //  sin (psi1) sin (phi), -cos (psi1) sin (phi), cos (phi)
                 // and we can choose to have phi in the interval [0 ; PI]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_K);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_K);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_Z);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_Z);
                 if ((v2.getZ().getReal() < -0.9999999999) || (v2.getZ().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(false);
                 }
@@ -996,8 +999,8 @@
                 // (-r) (Cartesian3D.plusK) coordinates are :
                 //  cos (psi1) sin (theta), sin (psi1) sin (theta), cos (theta)
                 // and we can choose to have theta in the interval [0 ; PI]
-                FieldVector3D<T> v1 = applyTo(Cartesian3D.PLUS_K);
-                FieldVector3D<T> v2 = applyInverseTo(Cartesian3D.PLUS_K);
+                FieldVector3D<T> v1 = applyTo(Vector3D.Unit.PLUS_Z);
+                FieldVector3D<T> v2 = applyInverseTo(Vector3D.Unit.PLUS_Z);
                 if ((v2.getZ().getReal() < -0.9999999999) || (v2.getZ().getReal() > 0.9999999999)) {
                     throw new CardanEulerSingularityException(false);
                 }
@@ -1074,8 +1077,8 @@
     /** Convert to a constant vector without derivatives.
      * @return a constant vector
      */
-    public Rotation toRotation() {
-        return new Rotation(q0.getReal(), q1.getReal(), q2.getReal(), q3.getReal(), false);
+    public QuaternionRotation toRotation() {
+        return QuaternionRotation.of(q0.getReal(), q1.getReal(), q2.getReal(), q3.getReal());
     }
 
     /** Apply the rotation to a vector.
@@ -1100,7 +1103,7 @@
      * @param u vector to apply the rotation to
      * @return a new vector which is the image of u by the rotation
      */
-    public FieldVector3D<T> applyTo(final Cartesian3D u) {
+    public FieldVector3D<T> applyTo(final Vector3D u) {
 
         final double x = u.getX();
         final double y = u.getY();
@@ -1157,17 +1160,17 @@
      * @param <T> the type of the field elements
      * @return a new vector which is the image of u by the rotation
      */
-    public static <T extends RealFieldElement<T>> FieldVector3D<T> applyTo(final Rotation r, final FieldVector3D<T> u) {
-
+    public static <T extends RealFieldElement<T>> FieldVector3D<T> applyTo(final QuaternionRotation rot, final FieldVector3D<T> u) {
+        final Quaternion r = rot.getQuaternion();
         final T x = u.getX();
         final T y = u.getY();
         final T z = u.getZ();
 
-        final T s = x.multiply(r.getQ1()).add(y.multiply(r.getQ2())).add(z.multiply(r.getQ3()));
+        final T s = x.multiply(r.getX()).add(y.multiply(r.getY())).add(z.multiply(r.getZ()));
 
-        return new FieldVector3D<>(x.multiply(r.getQ0()).subtract(z.multiply(r.getQ2()).subtract(y.multiply(r.getQ3()))).multiply(r.getQ0()).add(s.multiply(r.getQ1())).multiply(2).subtract(x),
-                                    y.multiply(r.getQ0()).subtract(x.multiply(r.getQ3()).subtract(z.multiply(r.getQ1()))).multiply(r.getQ0()).add(s.multiply(r.getQ2())).multiply(2).subtract(y),
-                                    z.multiply(r.getQ0()).subtract(y.multiply(r.getQ1()).subtract(x.multiply(r.getQ2()))).multiply(r.getQ0()).add(s.multiply(r.getQ3())).multiply(2).subtract(z));
+        return new FieldVector3D<>(x.multiply(r.getW()).subtract(z.multiply(r.getY()).subtract(y.multiply(r.getZ()))).multiply(r.getW()).add(s.multiply(r.getX())).multiply(2).subtract(x),
+                                    y.multiply(r.getW()).subtract(x.multiply(r.getZ()).subtract(z.multiply(r.getX()))).multiply(r.getW()).add(s.multiply(r.getY())).multiply(2).subtract(y),
+                                    z.multiply(r.getW()).subtract(y.multiply(r.getX()).subtract(x.multiply(r.getY()))).multiply(r.getW()).add(s.multiply(r.getZ())).multiply(2).subtract(z));
 
     }
 
@@ -1194,7 +1197,7 @@
      * @param u vector to apply the inverse of the rotation to
      * @return a new vector which such that u is its image by the rotation
      */
-    public FieldVector3D<T> applyInverseTo(final Cartesian3D u) {
+    public FieldVector3D<T> applyInverseTo(final Vector3D u) {
 
         final double x = u.getX();
         final double y = u.getY();
@@ -1254,18 +1257,18 @@
      * @param <T> the type of the field elements
      * @return a new vector which such that u is its image by the rotation
      */
-    public static <T extends RealFieldElement<T>> FieldVector3D<T> applyInverseTo(final Rotation r, final FieldVector3D<T> u) {
-
+    public static <T extends RealFieldElement<T>> FieldVector3D<T> applyInverseTo(final QuaternionRotation rot, final FieldVector3D<T> u) {
+        final Quaternion r = rot.getQuaternion();
         final T x = u.getX();
         final T y = u.getY();
         final T z = u.getZ();
 
-        final T s  = x.multiply(r.getQ1()).add(y.multiply(r.getQ2())).add(z.multiply(r.getQ3()));
-        final double m0 = -r.getQ0();
+        final T s  = x.multiply(r.getX()).add(y.multiply(r.getY())).add(z.multiply(r.getZ()));
+        final double m0 = -r.getW();
 
-        return new FieldVector3D<>(x.multiply(m0).subtract(z.multiply(r.getQ2()).subtract(y.multiply(r.getQ3()))).multiply(m0).add(s.multiply(r.getQ1())).multiply(2).subtract(x),
-                                    y.multiply(m0).subtract(x.multiply(r.getQ3()).subtract(z.multiply(r.getQ1()))).multiply(m0).add(s.multiply(r.getQ2())).multiply(2).subtract(y),
-                                    z.multiply(m0).subtract(y.multiply(r.getQ1()).subtract(x.multiply(r.getQ2()))).multiply(m0).add(s.multiply(r.getQ3())).multiply(2).subtract(z));
+        return new FieldVector3D<>(x.multiply(m0).subtract(z.multiply(r.getY()).subtract(y.multiply(r.getZ()))).multiply(m0).add(s.multiply(r.getX())).multiply(2).subtract(x),
+                                    y.multiply(m0).subtract(x.multiply(r.getZ()).subtract(z.multiply(r.getX()))).multiply(m0).add(s.multiply(r.getY())).multiply(2).subtract(y),
+                                    z.multiply(m0).subtract(y.multiply(r.getX()).subtract(x.multiply(r.getY()))).multiply(m0).add(s.multiply(r.getZ())).multiply(2).subtract(z));
 
     }
 
@@ -1333,7 +1336,7 @@
      * @param r rotation to apply the rotation to
      * @return a new rotation which is the composition of r by the instance
      */
-    public FieldRotation<T> applyTo(final Rotation r) {
+    public FieldRotation<T> applyTo(final QuaternionRotation r) {
         return compose(r, RotationConvention.VECTOR_OPERATOR);
     }
 
@@ -1361,7 +1364,7 @@
      * @param convention convention to use for the semantics of the angle
      * @return a new rotation which is the composition of r by the instance
      */
-    public FieldRotation<T> compose(final Rotation r, final RotationConvention convention) {
+    public FieldRotation<T> compose(final QuaternionRotation r, final RotationConvention convention) {
         return convention == RotationConvention.VECTOR_OPERATOR ?
                              composeInternal(r) : applyTo(r, this);
     }
@@ -1371,11 +1374,12 @@
      * @return a new rotation which is the composition of r by the instance
      * using vector operator convention
      */
-    private FieldRotation<T> composeInternal(final Rotation r) {
-        return new FieldRotation<>(q0.multiply(r.getQ0()).subtract(q1.multiply(r.getQ1()).add(q2.multiply(r.getQ2())).add(q3.multiply(r.getQ3()))),
-                        q0.multiply(r.getQ1()).add(q1.multiply(r.getQ0())).add(q3.multiply(r.getQ2()).subtract(q2.multiply(r.getQ3()))),
-                        q0.multiply(r.getQ2()).add(q2.multiply(r.getQ0())).add(q1.multiply(r.getQ3()).subtract(q3.multiply(r.getQ1()))),
-                        q0.multiply(r.getQ3()).add(q3.multiply(r.getQ0())).add(q2.multiply(r.getQ1()).subtract(q1.multiply(r.getQ2()))),
+    private FieldRotation<T> composeInternal(final QuaternionRotation rot) {
+        final Quaternion r = rot.getQuaternion();
+        return new FieldRotation<>(q0.multiply(r.getW()).subtract(q1.multiply(r.getX()).add(q2.multiply(r.getY())).add(q3.multiply(r.getZ()))),
+                        q0.multiply(r.getX()).add(q1.multiply(r.getW())).add(q3.multiply(r.getY()).subtract(q2.multiply(r.getZ()))),
+                        q0.multiply(r.getY()).add(q2.multiply(r.getW())).add(q1.multiply(r.getZ()).subtract(q3.multiply(r.getX()))),
+                        q0.multiply(r.getZ()).add(q3.multiply(r.getW())).add(q2.multiply(r.getX()).subtract(q1.multiply(r.getY()))),
                         false);
     }
 
@@ -1390,11 +1394,12 @@
      * @param <T> the type of the field elements
      * @return a new rotation which is the composition of r by the instance
      */
-    public static <T extends RealFieldElement<T>> FieldRotation<T> applyTo(final Rotation r1, final FieldRotation<T> rInner) {
-        return new FieldRotation<>(rInner.q0.multiply(r1.getQ0()).subtract(rInner.q1.multiply(r1.getQ1()).add(rInner.q2.multiply(r1.getQ2())).add(rInner.q3.multiply(r1.getQ3()))),
-                                    rInner.q1.multiply(r1.getQ0()).add(rInner.q0.multiply(r1.getQ1())).add(rInner.q2.multiply(r1.getQ3()).subtract(rInner.q3.multiply(r1.getQ2()))),
-                                    rInner.q2.multiply(r1.getQ0()).add(rInner.q0.multiply(r1.getQ2())).add(rInner.q3.multiply(r1.getQ1()).subtract(rInner.q1.multiply(r1.getQ3()))),
-                                    rInner.q3.multiply(r1.getQ0()).add(rInner.q0.multiply(r1.getQ3())).add(rInner.q1.multiply(r1.getQ2()).subtract(rInner.q2.multiply(r1.getQ1()))),
+    public static <T extends RealFieldElement<T>> FieldRotation<T> applyTo(final QuaternionRotation rot1, final FieldRotation<T> rInner) {
+        final Quaternion r1 = rot1.getQuaternion();
+        return new FieldRotation<>(rInner.q0.multiply(r1.getW()).subtract(rInner.q1.multiply(r1.getX()).add(rInner.q2.multiply(r1.getY())).add(rInner.q3.multiply(r1.getZ()))),
+                                    rInner.q1.multiply(r1.getW()).add(rInner.q0.multiply(r1.getX())).add(rInner.q2.multiply(r1.getZ()).subtract(rInner.q3.multiply(r1.getY()))),
+                                    rInner.q2.multiply(r1.getW()).add(rInner.q0.multiply(r1.getY())).add(rInner.q3.multiply(r1.getX()).subtract(rInner.q1.multiply(r1.getZ()))),
+                                    rInner.q3.multiply(r1.getW()).add(rInner.q0.multiply(r1.getZ())).add(rInner.q1.multiply(r1.getY()).subtract(rInner.q2.multiply(r1.getX()))),
                                     false);
     }
 
@@ -1467,7 +1472,7 @@
      * @return a new rotation which is the composition of r by the inverse
      * of the instance
      */
-    public FieldRotation<T> applyInverseTo(final Rotation r) {
+    public FieldRotation<T> applyInverseTo(final QuaternionRotation r) {
         return composeInverse(r, RotationConvention.VECTOR_OPERATOR);
     }
 
@@ -1497,7 +1502,7 @@
      * @return a new rotation which is the composition of r by the inverse
      * of the instance
      */
-    public FieldRotation<T> composeInverse(final Rotation r, final RotationConvention convention) {
+    public FieldRotation<T> composeInverse(final QuaternionRotation r, final RotationConvention convention) {
         return convention == RotationConvention.VECTOR_OPERATOR ?
                              composeInverseInternal(r) : applyTo(r, revert());
     }
@@ -1508,11 +1513,12 @@
      * @return a new rotation which is the composition of r by the inverse
      * of the instance using vector operator convention
      */
-    private FieldRotation<T> composeInverseInternal(Rotation r) {
-        return new FieldRotation<>(q0.multiply(r.getQ0()).add(q1.multiply(r.getQ1()).add(q2.multiply(r.getQ2())).add(q3.multiply(r.getQ3()))).negate(),
-                                    q1.multiply(r.getQ0()).add(q3.multiply(r.getQ2()).subtract(q2.multiply(r.getQ3()))).subtract(q0.multiply(r.getQ1())),
-                                    q2.multiply(r.getQ0()).add(q1.multiply(r.getQ3()).subtract(q3.multiply(r.getQ1()))).subtract(q0.multiply(r.getQ2())),
-                                    q3.multiply(r.getQ0()).add(q2.multiply(r.getQ1()).subtract(q1.multiply(r.getQ2()))).subtract(q0.multiply(r.getQ3())),
+    private FieldRotation<T> composeInverseInternal(QuaternionRotation rot) {
+        final Quaternion r = rot.getQuaternion();
+        return new FieldRotation<>(q0.multiply(r.getW()).add(q1.multiply(r.getX()).add(q2.multiply(r.getY())).add(q3.multiply(r.getZ()))).negate(),
+                                    q1.multiply(r.getW()).add(q3.multiply(r.getY()).subtract(q2.multiply(r.getZ()))).subtract(q0.multiply(r.getX())),
+                                    q2.multiply(r.getW()).add(q1.multiply(r.getZ()).subtract(q3.multiply(r.getX()))).subtract(q0.multiply(r.getY())),
+                                    q3.multiply(r.getW()).add(q2.multiply(r.getX()).subtract(q1.multiply(r.getY()))).subtract(q0.multiply(r.getZ())),
                                     false);
     }
 
@@ -1529,11 +1535,12 @@
      * @return a new rotation which is the composition of r by the inverse
      * of the instance
      */
-    public static <T extends RealFieldElement<T>> FieldRotation<T> applyInverseTo(final Rotation rOuter, final FieldRotation<T> rInner) {
-        return new FieldRotation<>(rInner.q0.multiply(rOuter.getQ0()).add(rInner.q1.multiply(rOuter.getQ1()).add(rInner.q2.multiply(rOuter.getQ2())).add(rInner.q3.multiply(rOuter.getQ3()))).negate(),
-                                    rInner.q0.multiply(rOuter.getQ1()).add(rInner.q2.multiply(rOuter.getQ3()).subtract(rInner.q3.multiply(rOuter.getQ2()))).subtract(rInner.q1.multiply(rOuter.getQ0())),
-                                    rInner.q0.multiply(rOuter.getQ2()).add(rInner.q3.multiply(rOuter.getQ1()).subtract(rInner.q1.multiply(rOuter.getQ3()))).subtract(rInner.q2.multiply(rOuter.getQ0())),
-                                    rInner.q0.multiply(rOuter.getQ3()).add(rInner.q1.multiply(rOuter.getQ2()).subtract(rInner.q2.multiply(rOuter.getQ1()))).subtract(rInner.q3.multiply(rOuter.getQ0())),
+    public static <T extends RealFieldElement<T>> FieldRotation<T> applyInverseTo(final QuaternionRotation rotOuter, final FieldRotation<T> rInner) {
+        final Quaternion rOuter = rotOuter.getQuaternion();
+        return new FieldRotation<>(rInner.q0.multiply(rOuter.getW()).add(rInner.q1.multiply(rOuter.getX()).add(rInner.q2.multiply(rOuter.getY())).add(rInner.q3.multiply(rOuter.getZ()))).negate(),
+                                    rInner.q0.multiply(rOuter.getX()).add(rInner.q2.multiply(rOuter.getZ()).subtract(rInner.q3.multiply(rOuter.getY()))).subtract(rInner.q1.multiply(rOuter.getW())),
+                                    rInner.q0.multiply(rOuter.getY()).add(rInner.q3.multiply(rOuter.getX()).subtract(rInner.q1.multiply(rOuter.getZ()))).subtract(rInner.q2.multiply(rOuter.getW())),
+                                    rInner.q0.multiply(rOuter.getZ()).add(rInner.q1.multiply(rOuter.getY()).subtract(rInner.q2.multiply(rOuter.getX()))).subtract(rInner.q3.multiply(rOuter.getW())),
                                     false);
     }
 
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/FieldVector3D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/FieldVector3D.java
index 6543e00..74d4d6f 100644
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/FieldVector3D.java
+++ b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/FieldVector3D.java
@@ -20,6 +20,7 @@
 import java.io.Serializable;
 import java.text.NumberFormat;
 
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.math4.RealFieldElement;
 import org.apache.commons.math4.exception.DimensionMismatchException;
 import org.apache.commons.math4.exception.MathArithmeticException;
@@ -28,7 +29,7 @@
 import org.apache.commons.math4.util.MathArrays;
 
 /**
- * This class is a re-implementation of {@link Cartesian3D} using {@link RealFieldElement}.
+ * This class is a re-implementation of {@link Vector3D} using {@link RealFieldElement}.
  * <p>Instance of this class are guaranteed to be immutable.</p>
  * @param <T> the type of the field elements
  * @since 3.2
@@ -110,7 +111,7 @@
      * @param a scale factor
      * @param u base (unscaled) vector
      */
-    public FieldVector3D(final T a, final Cartesian3D u) {
+    public FieldVector3D(final T a, final Vector3D u) {
         this.x = a.multiply(u.getX());
         this.y = a.multiply(u.getY());
         this.z = a.multiply(u.getZ());
@@ -152,8 +153,8 @@
      * @param a2 second scale factor
      * @param u2 second base (unscaled) vector
      */
-    public FieldVector3D(final T a1, final Cartesian3D u1,
-                         final T a2, final Cartesian3D u2) {
+    public FieldVector3D(final T a1, final Vector3D u1,
+                         final T a2, final Vector3D u2) {
         final T prototype = a1;
         this.x = prototype.linearCombination(u1.getX(), a1, u2.getX(), a2);
         this.y = prototype.linearCombination(u1.getY(), a1, u2.getY(), a2);
@@ -205,9 +206,9 @@
      * @param a3 third scale factor
      * @param u3 third base (unscaled) vector
      */
-    public FieldVector3D(final T a1, final Cartesian3D u1,
-                         final T a2, final Cartesian3D u2,
-                         final T a3, final Cartesian3D u3) {
+    public FieldVector3D(final T a1, final Vector3D u1,
+                         final T a2, final Vector3D u2,
+                         final T a3, final Vector3D u3) {
         final T prototype = a1;
         this.x = prototype.linearCombination(u1.getX(), a1, u2.getX(), a2, u3.getX(), a3);
         this.y = prototype.linearCombination(u1.getY(), a1, u2.getY(), a2, u3.getY(), a3);
@@ -267,10 +268,10 @@
      * @param a4 fourth scale factor
      * @param u4 fourth base (unscaled) vector
      */
-    public FieldVector3D(final T a1, final Cartesian3D u1,
-                         final T a2, final Cartesian3D u2,
-                         final T a3, final Cartesian3D u3,
-                         final T a4, final Cartesian3D u4) {
+    public FieldVector3D(final T a1, final Vector3D u1,
+                         final T a2, final Vector3D u2,
+                         final T a3, final Vector3D u3,
+                         final T a4, final Vector3D u4) {
         final T prototype = a1;
         this.x = prototype.linearCombination(u1.getX(), a1, u2.getX(), a2, u3.getX(), a3, u4.getX(), a4);
         this.y = prototype.linearCombination(u1.getY(), a1, u2.getY(), a2, u3.getY(), a3, u4.getY(), a4);
@@ -338,8 +339,8 @@
     /** Convert to a constant vector without derivatives.
      * @return a constant vector
      */
-    public Cartesian3D toVector3D() {
-        return new Cartesian3D(x.getReal(), y.getReal(), z.getReal());
+    public Vector3D toVector3D() {
+        return Vector3D.of(x.getReal(), y.getReal(), z.getReal());
     }
 
     /** Get the L<sub>1</sub> norm for the vector.
@@ -415,7 +416,7 @@
      * @param v vector to add
      * @return a new vector
      */
-    public FieldVector3D<T> add(final Cartesian3D v) {
+    public FieldVector3D<T> add(final Vector3D v) {
         return new FieldVector3D<>(x.add(v.getX()), y.add(v.getY()), z.add(v.getZ()));
     }
 
@@ -433,7 +434,7 @@
      * @param v vector to add
      * @return a new vector
      */
-    public FieldVector3D<T> add(final T factor, final Cartesian3D v) {
+    public FieldVector3D<T> add(final T factor, final Vector3D v) {
         return new FieldVector3D<>(x.add(factor.multiply(v.getX())),
                                     y.add(factor.multiply(v.getY())),
                                     z.add(factor.multiply(v.getZ())));
@@ -453,7 +454,7 @@
      * @param v vector to add
      * @return a new vector
      */
-    public FieldVector3D<T> add(final double factor, final Cartesian3D v) {
+    public FieldVector3D<T> add(final double factor, final Vector3D v) {
         return new FieldVector3D<>(x.add(factor * v.getX()),
                                     y.add(factor * v.getY()),
                                     z.add(factor * v.getZ()));
@@ -471,7 +472,7 @@
      * @param v vector to subtract
      * @return a new vector
      */
-    public FieldVector3D<T> subtract(final Cartesian3D v) {
+    public FieldVector3D<T> subtract(final Vector3D v) {
         return new FieldVector3D<>(x.subtract(v.getX()), y.subtract(v.getY()), z.subtract(v.getZ()));
     }
 
@@ -489,7 +490,7 @@
      * @param v vector to subtract
      * @return a new vector
      */
-    public FieldVector3D<T> subtract(final T factor, final Cartesian3D v) {
+    public FieldVector3D<T> subtract(final T factor, final Vector3D v) {
         return new FieldVector3D<>(x.subtract(factor.multiply(v.getX())),
                                     y.subtract(factor.multiply(v.getY())),
                                     z.subtract(factor.multiply(v.getZ())));
@@ -509,7 +510,7 @@
      * @param v vector to subtract
      * @return a new vector
      */
-    public FieldVector3D<T> subtract(final double factor, final Cartesian3D v) {
+    public FieldVector3D<T> subtract(final double factor, final Vector3D v) {
         return new FieldVector3D<>(x.subtract(factor * v.getX()),
                                     y.subtract(factor * v.getY()),
                                     z.subtract(factor * v.getZ()));
@@ -535,9 +536,9 @@
      * following example shows how to build a frame having the k axis
      * aligned with the known vector u :
      * <pre><code>
-     *   Cartesian3D k = u.normalize();
-     *   Cartesian3D i = k.orthogonal();
-     *   Cartesian3D j = Cartesian3D.crossProduct(k, i);
+     *   Vector3D k = u.normalize();
+     *   Vector3D i = k.orthogonal();
+     *   Vector3D j = Vector3D.crossProduct(k, i);
      * </code></pre>
      * @return a new normalized vector orthogonal to the instance
      * @exception MathArithmeticException if the norm of the instance is null
@@ -610,10 +611,10 @@
      * @return angular separation between v1 and v2
      * @exception MathArithmeticException if either vector has a null norm
      */
-    public static <T extends RealFieldElement<T>> T angle(final FieldVector3D<T> v1, final Cartesian3D v2)
+    public static <T extends RealFieldElement<T>> T angle(final FieldVector3D<T> v1, final Vector3D v2)
         throws MathArithmeticException {
 
-        final T normProduct = v1.getNorm().multiply(v2.getNorm());
+        final T normProduct = v1.getNorm().multiply(v2.norm());
         if (normProduct.getReal() == 0) {
             throw new MathArithmeticException(LocalizedFormats.ZERO_NORM);
         }
@@ -646,7 +647,7 @@
      * @return angular separation between v1 and v2
      * @exception MathArithmeticException if either vector has a null norm
      */
-    public static <T extends RealFieldElement<T>> T angle(final Cartesian3D v1, final FieldVector3D<T> v2)
+    public static <T extends RealFieldElement<T>> T angle(final Vector3D v1, final FieldVector3D<T> v2)
         throws MathArithmeticException {
         return angle(v2, v1);
     }
@@ -770,7 +771,7 @@
      * @param v second vector
      * @return the dot product this.v
      */
-    public T dotProduct(final Cartesian3D v) {
+    public T dotProduct(final Vector3D v) {
         return x.linearCombination(v.getX(), x, v.getY(), y, v.getZ(), z);
     }
 
@@ -788,7 +789,7 @@
      * @param v other vector
      * @return the cross product this ^ v as a new FieldVector3D
      */
-    public FieldVector3D<T> crossProduct(final Cartesian3D v) {
+    public FieldVector3D<T> crossProduct(final Vector3D v) {
         return new FieldVector3D<>(x.linearCombination(v.getZ(), y, -v.getY(), z),
                                     y.linearCombination(v.getX(), z, -v.getZ(), x),
                                     z.linearCombination(v.getY(), x, -v.getX(), y));
@@ -815,7 +816,7 @@
      * @param v second vector
      * @return the distance between the instance and p according to the L<sub>1</sub> norm
      */
-    public T distance1(final Cartesian3D v) {
+    public T distance1(final Vector3D v) {
         final T dx = x.subtract(v.getX()).abs();
         final T dy = y.subtract(v.getY()).abs();
         final T dz = z.subtract(v.getZ()).abs();
@@ -843,7 +844,7 @@
      * @param v second vector
      * @return the distance between the instance and p according to the L<sub>2</sub> norm
      */
-    public T distance(final Cartesian3D v) {
+    public T distance(final Vector3D v) {
         final T dx = x.subtract(v.getX());
         final T dy = y.subtract(v.getY());
         final T dz = z.subtract(v.getZ());
@@ -883,7 +884,7 @@
      * @param v second vector
      * @return the distance between the instance and p according to the L<sub>&infin;</sub> norm
      */
-    public T distanceInf(final Cartesian3D v) {
+    public T distanceInf(final Vector3D v) {
         final T dx = x.subtract(v.getX()).abs();
         final T dy = y.subtract(v.getY()).abs();
         final T dz = z.subtract(v.getZ()).abs();
@@ -923,7 +924,7 @@
      * @param v second vector
      * @return the square of the distance between the instance and p
      */
-    public T distanceSq(final Cartesian3D v) {
+    public T distanceSq(final Vector3D v) {
         final T dx = x.subtract(v.getX());
         final T dy = y.subtract(v.getY());
         final T dz = z.subtract(v.getZ());
@@ -948,7 +949,7 @@
      * @return the dot product v1.v2
      */
     public static <T extends RealFieldElement<T>> T dotProduct(final FieldVector3D<T> v1,
-                                                                   final Cartesian3D v2) {
+                                                                   final Vector3D v2) {
         return v1.dotProduct(v2);
     }
 
@@ -958,7 +959,7 @@
      * @param <T> the type of the field elements
      * @return the dot product v1.v2
      */
-    public static <T extends RealFieldElement<T>> T dotProduct(final Cartesian3D v1,
+    public static <T extends RealFieldElement<T>> T dotProduct(final Vector3D v1,
                                                                    final FieldVector3D<T> v2) {
         return v2.dotProduct(v1);
     }
@@ -981,7 +982,7 @@
      * @return the cross product v1 ^ v2 as a new Vector
      */
     public static <T extends RealFieldElement<T>> FieldVector3D<T> crossProduct(final FieldVector3D<T> v1,
-                                                                                    final Cartesian3D v2) {
+                                                                                    final Vector3D v2) {
         return v1.crossProduct(v2);
     }
 
@@ -991,7 +992,7 @@
      * @param <T> the type of the field elements
      * @return the cross product v1 ^ v2 as a new Vector
      */
-    public static <T extends RealFieldElement<T>> FieldVector3D<T> crossProduct(final Cartesian3D v1,
+    public static <T extends RealFieldElement<T>> FieldVector3D<T> crossProduct(final Vector3D v1,
                                                                                     final FieldVector3D<T> v2) {
         return new FieldVector3D<>(v2.x.linearCombination(v1.getY(), v2.z, -v1.getZ(), v2.y),
                                     v2.y.linearCombination(v1.getZ(), v2.x, -v1.getX(), v2.z),
@@ -1022,7 +1023,7 @@
      * @return the distance between v1 and v2 according to the L<sub>1</sub> norm
      */
     public static <T extends RealFieldElement<T>> T distance1(final FieldVector3D<T> v1,
-                                                                  final Cartesian3D v2) {
+                                                                  final Vector3D v2) {
         return v1.distance1(v2);
     }
 
@@ -1035,7 +1036,7 @@
      * @param <T> the type of the field elements
      * @return the distance between v1 and v2 according to the L<sub>1</sub> norm
      */
-    public static <T extends RealFieldElement<T>> T distance1(final Cartesian3D v1,
+    public static <T extends RealFieldElement<T>> T distance1(final Vector3D v1,
                                                                   final FieldVector3D<T> v2) {
         return v2.distance1(v1);
     }
@@ -1064,7 +1065,7 @@
      * @return the distance between v1 and v2 according to the L<sub>2</sub> norm
      */
     public static <T extends RealFieldElement<T>> T distance(final FieldVector3D<T> v1,
-                                                                 final Cartesian3D v2) {
+                                                                 final Vector3D v2) {
         return v1.distance(v2);
     }
 
@@ -1077,7 +1078,7 @@
      * @param <T> the type of the field elements
      * @return the distance between v1 and v2 according to the L<sub>2</sub> norm
      */
-    public static <T extends RealFieldElement<T>> T distance(final Cartesian3D v1,
+    public static <T extends RealFieldElement<T>> T distance(final Vector3D v1,
                                                                  final FieldVector3D<T> v2) {
         return v2.distance(v1);
     }
@@ -1106,7 +1107,7 @@
      * @return the distance between v1 and v2 according to the L<sub>&infin;</sub> norm
      */
     public static <T extends RealFieldElement<T>> T distanceInf(final FieldVector3D<T> v1,
-                                                                    final Cartesian3D v2) {
+                                                                    final Vector3D v2) {
         return v1.distanceInf(v2);
     }
 
@@ -1119,7 +1120,7 @@
      * @param <T> the type of the field elements
      * @return the distance between v1 and v2 according to the L<sub>&infin;</sub> norm
      */
-    public static <T extends RealFieldElement<T>> T distanceInf(final Cartesian3D v1,
+    public static <T extends RealFieldElement<T>> T distanceInf(final Vector3D v1,
                                                                     final FieldVector3D<T> v2) {
         return v2.distanceInf(v1);
     }
@@ -1148,7 +1149,7 @@
      * @return the square of the distance between v1 and v2
      */
     public static <T extends RealFieldElement<T>> T distanceSq(final FieldVector3D<T> v1,
-                                                                   final Cartesian3D v2) {
+                                                                   final Vector3D v2) {
         return v1.distanceSq(v2);
     }
 
@@ -1161,7 +1162,7 @@
      * @param <T> the type of the field elements
      * @return the square of the distance between v1 and v2
      */
-    public static <T extends RealFieldElement<T>> T distanceSq(final Cartesian3D v1,
+    public static <T extends RealFieldElement<T>> T distanceSq(final Vector3D v1,
                                                                    final FieldVector3D<T> v2) {
         return v2.distanceSq(v1);
     }
@@ -1171,15 +1172,6 @@
      */
     @Override
     public String toString() {
-        return Vector3DFormat.getInstance().format(toVector3D());
+        return toVector3D().toString();
     }
-
-    /** Get a string representation of this vector.
-     * @param format the custom format for components
-     * @return a string representation of this vector
-     */
-    public String toString(final NumberFormat format) {
-        return new Vector3DFormat(format).format(toVector3D());
-    }
-
 }
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Line.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Line.java
deleted file mode 100644
index 6b467fc..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Line.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * 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 org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Vector;
-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.Cartesian1D;
-import org.apache.commons.math4.geometry.partitioning.Embedding;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.numbers.core.Precision;
-
-/** The class represent lines in a three dimensional space.
-
- * <p>Each oriented line is intrinsically associated with an abscissa
- * which is a coordinate on the line. The point at abscissa 0 is the
- * orthogonal projection of the origin on the line, another equivalent
- * way to express this is to say that it is the point of the line
- * which is closest to the origin. Abscissa increases in the line
- * direction.</p>
-
- * @since 3.0
- */
-public class Line implements Embedding<Euclidean3D, Euclidean1D> {
-
-    /** Line direction. */
-    private Cartesian3D direction;
-
-    /** Line point closest to the origin. */
-    private Cartesian3D zero;
-
-    /** Tolerance below which points are considered identical. */
-    private final double tolerance;
-
-    /** Build a line from two points.
-     * @param p1 first point belonging to the line (this can be any point)
-     * @param p2 second point belonging to the line (this can be any point, different from p1)
-     * @param tolerance tolerance below which points are considered identical
-     * @exception MathIllegalArgumentException if the points are equal
-     * @since 3.3
-     */
-    public Line(final Cartesian3D p1, final Cartesian3D p2, final double tolerance)
-        throws MathIllegalArgumentException {
-        reset(p1, p2);
-        this.tolerance = tolerance;
-    }
-
-    /** Copy constructor.
-     * <p>The created instance is completely independent from the
-     * original instance, it is a deep copy.</p>
-     * @param line line to copy
-     */
-    public Line(final Line line) {
-        this.direction = line.direction;
-        this.zero      = line.zero;
-        this.tolerance = line.tolerance;
-    }
-
-    /** Reset the instance as if built from two points.
-     * @param p1 first point belonging to the line (this can be any point)
-     * @param p2 second point belonging to the line (this can be any point, different from p1)
-     * @exception MathIllegalArgumentException if the points are equal
-     */
-    public void reset(final Cartesian3D p1, final Cartesian3D p2) throws MathIllegalArgumentException {
-        final Cartesian3D delta = p2.subtract(p1);
-        final double norm2 = delta.getNormSq();
-        if (norm2 == 0.0) {
-            throw new MathIllegalArgumentException(LocalizedFormats.ZERO_NORM);
-        }
-        this.direction = new Cartesian3D(1.0 / FastMath.sqrt(norm2), delta);
-        zero = new Cartesian3D(1.0, p1, -p1.dotProduct(delta) / norm2, delta);
-    }
-
-    /** Get the tolerance below which points are considered identical.
-     * @return tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public double getTolerance() {
-        return tolerance;
-    }
-
-    /** Get a line with reversed direction.
-     * @return a new instance, with reversed direction
-     */
-    public Line revert() {
-        final Line reverted = new Line(this);
-        reverted.direction = reverted.direction.negate();
-        return reverted;
-    }
-
-    /** Get the normalized direction vector.
-     * @return normalized direction vector
-     */
-    public Cartesian3D getDirection() {
-        return direction;
-    }
-
-    /** Get the line point closest to the origin.
-     * @return line point closest to the origin
-     */
-    public Cartesian3D getOrigin() {
-        return zero;
-    }
-
-    /** Get the abscissa of a point with respect to the line.
-     * <p>The abscissa is 0 if the projection of the point and the
-     * projection of the frame origin on the line are the same
-     * point.</p>
-     * @param point point to check
-     * @return abscissa of the point
-     */
-    public double getAbscissa(final Cartesian3D point) {
-        return point.subtract(zero).dotProduct(direction);
-    }
-
-    /** Get one point from the line.
-     * @param abscissa desired abscissa for the point
-     * @return one point belonging to the line, at specified abscissa
-     */
-    public Cartesian3D pointAt(final double abscissa) {
-        return new Cartesian3D(1.0, zero, abscissa, direction);
-    }
-
-    /** Transform a space point into a sub-space point.
-     * @param vector n-dimension point of the space
-     * @return (n-1)-dimension point of the sub-space corresponding to
-     * the specified space point
-     */
-    public Cartesian1D toSubSpace(Vector<Euclidean3D> vector) {
-        return toSubSpace((Point<Euclidean3D>) vector);
-    }
-
-    /** Transform a sub-space point into a space point.
-     * @param vector (n-1)-dimension point of the sub-space
-     * @return n-dimension point of the space corresponding to the
-     * specified sub-space point
-     */
-    public Cartesian3D toSpace(Vector<Euclidean1D> vector) {
-        return toSpace((Point<Euclidean1D>) vector);
-    }
-
-    /** {@inheritDoc}
-     * @see #getAbscissa(Cartesian3D)
-     */
-    @Override
-    public Cartesian1D toSubSpace(final Point<Euclidean3D> point) {
-        return toSubSpace((Cartesian3D) point);
-    }
-
-    /** {@inheritDoc}
-     * @see #pointAt(double)
-     */
-    @Override
-    public Cartesian3D toSpace(final Point<Euclidean1D> point) {
-        return toSpace((Cartesian1D) point);
-    }
-
-    /** Transform a space point into a sub-space point.
-     * @param point n-dimension point of the space
-     * @return (n-1)-dimension point of the sub-space corresponding to
-     * the specified space point
-     */
-    public Cartesian1D toSubSpace(final Cartesian3D point) {
-        return new Cartesian1D(getAbscissa(point));
-    }
-
-    /** Transform a sub-space point into a space point.
-     * @param point (n-1)-dimension point of the sub-space
-     * @return n-dimension point of the space corresponding to the
-     * specified sub-space point
-     */
-    public Cartesian3D toSpace(final Cartesian1D point) {
-        return pointAt(point.getX());
-    }
-
-    /** Check if the instance is similar to another line.
-     * <p>Lines are considered similar if they contain the same
-     * points. This does not mean they are equal since they can have
-     * opposite directions.</p>
-     * @param line line to which instance should be compared
-     * @return true if the lines are similar
-     */
-    public boolean isSimilarTo(final Line line) {
-        final double angle = Cartesian3D.angle(direction, line.direction);
-        return ((angle < tolerance) || (angle > (FastMath.PI - tolerance))) && contains(line.zero);
-    }
-
-    /** Check if the instance contains a point.
-     * @param p point to check
-     * @return true if p belongs to the line
-     */
-    public boolean contains(final Cartesian3D p) {
-        return distance(p) < tolerance;
-    }
-
-    /** Compute the distance between the instance and a point.
-     * @param p to check
-     * @return distance between the instance and the point
-     */
-    public double distance(final Cartesian3D p) {
-        final Cartesian3D d = p.subtract(zero);
-        final Cartesian3D n = new Cartesian3D(1.0, d, -d.dotProduct(direction), direction);
-        return n.getNorm();
-    }
-
-    /** Compute the shortest distance between the instance and another line.
-     * @param line line to check against the instance
-     * @return shortest distance between the instance and the line
-     */
-    public double distance(final Line line) {
-
-        final Cartesian3D normal = Cartesian3D.crossProduct(direction, line.direction);
-        final double n = normal.getNorm();
-        if (n < Precision.SAFE_MIN) {
-            // lines are parallel
-            return distance(line.zero);
-        }
-
-        // signed separation of the two parallel planes that contains the lines
-        final double offset = line.zero.subtract(zero).dotProduct(normal) / n;
-
-        return FastMath.abs(offset);
-
-    }
-
-    /** Compute the point of the instance closest to another line.
-     * @param line line to check against the instance
-     * @return point of the instance closest to another line
-     */
-    public Cartesian3D closestPoint(final Line line) {
-
-        final double cos = direction.dotProduct(line.direction);
-        final double n = 1 - cos * cos;
-        if (n < Precision.EPSILON) {
-            // the lines are parallel
-            return zero;
-        }
-
-        final Cartesian3D delta0 = line.zero.subtract(zero);
-        final double a        = delta0.dotProduct(direction);
-        final double b        = delta0.dotProduct(line.direction);
-
-        return new Cartesian3D(1, zero, (a - b * cos) / n, direction);
-
-    }
-
-    /** Get the intersection point of the instance and another line.
-     * @param line other line
-     * @return intersection point of the instance and the other line
-     * or null if there are no intersection points
-     */
-    public Cartesian3D intersection(final Line line) {
-        final Cartesian3D closest = closestPoint(line);
-        return line.contains(closest) ? closest : null;
-    }
-
-    /** Build a sub-line covering the whole line.
-     * @return a sub-line covering the whole line
-     */
-    public SubLine wholeLine() {
-        return new SubLine(this, new IntervalsSet(tolerance));
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/OutlineExtractor.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/OutlineExtractor.java
deleted file mode 100644
index 71657e2..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/OutlineExtractor.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * 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.util.ArrayList;
-
-import org.apache.commons.math4.geometry.Point;
-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.Cartesian2D;
-import org.apache.commons.math4.geometry.partitioning.AbstractSubHyperplane;
-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.RegionFactory;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-import org.apache.commons.math4.util.FastMath;
-
-/** Extractor for {@link PolygonsSet polyhedrons sets} outlines.
- * <p>This class extracts the 2D outlines from {{@link PolygonsSet
- * polyhedrons sets} in a specified projection plane.</p>
- * @since 3.0
- */
-public class OutlineExtractor {
-
-    /** Abscissa axis of the projection plane. */
-    private final Cartesian3D u;
-
-    /** Ordinate axis of the projection plane. */
-    private final Cartesian3D v;
-
-    /** Normal of the projection plane (viewing direction). */
-    private final Cartesian3D w;
-
-    /** Build an extractor for a specific projection plane.
-     * @param u abscissa axis of the projection point
-     * @param v ordinate axis of the projection point
-     */
-    public OutlineExtractor(final Cartesian3D u, final Cartesian3D v) {
-        this.u = u;
-        this.v = v;
-        w = Cartesian3D.crossProduct(u, v);
-    }
-
-    /** Extract the outline of a polyhedrons set.
-     * @param polyhedronsSet polyhedrons set whose outline must be extracted
-     * @return an outline, as an array of loops.
-     */
-    public Cartesian2D[][] getOutline(final PolyhedronsSet polyhedronsSet) {
-
-        // project all boundary facets into one polygons set
-        final BoundaryProjector projector = new BoundaryProjector(polyhedronsSet.getTolerance());
-        polyhedronsSet.getTree(true).visit(projector);
-        final PolygonsSet projected = projector.getProjected();
-
-        // Remove the spurious intermediate vertices from the outline
-        final Cartesian2D[][] outline = projected.getVertices();
-        for (int i = 0; i < outline.length; ++i) {
-            final Cartesian2D[] rawLoop = outline[i];
-            int end = rawLoop.length;
-            int j = 0;
-            while (j < end) {
-                if (pointIsBetween(rawLoop, end, j)) {
-                    // the point should be removed
-                    for (int k = j; k < (end - 1); ++k) {
-                        rawLoop[k] = rawLoop[k + 1];
-                    }
-                    --end;
-                } else {
-                    // the point remains in the loop
-                    ++j;
-                }
-            }
-            if (end != rawLoop.length) {
-                // resize the array
-                outline[i] = new Cartesian2D[end];
-                System.arraycopy(rawLoop, 0, outline[i], 0, end);
-            }
-        }
-
-        return outline;
-
-    }
-
-    /** Check if a point is geometrically between its neighbor in an array.
-     * <p>The neighbors are computed considering the array is a loop
-     * (i.e. point at index (n-1) is before point at index 0)</p>
-     * @param loop points array
-     * @param n number of points to consider in the array
-     * @param i index of the point to check (must be between 0 and n-1)
-     * @return true if the point is exactly between its neighbors
-     */
-    private boolean pointIsBetween(final Cartesian2D[] loop, final int n, final int i) {
-        final Cartesian2D previous = loop[(i + n - 1) % n];
-        final Cartesian2D current  = loop[i];
-        final Cartesian2D next     = loop[(i + 1) % n];
-        final double dx1       = current.getX() - previous.getX();
-        final double dy1       = current.getY() - previous.getY();
-        final double dx2       = next.getX()    - current.getX();
-        final double dy2       = next.getY()    - current.getY();
-        final double cross     = dx1 * dy2 - dx2 * dy1;
-        final double dot       = dx1 * dx2 + dy1 * dy2;
-        final double d1d2      = FastMath.sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2));
-        return (FastMath.abs(cross) <= (1.0e-6 * d1d2)) && (dot >= 0.0);
-    }
-
-    /** Visitor projecting the boundary facets on a plane. */
-    private class BoundaryProjector implements BSPTreeVisitor<Euclidean3D> {
-
-        /** Projection of the polyhedrons set on the plane. */
-        private PolygonsSet projected;
-
-        /** Tolerance below which points are considered identical. */
-        private final double tolerance;
-
-        /** Simple constructor.
-         * @param tolerance tolerance below which points are considered identical
-         */
-        BoundaryProjector(final double tolerance) {
-            this.projected = new PolygonsSet(new BSPTree<Euclidean2D>(Boolean.FALSE), tolerance);
-            this.tolerance = tolerance;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Order visitOrder(final BSPTree<Euclidean3D> node) {
-            return Order.MINUS_SUB_PLUS;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void visitInternalNode(final BSPTree<Euclidean3D> node) {
-            @SuppressWarnings("unchecked")
-            final BoundaryAttribute<Euclidean3D> attribute =
-                (BoundaryAttribute<Euclidean3D>) node.getAttribute();
-            if (attribute.getPlusOutside() != null) {
-                addContribution(attribute.getPlusOutside(), false);
-            }
-            if (attribute.getPlusInside() != null) {
-                addContribution(attribute.getPlusInside(), true);
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void visitLeafNode(final BSPTree<Euclidean3D> node) {
-        }
-
-        /** Add he contribution of a boundary facet.
-         * @param facet boundary facet
-         * @param reversed if true, the facet has the inside on its plus side
-         */
-        private void addContribution(final SubHyperplane<Euclidean3D> facet, final boolean reversed) {
-
-            // extract the vertices of the facet
-            @SuppressWarnings("unchecked")
-            final AbstractSubHyperplane<Euclidean3D, Euclidean2D> absFacet =
-                (AbstractSubHyperplane<Euclidean3D, Euclidean2D>) facet;
-            final Plane plane    = (Plane) facet.getHyperplane();
-
-            final double scal = plane.getNormal().dotProduct(w);
-            if (FastMath.abs(scal) > 1.0e-3) {
-                Cartesian2D[][] vertices =
-                    ((PolygonsSet) absFacet.getRemainingRegion()).getVertices();
-
-                if ((scal < 0) ^ reversed) {
-                    // the facet is seen from the inside,
-                    // we need to invert its boundary orientation
-                    final Cartesian2D[][] newVertices = new Cartesian2D[vertices.length][];
-                    for (int i = 0; i < vertices.length; ++i) {
-                        final Cartesian2D[] loop = vertices[i];
-                        final Cartesian2D[] newLoop = new Cartesian2D[loop.length];
-                        if (loop[0] == null) {
-                            newLoop[0] = null;
-                            for (int j = 1; j < loop.length; ++j) {
-                                newLoop[j] = loop[loop.length - j];
-                            }
-                        } else {
-                            for (int j = 0; j < loop.length; ++j) {
-                                newLoop[j] = loop[loop.length - (j + 1)];
-                            }
-                        }
-                        newVertices[i] = newLoop;
-                    }
-
-                    // use the reverted vertices
-                    vertices = newVertices;
-
-                }
-
-                // compute the projection of the facet in the outline plane
-                final ArrayList<SubHyperplane<Euclidean2D>> edges = new ArrayList<>();
-                for (Cartesian2D[] loop : vertices) {
-                    final boolean closed = loop[0] != null;
-                    int previous         = closed ? (loop.length - 1) : 1;
-                    Cartesian3D previous3D  = plane.toSpace(loop[previous]);
-                    int current          = (previous + 1) % loop.length;
-                    Cartesian2D pPoint       = new Cartesian2D(previous3D.dotProduct(u),
-                                                         previous3D.dotProduct(v));
-                    while (current < loop.length) {
-
-                        final Cartesian3D current3D = plane.toSpace((Point<Euclidean2D>) loop[current]);
-                        final Cartesian2D  cPoint    = new Cartesian2D(current3D.dotProduct(u),
-                                                                 current3D.dotProduct(v));
-                        final org.apache.commons.math4.geometry.euclidean.twod.Line line =
-                            new org.apache.commons.math4.geometry.euclidean.twod.Line(pPoint, cPoint, tolerance);
-                        SubHyperplane<Euclidean2D> edge = line.wholeHyperplane();
-
-                        if (closed || (previous != 1)) {
-                            // the previous point is a real vertex
-                            // it defines one bounding point of the edge
-                            final double angle = line.getAngle() + 0.5 * FastMath.PI;
-                            final org.apache.commons.math4.geometry.euclidean.twod.Line l =
-                                new org.apache.commons.math4.geometry.euclidean.twod.Line(pPoint, angle, tolerance);
-                            edge = edge.split(l).getPlus();
-                        }
-
-                        if (closed || (current != (loop.length - 1))) {
-                            // the current point is a real vertex
-                            // it defines one bounding point of the edge
-                            final double angle = line.getAngle() + 0.5 * FastMath.PI;
-                            final org.apache.commons.math4.geometry.euclidean.twod.Line l =
-                                new org.apache.commons.math4.geometry.euclidean.twod.Line(cPoint, angle, tolerance);
-                            edge = edge.split(l).getMinus();
-                        }
-
-                        edges.add(edge);
-
-                        previous   = current++;
-                        previous3D = current3D;
-                        pPoint     = cPoint;
-
-                    }
-                }
-                final PolygonsSet projectedFacet = new PolygonsSet(edges, tolerance);
-
-                // add the contribution of the facet to the global outline
-                projected = (PolygonsSet) new RegionFactory<Euclidean2D>().union(projected, projectedFacet);
-
-            }
-        }
-
-        /** Get the projection of the polyhedrons set on the plane.
-         * @return projection of the polyhedrons set on the plane
-         */
-        public PolygonsSet getProjected() {
-            return projected;
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Plane.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Plane.java
deleted file mode 100644
index 7bcc4e3..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Plane.java
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * 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 org.apache.commons.math4.exception.MathArithmeticException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Vector;
-import org.apache.commons.math4.geometry.euclidean.oned.Cartesian1D;
-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.Cartesian2D;
-import org.apache.commons.math4.geometry.partitioning.Embedding;
-import org.apache.commons.math4.geometry.partitioning.Hyperplane;
-import org.apache.commons.math4.util.FastMath;
-
-/** The class represent planes in a three dimensional space.
- * @since 3.0
- */
-public class Plane implements Hyperplane<Euclidean3D>, Embedding<Euclidean3D, Euclidean2D> {
-
-    /** Offset of the origin with respect to the plane. */
-    private double originOffset;
-
-    /** Origin of the plane frame. */
-    private Cartesian3D origin;
-
-    /** First vector of the plane frame (in plane). */
-    private Cartesian3D u;
-
-    /** Second vector of the plane frame (in plane). */
-    private Cartesian3D v;
-
-    /** Third vector of the plane frame (plane normal). */
-    private Cartesian3D w;
-
-    /** Tolerance below which points are considered identical. */
-    private final double tolerance;
-
-    /** Build a plane normal to a given direction and containing the origin.
-     * @param normal normal direction to the plane
-     * @param tolerance tolerance below which points are considered identical
-     * @exception MathArithmeticException if the normal norm is too small
-     * @since 3.3
-     */
-    public Plane(final Cartesian3D normal, final double tolerance)
-        throws MathArithmeticException {
-        setNormal(normal);
-        this.tolerance = tolerance;
-        originOffset = 0;
-        setFrame();
-    }
-
-    /** Build a plane from a point and a normal.
-     * @param p point belonging to the plane
-     * @param normal normal direction to the plane
-     * @param tolerance tolerance below which points are considered identical
-     * @exception MathArithmeticException if the normal norm is too small
-     * @since 3.3
-     */
-    public Plane(final Cartesian3D p, final Cartesian3D normal, final double tolerance)
-        throws MathArithmeticException {
-        setNormal(normal);
-        this.tolerance = tolerance;
-        originOffset = -p.dotProduct(w);
-        setFrame();
-    }
-
-    /** Build a plane from three points.
-     * <p>The plane is oriented in the direction of
-     * {@code (p2-p1) ^ (p3-p1)}</p>
-     * @param p1 first point belonging to the plane
-     * @param p2 second point belonging to the plane
-     * @param p3 third point belonging to the plane
-     * @param tolerance tolerance below which points are considered identical
-     * @exception MathArithmeticException if the points do not constitute a plane
-     * @since 3.3
-     */
-    public Plane(final Cartesian3D p1, final Cartesian3D p2, final Cartesian3D p3, final double tolerance)
-        throws MathArithmeticException {
-        this(p1, p2.subtract(p1).crossProduct(p3.subtract(p1)), tolerance);
-    }
-
-    /** Copy constructor.
-     * <p>The instance created is completely independent of the original
-     * one. A deep copy is used, none of the underlying object are
-     * shared.</p>
-     * @param plane plane to copy
-     */
-    public Plane(final Plane plane) {
-        originOffset = plane.originOffset;
-        origin       = plane.origin;
-        u            = plane.u;
-        v            = plane.v;
-        w            = plane.w;
-        tolerance    = plane.tolerance;
-    }
-
-    /** Copy the instance.
-     * <p>The instance created is completely independant of the original
-     * one. A deep copy is used, none of the underlying objects are
-     * shared (except for immutable objects).</p>
-     * @return a new hyperplane, copy of the instance
-     */
-    @Override
-    public Plane copySelf() {
-        return new Plane(this);
-    }
-
-    /** Reset the instance as if built from a point and a normal.
-     * @param p point belonging to the plane
-     * @param normal normal direction to the plane
-     * @exception MathArithmeticException if the normal norm is too small
-     */
-    public void reset(final Cartesian3D p, final Cartesian3D normal) throws MathArithmeticException {
-        setNormal(normal);
-        originOffset = -p.dotProduct(w);
-        setFrame();
-    }
-
-    /** Reset the instance from another one.
-     * <p>The updated instance is completely independant of the original
-     * one. A deep reset is used none of the underlying object is
-     * shared.</p>
-     * @param original plane to reset from
-     */
-    public void reset(final Plane original) {
-        originOffset = original.originOffset;
-        origin       = original.origin;
-        u            = original.u;
-        v            = original.v;
-        w            = original.w;
-    }
-
-    /** Set the normal vactor.
-     * @param normal normal direction to the plane (will be copied)
-     * @exception MathArithmeticException if the normal norm is too small
-     */
-    private void setNormal(final Cartesian3D normal) throws MathArithmeticException {
-        final double norm = normal.getNorm();
-        if (norm < 1.0e-10) {
-            throw new MathArithmeticException(LocalizedFormats.ZERO_NORM);
-        }
-        w = new Cartesian3D(1.0 / norm, normal);
-    }
-
-    /** Reset the plane frame.
-     */
-    private void setFrame() {
-        origin = new Cartesian3D(-originOffset, w);
-        u = w.orthogonal();
-        v = Cartesian3D.crossProduct(w, u);
-    }
-
-    /** Get the origin point of the plane frame.
-     * <p>The point returned is the orthogonal projection of the
-     * 3D-space origin in the plane.</p>
-     * @return the origin point of the plane frame (point closest to the
-     * 3D-space origin)
-     */
-    public Cartesian3D getOrigin() {
-        return origin;
-    }
-
-    /** Get the normalized normal vector.
-     * <p>The frame defined by ({@link #getU getU}, {@link #getV getV},
-     * {@link #getNormal getNormal}) is a rigth-handed orthonormalized
-     * frame).</p>
-     * @return normalized normal vector
-     * @see #getU
-     * @see #getV
-     */
-    public Cartesian3D getNormal() {
-        return w;
-    }
-
-    /** Get the plane first canonical vector.
-     * <p>The frame defined by ({@link #getU getU}, {@link #getV getV},
-     * {@link #getNormal getNormal}) is a rigth-handed orthonormalized
-     * frame).</p>
-     * @return normalized first canonical vector
-     * @see #getV
-     * @see #getNormal
-     */
-    public Cartesian3D getU() {
-        return u;
-    }
-
-    /** Get the plane second canonical vector.
-     * <p>The frame defined by ({@link #getU getU}, {@link #getV getV},
-     * {@link #getNormal getNormal}) is a rigth-handed orthonormalized
-     * frame).</p>
-     * @return normalized second canonical vector
-     * @see #getU
-     * @see #getNormal
-     */
-    public Cartesian3D getV() {
-        return v;
-    }
-
-    /** {@inheritDoc}
-     * @since 3.3
-     */
-    @Override
-    public Point<Euclidean3D> project(Point<Euclidean3D> point) {
-        return toSpace(toSubSpace(point));
-    }
-
-    /** {@inheritDoc}
-     * @since 3.3
-     */
-    @Override
-    public double getTolerance() {
-        return tolerance;
-    }
-
-    /** Revert the plane.
-     * <p>Replace the instance by a similar plane with opposite orientation.</p>
-     * <p>The new plane frame is chosen in such a way that a 3D point that had
-     * {@code (x, y)} in-plane coordinates and {@code z} offset with
-     * respect to the plane and is unaffected by the change will have
-     * {@code (y, x)} in-plane coordinates and {@code -z} offset with
-     * respect to the new plane. This means that the {@code u} and {@code v}
-     * vectors returned by the {@link #getU} and {@link #getV} methods are exchanged,
-     * and the {@code w} vector returned by the {@link #getNormal} method is
-     * reversed.</p>
-     */
-    public void revertSelf() {
-        final Cartesian3D tmp = u;
-        u = v;
-        v = tmp;
-        w = w.negate();
-        originOffset = -originOffset;
-    }
-
-    /** Transform a space vector into a sub-space vector.
-     * @param vector n-dimension vector of the space
-     * @return (n-1)-dimension vector of the sub-space corresponding to
-     * the specified space vector
-     */
-    public Cartesian2D toSubSpace(Vector<Euclidean3D> vector) {
-        return toSubSpace((Cartesian3D) vector);
-    }
-
-    /** Transform a sub-space point into a space point.
-     * @param vector (n-1)-dimension point of the sub-space
-     * @return n-dimension point of the space corresponding to the
-     * specified sub-space point
-     */
-    public Cartesian3D toSpace(Vector<Euclidean2D> vector) {
-        return toSpace((Cartesian2D) vector);
-    }
-
-    /** Transform a 3D space point into an in-plane point.
-     * @param point point of the space (must be a {@link Cartesian3D} instance)
-     * @return in-plane point
-     * @see #toSpace
-     */
-    @Override
-    public Cartesian2D toSubSpace(final Point<Euclidean3D> point) {
-        return toSubSpace((Cartesian3D) point);
-    }
-
-    /** Transform an in-plane point into a 3D space point.
-     * @param point in-plane point (must be a {@link Cartesian2D} instance)
-     * @return 3D space point
-     * @see #toSubSpace
-     */
-    @Override
-    public Cartesian3D toSpace(final Point<Euclidean2D> point) {
-        return toSpace((Cartesian2D) point);
-    }
-
-    /** Transform a 3D space point into an in-plane point.
-     * @param point point of the space
-     * @return in-plane point
-     * @see #toSpace
-     */
-    public Cartesian2D toSubSpace(final Cartesian3D point) {
-        return new Cartesian2D(point.dotProduct(u), point.dotProduct(v));
-    }
-
-    /** Transform an in-plane point into a 3D space point.
-     * @param point in-plane point
-     * @return 3D space point
-     * @see #toSubSpace
-     */
-    public Cartesian3D toSpace(final Cartesian2D point) {
-        return new Cartesian3D(point.getX(), u, point.getY(), v, -originOffset, w);
-    }
-
-    /** Get one point from the 3D-space.
-     * @param inPlane desired in-plane coordinates for the point in the
-     * plane
-     * @param offset desired offset for the point
-     * @return one point in the 3D-space, with given coordinates and offset
-     * relative to the plane
-     */
-    public Cartesian3D getPointAt(final Cartesian2D inPlane, final double offset) {
-        return new Cartesian3D(inPlane.getX(), u, inPlane.getY(), v, offset - originOffset, w);
-    }
-
-    /** Check if the instance is similar to another plane.
-     * <p>Planes are considered similar if they contain the same
-     * points. This does not mean they are equal since they can have
-     * opposite normals.</p>
-     * @param plane plane to which the instance is compared
-     * @return true if the planes are similar
-     */
-    public boolean isSimilarTo(final Plane plane) {
-        final double angle = Cartesian3D.angle(w, plane.w);
-        return ((angle < 1.0e-10) && (FastMath.abs(originOffset - plane.originOffset) < tolerance)) ||
-               ((angle > (FastMath.PI - 1.0e-10)) && (FastMath.abs(originOffset + plane.originOffset) < tolerance));
-    }
-
-    /** Rotate the plane around the specified point.
-     * <p>The instance is not modified, a new instance is created.</p>
-     * @param center rotation center
-     * @param rotation vectorial rotation operator
-     * @return a new plane
-     */
-    public Plane rotate(final Cartesian3D center, final Rotation rotation) {
-
-        final Cartesian3D delta = origin.subtract(center);
-        final Plane plane = new Plane(center.add(rotation.applyTo(delta)),
-                                      rotation.applyTo(w), tolerance);
-
-        // make sure the frame is transformed as desired
-        plane.u = rotation.applyTo(u);
-        plane.v = rotation.applyTo(v);
-
-        return plane;
-
-    }
-
-    /** Translate the plane by the specified amount.
-     * <p>The instance is not modified, a new instance is created.</p>
-     * @param translation translation to apply
-     * @return a new plane
-     */
-    public Plane translate(final Cartesian3D translation) {
-
-        final Plane plane = new Plane(origin.add(translation), w, tolerance);
-
-        // make sure the frame is transformed as desired
-        plane.u = u;
-        plane.v = v;
-
-        return plane;
-
-    }
-
-    /** Get the intersection of a line with the instance.
-     * @param line line intersecting the instance
-     * @return intersection point between between the line and the
-     * instance (null if the line is parallel to the instance)
-     */
-    public Cartesian3D intersection(final Line line) {
-        final Cartesian3D direction = line.getDirection();
-        final double   dot       = w.dotProduct(direction);
-        if (FastMath.abs(dot) < 1.0e-10) {
-            return null;
-        }
-        final Cartesian3D point = line.toSpace(Cartesian1D.ZERO);
-        final double   k     = -(originOffset + w.dotProduct(point)) / dot;
-        return new Cartesian3D(1.0, point, k, direction);
-    }
-
-    /** Build the line shared by the instance and another plane.
-     * @param other other plane
-     * @return line at the intersection of the instance and the
-     * other plane (really a {@link Line Line} instance)
-     */
-    public Line intersection(final Plane other) {
-        final Cartesian3D direction = Cartesian3D.crossProduct(w, other.w);
-        if (direction.getNorm() < tolerance) {
-            return null;
-        }
-        final Cartesian3D point = intersection(this, other, new Plane(direction, tolerance));
-        return new Line(point, point.add(direction), tolerance);
-    }
-
-    /** Get the intersection point of three planes.
-     * @param plane1 first plane1
-     * @param plane2 second plane2
-     * @param plane3 third plane2
-     * @return intersection point of three planes, null if some planes are parallel
-     */
-    public static Cartesian3D intersection(final Plane plane1, final Plane plane2, final Plane plane3) {
-
-        // coefficients of the three planes linear equations
-        final double a1 = plane1.w.getX();
-        final double b1 = plane1.w.getY();
-        final double c1 = plane1.w.getZ();
-        final double d1 = plane1.originOffset;
-
-        final double a2 = plane2.w.getX();
-        final double b2 = plane2.w.getY();
-        final double c2 = plane2.w.getZ();
-        final double d2 = plane2.originOffset;
-
-        final double a3 = plane3.w.getX();
-        final double b3 = plane3.w.getY();
-        final double c3 = plane3.w.getZ();
-        final double d3 = plane3.originOffset;
-
-        // direct Cramer resolution of the linear system
-        // (this is still feasible for a 3x3 system)
-        final double a23         = b2 * c3 - b3 * c2;
-        final double b23         = c2 * a3 - c3 * a2;
-        final double c23         = a2 * b3 - a3 * b2;
-        final double determinant = a1 * a23 + b1 * b23 + c1 * c23;
-        if (FastMath.abs(determinant) < 1.0e-10) {
-            return null;
-        }
-
-        final double r = 1.0 / determinant;
-        return new Cartesian3D(
-                            (-a23 * d1 - (c1 * b3 - c3 * b1) * d2 - (c2 * b1 - c1 * b2) * d3) * r,
-                            (-b23 * d1 - (c3 * a1 - c1 * a3) * d2 - (c1 * a2 - c2 * a1) * d3) * r,
-                            (-c23 * d1 - (b1 * a3 - b3 * a1) * d2 - (b2 * a1 - b1 * a2) * d3) * r);
-
-    }
-
-    /** Build a region covering the whole hyperplane.
-     * @return a region covering the whole hyperplane
-     */
-    @Override
-    public SubPlane wholeHyperplane() {
-        return new SubPlane(this, new PolygonsSet(tolerance));
-    }
-
-    /** Build a region covering the whole space.
-     * @return a region containing the instance (really a {@link
-     * PolyhedronsSet PolyhedronsSet} instance)
-     */
-    @Override
-    public PolyhedronsSet wholeSpace() {
-        return new PolyhedronsSet(tolerance);
-    }
-
-    /** Check if the instance contains a point.
-     * @param p point to check
-     * @return true if p belongs to the plane
-     */
-    public boolean contains(final Cartesian3D p) {
-        return FastMath.abs(getOffset(p)) < tolerance;
-    }
-
-    /** Get the offset (oriented distance) of a parallel plane.
-     * <p>This method should be called only for parallel planes otherwise
-     * the result is not meaningful.</p>
-     * <p>The offset is 0 if both planes are the same, it is
-     * positive if the plane is on the plus side of the instance and
-     * negative if it is on the minus side, according to its natural
-     * orientation.</p>
-     * @param plane plane to check
-     * @return offset of the plane
-     */
-    public double getOffset(final Plane plane) {
-        return originOffset + (sameOrientationAs(plane) ? -plane.originOffset : plane.originOffset);
-    }
-
-    /** Get the offset (oriented distance) of a vector.
-     * @param vector vector to check
-     * @return offset of the vector
-     */
-//    public double getOffset(Vector<Euclidean3D> vector) {
-//        return getOffset((Point<Euclidean3D>) vector);
-//    }
-
-    /** Get the offset (oriented distance) of a point.
-     * <p>The offset is 0 if the point is on the underlying hyperplane,
-     * it is positive if the point is on one particular side of the
-     * hyperplane, and it is negative if the point is on the other side,
-     * according to the hyperplane natural orientation.</p>
-     * @param point point to check
-     * @return offset of the point
-     */
-    @Override
-    public double getOffset(final Point<Euclidean3D> point) {
-        return ((Cartesian3D) point).dotProduct(w) + originOffset;
-    }
-
-    /** Check if the instance has the same orientation as another hyperplane.
-     * @param other other hyperplane to check against the instance
-     * @return true if the instance and the other hyperplane have
-     * the same orientation
-     */
-    @Override
-    public boolean sameOrientationAs(final Hyperplane<Euclidean3D> other) {
-        return (((Plane) other).w).dotProduct(w) > 0.0;
-    }
-
-}
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
deleted file mode 100644
index cfd9f7c..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSet.java
+++ /dev/null
@@ -1,725 +0,0 @@
-/*
- * 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.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.exception.NumberIsTooSmallException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.euclidean.oned.Euclidean1D;
-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.AbstractRegion;
-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.Hyperplane;
-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.geometry.partitioning.Transform;
-import org.apache.commons.math4.util.FastMath;
-
-/** This class represents a 3D region: a set of polyhedrons.
- * @since 3.0
- */
-public class PolyhedronsSet extends AbstractRegion<Euclidean3D, Euclidean2D> {
-
-    /** Build a polyhedrons set representing the whole real line.
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public PolyhedronsSet(final double tolerance) {
-        super(tolerance);
-    }
-
-    /** Build a polyhedrons set from a BSP tree.
-     * <p>The leaf nodes of the BSP tree <em>must</em> have a
-     * {@code Boolean} attribute representing the inside status of
-     * the corresponding cell (true for inside cells, false for outside
-     * cells). In order to avoid building too many small objects, it is
-     * recommended to use the predefined constants
-     * {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
-     * <p>
-     * This constructor is aimed at expert use, as building the tree may
-     * be a difficult task. It is not intended for general use and for
-     * performances reasons does not check thoroughly its input, as this would
-     * require walking the full tree each time. Failing to provide a tree with
-     * the proper attributes, <em>will</em> therefore generate problems like
-     * {@link NullPointerException} or {@link ClassCastException} only later on.
-     * This limitation is known and explains why this constructor is for expert
-     * use only. The caller does have the responsibility to provided correct arguments.
-     * </p>
-     * @param tree inside/outside BSP tree representing the region
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public PolyhedronsSet(final BSPTree<Euclidean3D> tree, final double tolerance) {
-        super(tree, tolerance);
-    }
-
-    /** Build a polyhedrons set from a Boundary REPresentation (B-rep) specified by sub-hyperplanes.
-     * <p>The boundary is provided as a collection of {@link
-     * SubHyperplane sub-hyperplanes}. Each sub-hyperplane has the
-     * interior part of the region on its minus side and the exterior on
-     * its plus side.</p>
-     * <p>The boundary elements can be in any order, and can form
-     * several non-connected sets (like for example polyhedrons with holes
-     * or a set of disjoint polyhedrons considered as a whole). In
-     * fact, the elements do not even need to be connected together
-     * (their topological connections are not used here). However, if the
-     * boundary does not really separate an inside open from an outside
-     * open (open having here its topological meaning), then subsequent
-     * calls to the {@link Region#checkPoint(Point) checkPoint} method will
-     * not be meaningful anymore.</p>
-     * <p>If the boundary is empty, the region will represent the whole
-     * space.</p>
-     * @param boundary collection of boundary elements, as a
-     * collection of {@link SubHyperplane SubHyperplane} objects
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public PolyhedronsSet(final Collection<SubHyperplane<Euclidean3D>> boundary,
-                          final double tolerance) {
-        super(boundary, tolerance);
-    }
-
-    /** Build a polyhedrons set from a Boundary REPresentation (B-rep) specified by connected vertices.
-     * <p>
-     * The boundary is provided as a list of vertices and a list of facets.
-     * Each facet is specified as an integer array containing the arrays vertices
-     * indices in the vertices list. Each facet normal is oriented by right hand
-     * rule to the facet vertices list.
-     * </p>
-     * <p>
-     * Some basic sanity checks are performed but not everything is thoroughly
-     * assessed, so it remains under caller responsibility to ensure the vertices
-     * and facets are consistent and properly define a polyhedrons set.
-     * </p>
-     * @param vertices list of polyhedrons set vertices
-     * @param facets list of facets, as vertices indices in the vertices list
-     * @param tolerance tolerance below which points are considered identical
-     * @exception MathIllegalArgumentException if some basic sanity checks fail
-     * @since 3.5
-     */
-    public PolyhedronsSet(final List<Cartesian3D> vertices, final List<int[]> facets,
-                          final double tolerance) {
-        super(buildBoundary(vertices, facets, tolerance), tolerance);
-    }
-
-    /** Build a parallellepipedic box.
-     * @param xMin low bound along the x direction
-     * @param xMax high bound along the x direction
-     * @param yMin low bound along the y direction
-     * @param yMax high bound along the y direction
-     * @param zMin low bound along the z direction
-     * @param zMax high bound along the z direction
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public PolyhedronsSet(final double xMin, final double xMax,
-                          final double yMin, final double yMax,
-                          final double zMin, final double zMax,
-                          final double tolerance) {
-        super(buildBoundary(xMin, xMax, yMin, yMax, zMin, zMax, tolerance), tolerance);
-    }
-
-    /** Build a parallellepipedic box boundary.
-     * @param xMin low bound along the x direction
-     * @param xMax high bound along the x direction
-     * @param yMin low bound along the y direction
-     * @param yMax high bound along the y direction
-     * @param zMin low bound along the z direction
-     * @param zMax high bound along the z direction
-     * @param tolerance tolerance below which points are considered identical
-     * @return boundary tree
-     * @since 3.3
-     */
-    private static BSPTree<Euclidean3D> buildBoundary(final double xMin, final double xMax,
-                                                      final double yMin, final double yMax,
-                                                      final double zMin, final double zMax,
-                                                      final double tolerance) {
-        if ((xMin >= xMax - tolerance) || (yMin >= yMax - tolerance) || (zMin >= zMax - tolerance)) {
-            // too thin box, build an empty polygons set
-            return new BSPTree<>(Boolean.FALSE);
-        }
-        final Plane pxMin = new Plane(new Cartesian3D(xMin, 0,    0),   Cartesian3D.MINUS_I, tolerance);
-        final Plane pxMax = new Plane(new Cartesian3D(xMax, 0,    0),   Cartesian3D.PLUS_I,  tolerance);
-        final Plane pyMin = new Plane(new Cartesian3D(0,    yMin, 0),   Cartesian3D.MINUS_J, tolerance);
-        final Plane pyMax = new Plane(new Cartesian3D(0,    yMax, 0),   Cartesian3D.PLUS_J,  tolerance);
-        final Plane pzMin = new Plane(new Cartesian3D(0,    0,   zMin), Cartesian3D.MINUS_K, tolerance);
-        final Plane pzMax = new Plane(new Cartesian3D(0,    0,   zMax), Cartesian3D.PLUS_K,  tolerance);
-        final Region<Euclidean3D> boundary =
-        new RegionFactory<Euclidean3D>().buildConvex(pxMin, pxMax, pyMin, pyMax, pzMin, pzMax);
-        return boundary.getTree(false);
-    }
-
-    /** Build boundary from vertices and facets.
-     * @param vertices list of polyhedrons set vertices
-     * @param facets list of facets, as vertices indices in the vertices list
-     * @param tolerance tolerance below which points are considered identical
-     * @return boundary as a list of sub-hyperplanes
-     * @exception MathIllegalArgumentException if some basic sanity checks fail
-     * @since 3.5
-     */
-    private static List<SubHyperplane<Euclidean3D>> buildBoundary(final List<Cartesian3D> vertices,
-                                                                  final List<int[]> facets,
-                                                                  final double tolerance) {
-
-        // check vertices distances
-        for (int i = 0; i < vertices.size() - 1; ++i) {
-            final Cartesian3D vi = vertices.get(i);
-            for (int j = i + 1; j < vertices.size(); ++j) {
-                if (Cartesian3D.distance(vi, vertices.get(j)) <= tolerance) {
-                    throw new MathIllegalArgumentException(LocalizedFormats.CLOSE_VERTICES,
-                                                           vi.getX(), vi.getY(), vi.getZ());
-                }
-            }
-        }
-
-        // find how vertices are referenced by facets
-        final int[][] references = findReferences(vertices, facets);
-
-        // find how vertices are linked together by edges along the facets they belong to
-        final int[][] successors = successors(vertices, facets, references);
-
-        // check edges orientations
-        for (int vA = 0; vA < vertices.size(); ++vA) {
-            for (final int vB : successors[vA]) {
-
-                if (vB >= 0) {
-                    // when facets are properly oriented, if vB is the successor of vA on facet f1,
-                    // then there must be an adjacent facet f2 where vA is the successor of vB
-                    boolean found = false;
-                    for (final int v : successors[vB]) {
-                        found = found || (v == vA);
-                    }
-                    if (!found) {
-                        final Cartesian3D start = vertices.get(vA);
-                        final Cartesian3D end   = vertices.get(vB);
-                        throw new MathIllegalArgumentException(LocalizedFormats.EDGE_CONNECTED_TO_ONE_FACET,
-                                                               start.getX(), start.getY(), start.getZ(),
-                                                               end.getX(),   end.getY(),   end.getZ());
-                    }
-                }
-            }
-        }
-
-        final List<SubHyperplane<Euclidean3D>> boundary = new ArrayList<>();
-
-        for (final int[] facet : facets) {
-
-            // define facet plane from the first 3 points
-            Plane plane = new Plane(vertices.get(facet[0]), vertices.get(facet[1]), vertices.get(facet[2]),
-                                    tolerance);
-
-            // check all points are in the plane
-            final Cartesian2D[] two2Points = new Cartesian2D[facet.length];
-            for (int i = 0 ; i < facet.length; ++i) {
-                final Cartesian3D v = vertices.get(facet[i]);
-                if (!plane.contains(v)) {
-                    throw new MathIllegalArgumentException(LocalizedFormats.OUT_OF_PLANE,
-                                                           v.getX(), v.getY(), v.getZ());
-                }
-                two2Points[i] = plane.toSubSpace(v);
-            }
-
-            // create the polygonal facet
-            boundary.add(new SubPlane(plane, new PolygonsSet(tolerance, two2Points)));
-
-        }
-
-        return boundary;
-
-    }
-
-    /** Find the facets that reference each edges.
-     * @param vertices list of polyhedrons set vertices
-     * @param facets list of facets, as vertices indices in the vertices list
-     * @return references array such that r[v][k] = f for some k if facet f contains vertex v
-     * @exception MathIllegalArgumentException if some facets have fewer than 3 vertices
-     * @since 3.5
-     */
-    private static int[][] findReferences(final List<Cartesian3D> vertices, final List<int[]> facets) {
-
-        // find the maximum number of facets a vertex belongs to
-        final int[] nbFacets = new int[vertices.size()];
-        int maxFacets  = 0;
-        for (final int[] facet : facets) {
-            if (facet.length < 3) {
-                throw new NumberIsTooSmallException(LocalizedFormats.WRONG_NUMBER_OF_POINTS,
-                                                    3, facet.length, true);
-            }
-            for (final int index : facet) {
-                maxFacets = FastMath.max(maxFacets, ++nbFacets[index]);
-            }
-        }
-
-        // set up the references array
-        final int[][] references = new int[vertices.size()][maxFacets];
-        for (int[] r : references) {
-            Arrays.fill(r, -1);
-        }
-        for (int f = 0; f < facets.size(); ++f) {
-            for (final int v : facets.get(f)) {
-                // vertex v is referenced by facet f
-                int k = 0;
-                while (k < maxFacets && references[v][k] >= 0) {
-                    ++k;
-                }
-                references[v][k] = f;
-            }
-        }
-
-        return references;
-
-    }
-
-    /** Find the successors of all vertices among all facets they belong to.
-     * @param vertices list of polyhedrons set vertices
-     * @param facets list of facets, as vertices indices in the vertices list
-     * @param references facets references array
-     * @return indices of vertices that follow vertex v in some facet (the array
-     * may contain extra entries at the end, set to negative indices)
-     * @exception MathIllegalArgumentException if the same vertex appears more than
-     * once in the successors list (which means one facet orientation is wrong)
-     * @since 3.5
-     */
-    private static int[][] successors(final List<Cartesian3D> vertices, final List<int[]> facets,
-                                      final int[][] references) {
-
-        // create an array large enough
-        final int[][] successors = new int[vertices.size()][references[0].length];
-        for (final int[] s : successors) {
-            Arrays.fill(s, -1);
-        }
-
-        for (int v = 0; v < vertices.size(); ++v) {
-            for (int k = 0; k < successors[v].length && references[v][k] >= 0; ++k) {
-
-                // look for vertex v
-                final int[] facet = facets.get(references[v][k]);
-                int i = 0;
-                while (i < facet.length && facet[i] != v) {
-                    ++i;
-                }
-
-                // we have found vertex v, we deduce its successor on current facet
-                successors[v][k] = facet[(i + 1) % facet.length];
-                for (int l = 0; l < k; ++l) {
-                    if (successors[v][l] == successors[v][k]) {
-                        final Cartesian3D start = vertices.get(v);
-                        final Cartesian3D end   = vertices.get(successors[v][k]);
-                        throw new MathIllegalArgumentException(LocalizedFormats.FACET_ORIENTATION_MISMATCH,
-                                                               start.getX(), start.getY(), start.getZ(),
-                                                               end.getX(),   end.getY(),   end.getZ());
-                    }
-                }
-
-            }
-        }
-
-        return successors;
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public PolyhedronsSet buildNew(final BSPTree<Euclidean3D> tree) {
-        return new PolyhedronsSet(tree, getTolerance());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void computeGeometricalProperties() {
-        // check simple cases first
-        if (isEmpty()) {
-            setSize(0.0);
-            setBarycenter((Point<Euclidean3D>) Cartesian3D.NaN);
-        }
-        else if (isFull()) {
-            setSize(Double.POSITIVE_INFINITY);
-            setBarycenter((Point<Euclidean3D>) Cartesian3D.NaN);
-        }
-        else {
-            // not empty or full; compute the contribution of all boundary facets
-            final FacetsContributionVisitor contributionVisitor = new FacetsContributionVisitor();
-            getTree(true).visit(contributionVisitor);
-
-            final double size = contributionVisitor.getSize();
-            final Cartesian3D barycenter = contributionVisitor.getBarycenter();
-
-            if (size < 0) {
-                // the polyhedrons set is a finite outside surrounded by an infinite inside
-                setSize(Double.POSITIVE_INFINITY);
-                setBarycenter((Point<Euclidean3D>) Cartesian3D.NaN);
-            } else {
-                // the polyhedrons set is finite
-                setSize(size);
-                setBarycenter((Point<Euclidean3D>) barycenter);
-            }
-        }
-    }
-
-    /** Visitor computing polyhedron geometrical properties.
-     *  The volume of the polyhedron is computed using the equation
-     *  <code>V = (1/3)*&Sigma;<sub>F</sub>[(C<sub>F</sub>&sdot;N<sub>F</sub>)*area(F)]</code>,
-     *  where <code>F</code> represents each face in the polyhedron, <code>C<sub>F</sub></code>
-     *  represents the barycenter of the face, and <code>N<sub>F</sub></code> represents the
-     *  normal of the face. (More details can be found in the article
-     *  <a href="https://en.wikipedia.org/wiki/Polyhedron#Volume">here</a>.)
-     *  This essentially splits up the polyhedron into pyramids with a polyhedron
-     *  face forming the base of each pyramid.
-     *  The barycenter is computed in a similar way. The barycenter of each pyramid
-     *  is calculated using the fact that it is located 3/4 of the way along the
-     *  line from the apex to the base. The polyhedron barycenter then becomes
-     *  the volume-weighted average of these pyramid centers.
-     */
-    private static class FacetsContributionVisitor implements BSPTreeVisitor<Euclidean3D> {
-
-        /** Accumulator for facet volume contributions. */
-        private double volumeSum;
-
-        /** Accumulator for barycenter contributions. */
-        private Cartesian3D barycenterSum = Cartesian3D.ZERO;
-
-        /** Returns the total computed size (ie, volume) of the polyhedron.
-         * This value will be negative if the polyhedron is "inside-out", meaning
-         * that it has a finite outside surrounded by an infinite inside.
-         * @return the volume.
-         */
-        public double getSize() {
-            // apply the 1/3 pyramid volume scaling factor
-            return volumeSum / 3.0;
-        }
-
-        /** Returns the computed barycenter. This is the volume-weighted average
-         * of contributions from all facets. All coordinates will be NaN if the
-         * region is infinite.
-         * @return the barycenter.
-         */
-        public Cartesian3D getBarycenter() {
-            // Since the volume we used when adding together the facet contributions
-            // was 3x the actual pyramid size, we'll multiply by 1/4 here instead
-            // of 3/4 to adjust for the actual barycenter position in each pyramid.
-            return new Cartesian3D(1.0 / (4 * getSize()), barycenterSum);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Order visitOrder(final BSPTree<Euclidean3D> node) {
-            return Order.MINUS_SUB_PLUS;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void visitInternalNode(final BSPTree<Euclidean3D> node) {
-            @SuppressWarnings("unchecked")
-            final BoundaryAttribute<Euclidean3D> attribute =
-                (BoundaryAttribute<Euclidean3D>) node.getAttribute();
-            if (attribute.getPlusOutside() != null) {
-                addContribution(attribute.getPlusOutside(), false);
-            }
-            if (attribute.getPlusInside() != null) {
-                addContribution(attribute.getPlusInside(), true);
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void visitLeafNode(final BSPTree<Euclidean3D> node) {
-        }
-
-        /** Add the contribution of a boundary facet.
-         * @param facet boundary facet
-         * @param reversed if true, the facet has the inside on its plus side
-         */
-        private void addContribution(final SubHyperplane<Euclidean3D> facet, final boolean reversed) {
-
-            final Region<Euclidean2D> polygon = ((SubPlane) facet).getRemainingRegion();
-            final double area = polygon.getSize();
-
-            if (Double.isInfinite(area)) {
-                volumeSum = Double.POSITIVE_INFINITY;
-                barycenterSum = Cartesian3D.NaN;
-            } else {
-                final Plane plane = (Plane) facet.getHyperplane();
-                final Cartesian3D facetBarycenter = plane.toSpace(polygon.getBarycenter());
-
-                // the volume here is actually 3x the actual pyramid volume; we'll apply
-                // the final scaling all at once at the end
-                double scaledVolume = area * facetBarycenter.dotProduct(plane.getNormal());
-                if (reversed) {
-                    scaledVolume = -scaledVolume;
-                }
-
-                volumeSum += scaledVolume;
-                barycenterSum = new Cartesian3D(1.0, barycenterSum, scaledVolume, facetBarycenter);
-            }
-        }
-    }
-
-    /** Get the first sub-hyperplane crossed by a semi-infinite line.
-     * @param point start point of the part of the line considered
-     * @param line line to consider (contains point)
-     * @return the first sub-hyperplane crossed by the line after the
-     * given point, or null if the line does not intersect any
-     * sub-hyperplane
-     */
-    public SubHyperplane<Euclidean3D> firstIntersection(final Cartesian3D point, final Line line) {
-        return recurseFirstIntersection(getTree(true), point, line);
-    }
-
-    /** Get the first sub-hyperplane crossed by a semi-infinite line.
-     * @param node current node
-     * @param point start point of the part of the line considered
-     * @param line line to consider (contains point)
-     * @return the first sub-hyperplane crossed by the line after the
-     * given point, or null if the line does not intersect any
-     * sub-hyperplane
-     */
-    private SubHyperplane<Euclidean3D> recurseFirstIntersection(final BSPTree<Euclidean3D> node,
-                                                                final Cartesian3D point,
-                                                                final Line line) {
-
-        final SubHyperplane<Euclidean3D> cut = node.getCut();
-        if (cut == null) {
-            return null;
-        }
-        final BSPTree<Euclidean3D> minus = node.getMinus();
-        final BSPTree<Euclidean3D> plus  = node.getPlus();
-        final Plane                plane = (Plane) cut.getHyperplane();
-
-        // establish search order
-        final double offset = plane.getOffset(point);
-        final boolean in    = FastMath.abs(offset) < getTolerance();
-        final BSPTree<Euclidean3D> near;
-        final BSPTree<Euclidean3D> far;
-        if (offset < 0) {
-            near = minus;
-            far  = plus;
-        } else {
-            near = plus;
-            far  = minus;
-        }
-
-        if (in) {
-            // search in the cut hyperplane
-            final SubHyperplane<Euclidean3D> facet = boundaryFacet(point, node);
-            if (facet != null) {
-                return facet;
-            }
-        }
-
-        // search in the near branch
-        final SubHyperplane<Euclidean3D> crossed = recurseFirstIntersection(near, point, line);
-        if (crossed != null) {
-            return crossed;
-        }
-
-        if (!in) {
-            // search in the cut hyperplane
-            final Cartesian3D hit3D = plane.intersection(line);
-            if (hit3D != null && line.getAbscissa(hit3D) > line.getAbscissa(point)) {
-                final SubHyperplane<Euclidean3D> facet = boundaryFacet(hit3D, node);
-                if (facet != null) {
-                    return facet;
-                }
-            }
-        }
-
-        // search in the far branch
-        return recurseFirstIntersection(far, point, line);
-
-    }
-
-    /** Check if a point belongs to the boundary part of a node.
-     * @param point point to check
-     * @param node node containing the boundary facet to check
-     * @return the boundary facet this points belongs to (or null if it
-     * does not belong to any boundary facet)
-     */
-    private SubHyperplane<Euclidean3D> boundaryFacet(final Cartesian3D point,
-                                                     final BSPTree<Euclidean3D> node) {
-        final Cartesian2D point2D = ((Plane) node.getCut().getHyperplane()).toSubSpace(point);
-        @SuppressWarnings("unchecked")
-        final BoundaryAttribute<Euclidean3D> attribute =
-            (BoundaryAttribute<Euclidean3D>) node.getAttribute();
-        if ((attribute.getPlusOutside() != null) &&
-            (((SubPlane) attribute.getPlusOutside()).getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) {
-            return attribute.getPlusOutside();
-        }
-        if ((attribute.getPlusInside() != null) &&
-            (((SubPlane) attribute.getPlusInside()).getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) {
-            return attribute.getPlusInside();
-        }
-        return null;
-    }
-
-    /** Rotate the region around the specified point.
-     * <p>The instance is not modified, a new instance is created.</p>
-     * @param center rotation center
-     * @param rotation vectorial rotation operator
-     * @return a new instance representing the rotated region
-     */
-    public PolyhedronsSet rotate(final Cartesian3D center, final Rotation rotation) {
-        return (PolyhedronsSet) applyTransform(new RotationTransform(center, rotation));
-    }
-
-    /** 3D rotation as a Transform. */
-    private static class RotationTransform implements Transform<Euclidean3D, Euclidean2D> {
-
-        /** Center point of the rotation. */
-        private final Cartesian3D   center;
-
-        /** Vectorial rotation. */
-        private final Rotation   rotation;
-
-        /** Cached original hyperplane. */
-        private Plane cachedOriginal;
-
-        /** Cached 2D transform valid inside the cached original hyperplane. */
-        private Transform<Euclidean2D, Euclidean1D>  cachedTransform;
-
-        /** Build a rotation transform.
-         * @param center center point of the rotation
-         * @param rotation vectorial rotation
-         */
-        RotationTransform(final Cartesian3D center, final Rotation rotation) {
-            this.center   = center;
-            this.rotation = rotation;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Cartesian3D apply(final Point<Euclidean3D> point) {
-            final Cartesian3D delta = ((Cartesian3D) point).subtract(center);
-            return new Cartesian3D(1.0, center, 1.0, rotation.applyTo(delta));
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Plane apply(final Hyperplane<Euclidean3D> hyperplane) {
-            return ((Plane) hyperplane).rotate(center, rotation);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public SubHyperplane<Euclidean2D> apply(final SubHyperplane<Euclidean2D> sub,
-                                                final Hyperplane<Euclidean3D> original,
-                                                final Hyperplane<Euclidean3D> transformed) {
-            if (original != cachedOriginal) {
-                // we have changed hyperplane, reset the in-hyperplane transform
-
-                final Plane    oPlane = (Plane) original;
-                final Plane    tPlane = (Plane) transformed;
-                final Cartesian3D p00    = oPlane.getOrigin();
-                final Cartesian3D p10    = oPlane.toSpace(new Cartesian2D(1.0, 0.0));
-                final Cartesian3D p01    = oPlane.toSpace(new Cartesian2D(0.0, 1.0));
-                final Cartesian2D tP00   = tPlane.toSubSpace(apply(p00));
-                final Cartesian2D tP10   = tPlane.toSubSpace(apply(p10));
-                final Cartesian2D tP01   = tPlane.toSubSpace(apply(p01));
-
-                cachedOriginal  = (Plane) original;
-                cachedTransform =
-                        org.apache.commons.math4.geometry.euclidean.twod.Line.getTransform(tP10.getX() - tP00.getX(),
-                                                                                           tP10.getY() - tP00.getY(),
-                                                                                           tP01.getX() - tP00.getX(),
-                                                                                           tP01.getY() - tP00.getY(),
-                                                                                           tP00.getX(),
-                                                                                           tP00.getY());
-
-            }
-            return ((SubLine) sub).applyTransform(cachedTransform);
-        }
-
-    }
-
-    /** Translate the region by the specified amount.
-     * <p>The instance is not modified, a new instance is created.</p>
-     * @param translation translation to apply
-     * @return a new instance representing the translated region
-     */
-    public PolyhedronsSet translate(final Cartesian3D translation) {
-        return (PolyhedronsSet) applyTransform(new TranslationTransform(translation));
-    }
-
-    /** 3D translation as a transform. */
-    private static class TranslationTransform implements Transform<Euclidean3D, Euclidean2D> {
-
-        /** Translation vector. */
-        private final Cartesian3D   translation;
-
-        /** Cached original hyperplane. */
-        private Plane cachedOriginal;
-
-        /** Cached 2D transform valid inside the cached original hyperplane. */
-        private Transform<Euclidean2D, Euclidean1D>  cachedTransform;
-
-        /** Build a translation transform.
-         * @param translation translation vector
-         */
-        TranslationTransform(final Cartesian3D translation) {
-            this.translation = translation;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Cartesian3D apply(final Point<Euclidean3D> point) {
-            return new Cartesian3D(1.0, (Cartesian3D) point, 1.0, translation);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Plane apply(final Hyperplane<Euclidean3D> hyperplane) {
-            return ((Plane) hyperplane).translate(translation);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public SubHyperplane<Euclidean2D> apply(final SubHyperplane<Euclidean2D> sub,
-                                                final Hyperplane<Euclidean3D> original,
-                                                final Hyperplane<Euclidean3D> transformed) {
-            if (original != cachedOriginal) {
-                // we have changed hyperplane, reset the in-hyperplane transform
-
-                final Plane   oPlane = (Plane) original;
-                final Plane   tPlane = (Plane) transformed;
-                final Cartesian2D shift  = tPlane.toSubSpace(apply(oPlane.getOrigin()));
-
-                cachedOriginal  = (Plane) original;
-                cachedTransform =
-                        org.apache.commons.math4.geometry.euclidean.twod.Line.getTransform(1, 0, 0, 1,
-                                                                                           shift.getX(),
-                                                                                           shift.getY());
-
-            }
-
-            return ((SubLine) sub).applyTransform(cachedTransform);
-
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Rotation.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Rotation.java
deleted file mode 100644
index 4d18e52..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Rotation.java
+++ /dev/null
@@ -1,1424 +0,0 @@
-/*
- * 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.Serializable;
-
-import org.apache.commons.numbers.arrays.LinearCombination;
-import org.apache.commons.math4.exception.MathArithmeticException;
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.util.FastMath;
-
-/**
- * This class implements rotations in a three-dimensional space.
- *
- * <p>Rotations can be represented by several different mathematical
- * entities (matrices, axe and angle, Cardan or Euler angles,
- * quaternions). This class presents an higher level abstraction, more
- * user-oriented and hiding this implementation details. Well, for the
- * curious, we use quaternions for the internal representation. The
- * user can build a rotation from any of these representations, and
- * any of these representations can be retrieved from a
- * <code>Rotation</code> instance (see the various constructors and
- * getters). In addition, a rotation can also be built implicitly
- * from a set of vectors and their image.</p>
- * <p>This implies that this class can be used to convert from one
- * representation to another one. For example, converting a rotation
- * matrix into a set of Cardan angles from can be done using the
- * following single line of code:</p>
- * <pre>
- * double[] angles = new Rotation(matrix, 1.0e-10).getAngles(RotationOrder.XYZ);
- * </pre>
- * <p>Focus is oriented on what a rotation <em>do</em> rather than on its
- * underlying representation. Once it has been built, and regardless of its
- * internal representation, a rotation is an <em>operator</em> which basically
- * transforms three dimensional {@link Cartesian3D vectors} into other three
- * dimensional {@link Cartesian3D vectors}. Depending on the application, the
- * meaning of these vectors may vary and the semantics of the rotation also.</p>
- * <p>For example in an spacecraft attitude simulation tool, users will often
- * consider the vectors are fixed (say the Earth direction for example) and the
- * frames change. The rotation transforms the coordinates of the vector in inertial
- * frame into the coordinates of the same vector in satellite frame. In this
- * case, the rotation implicitly defines the relation between the two frames.</p>
- * <p>Another example could be a telescope control application, where the rotation
- * would transform the sighting direction at rest into the desired observing
- * direction when the telescope is pointed towards an object of interest. In this
- * case the rotation transforms the direction at rest in a topocentric frame
- * into the sighting direction in the same topocentric frame. This implies in this
- * case the frame is fixed and the vector moves.</p>
- * <p>In many case, both approaches will be combined. In our telescope example,
- * we will probably also need to transform the observing direction in the topocentric
- * frame into the observing direction in inertial frame taking into account the observatory
- * location and the Earth rotation, which would essentially be an application of the
- * first approach.</p>
- *
- * <p>These examples show that a rotation is what the user wants it to be. This
- * class does not push the user towards one specific definition and hence does not
- * provide methods like <code>projectVectorIntoDestinationFrame</code> or
- * <code>computeTransformedDirection</code>. It provides simpler and more generic
- * methods: {@link #applyTo(Cartesian3D) applyTo(Cartesian3D)} and {@link
- * #applyInverseTo(Cartesian3D) applyInverseTo(Cartesian3D)}.</p>
- *
- * <p>Since a rotation is basically a vectorial operator, several rotations can be
- * composed together and the composite operation <code>r = r<sub>1</sub> o
- * r<sub>2</sub></code> (which means that for each vector <code>u</code>,
- * <code>r(u) = r<sub>1</sub>(r<sub>2</sub>(u))</code>) is also a rotation. Hence
- * we can consider that in addition to vectors, a rotation can be applied to other
- * rotations as well (or to itself). With our previous notations, we would say we
- * can apply <code>r<sub>1</sub></code> to <code>r<sub>2</sub></code> and the result
- * we get is <code>r = r<sub>1</sub> o r<sub>2</sub></code>. For this purpose, the
- * class provides the methods: {@link #applyTo(Rotation) applyTo(Rotation)} and
- * {@link #applyInverseTo(Rotation) applyInverseTo(Rotation)}.</p>
- *
- * <p>Rotations are guaranteed to be immutable objects.</p>
- *
- * @see Cartesian3D
- * @see RotationOrder
- * @since 1.2
- */
-
-public class Rotation implements Serializable {
-
-  /** Identity rotation. */
-  public static final Rotation IDENTITY = new Rotation(1.0, 0.0, 0.0, 0.0, false);
-
-  /** Serializable version identifier */
-  private static final long serialVersionUID = -2153622329907944313L;
-
-  /** Scalar coordinate of the quaternion. */
-  private final double q0;
-
-  /** First coordinate of the vectorial part of the quaternion. */
-  private final double q1;
-
-  /** Second coordinate of the vectorial part of the quaternion. */
-  private final double q2;
-
-  /** Third coordinate of the vectorial part of the quaternion. */
-  private final double q3;
-
-  /** Build a rotation from the quaternion coordinates.
-   * <p>A rotation can be built from a <em>normalized</em> quaternion,
-   * i.e. a quaternion for which q<sub>0</sub><sup>2</sup> +
-   * q<sub>1</sub><sup>2</sup> + q<sub>2</sub><sup>2</sup> +
-   * q<sub>3</sub><sup>2</sup> = 1. If the quaternion is not normalized,
-   * the constructor can normalize it in a preprocessing step.</p>
-   * <p>Note that some conventions put the scalar part of the quaternion
-   * as the 4<sup>th</sup> component and the vector part as the first three
-   * components. This is <em>not</em> our convention. We put the scalar part
-   * as the first component.</p>
-   * @param q0 scalar part of the quaternion
-   * @param q1 first coordinate of the vectorial part of the quaternion
-   * @param q2 second coordinate of the vectorial part of the quaternion
-   * @param q3 third coordinate of the vectorial part of the quaternion
-   * @param needsNormalization if true, the coordinates are considered
-   * not to be normalized, a normalization preprocessing step is performed
-   * before using them
-   */
-  public Rotation(double q0, double q1, double q2, double q3,
-                  boolean needsNormalization) {
-
-    if (needsNormalization) {
-      // normalization preprocessing
-      double inv = 1.0 / FastMath.sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
-      q0 *= inv;
-      q1 *= inv;
-      q2 *= inv;
-      q3 *= inv;
-    }
-
-    this.q0 = q0;
-    this.q1 = q1;
-    this.q2 = q2;
-    this.q3 = q3;
-
-  }
-
-  /** Build a rotation from an axis and an angle.
-   * <p>
-   * Calling this constructor is equivalent to call
-   * {@link #Rotation(Cartesian3D, double, RotationConvention)
-   * new Rotation(axis, angle, RotationConvention.VECTOR_OPERATOR)}
-   * </p>
-   * @param axis axis around which to rotate
-   * @param angle rotation angle.
-   * @exception MathIllegalArgumentException if the axis norm is zero
-   * @deprecated as of 3.6, replaced with {@link #Rotation(Cartesian3D, double, RotationConvention)}
-   */
-  @Deprecated
-  public Rotation(Cartesian3D axis, double angle) throws MathIllegalArgumentException {
-      this(axis, angle, RotationConvention.VECTOR_OPERATOR);
-  }
-
-  /** Build a rotation from an axis and an angle.
-   * @param axis axis around which to rotate
-   * @param angle rotation angle
-   * @param convention convention to use for the semantics of the angle
-   * @exception MathIllegalArgumentException if the axis norm is zero
-   * @since 3.6
-   */
-  public Rotation(final Cartesian3D axis, final double angle, final RotationConvention convention)
-      throws MathIllegalArgumentException {
-
-    double norm = axis.getNorm();
-    if (norm == 0) {
-      throw new MathIllegalArgumentException(LocalizedFormats.ZERO_NORM_FOR_ROTATION_AXIS);
-    }
-
-    double halfAngle = convention == RotationConvention.VECTOR_OPERATOR ? -0.5 * angle : +0.5 * angle;
-    double coeff = FastMath.sin(halfAngle) / norm;
-
-    q0 = FastMath.cos (halfAngle);
-    q1 = coeff * axis.getX();
-    q2 = coeff * axis.getY();
-    q3 = coeff * axis.getZ();
-
-  }
-
-  /** Build a rotation from a 3X3 matrix.
-
-   * <p>Rotation matrices are orthogonal matrices, i.e. unit matrices
-   * (which are matrices for which m.m<sup>T</sup> = I) with real
-   * coefficients. The module of the determinant of unit matrices is
-   * 1, among the orthogonal 3X3 matrices, only the ones having a
-   * positive determinant (+1) are rotation matrices.</p>
-
-   * <p>When a rotation is defined by a matrix with truncated values
-   * (typically when it is extracted from a technical sheet where only
-   * four to five significant digits are available), the matrix is not
-   * orthogonal anymore. This constructor handles this case
-   * transparently by using a copy of the given matrix and applying a
-   * correction to the copy in order to perfect its orthogonality. If
-   * the Frobenius norm of the correction needed is above the given
-   * threshold, then the matrix is considered to be too far from a
-   * true rotation matrix and an exception is thrown.<p>
-
-   * @param m rotation matrix
-   * @param threshold convergence threshold for the iterative
-   * orthogonality correction (convergence is reached when the
-   * difference between two steps of the Frobenius norm of the
-   * correction is below this threshold)
-
-   * @exception NotARotationMatrixException if the matrix is not a 3X3
-   * matrix, or if it cannot be transformed into an orthogonal matrix
-   * with the given threshold, or if the determinant of the resulting
-   * orthogonal matrix is negative
-
-   */
-  public Rotation(double[][] m, double threshold)
-    throws NotARotationMatrixException {
-
-    // dimension check
-    if ((m.length != 3) || (m[0].length != 3) ||
-        (m[1].length != 3) || (m[2].length != 3)) {
-      throw new NotARotationMatrixException(
-              LocalizedFormats.ROTATION_MATRIX_DIMENSIONS,
-              m.length, m[0].length);
-    }
-
-    // compute a "close" orthogonal matrix
-    double[][] ort = orthogonalizeMatrix(m, threshold);
-
-    // check the sign of the determinant
-    double det = ort[0][0] * (ort[1][1] * ort[2][2] - ort[2][1] * ort[1][2]) -
-                 ort[1][0] * (ort[0][1] * ort[2][2] - ort[2][1] * ort[0][2]) +
-                 ort[2][0] * (ort[0][1] * ort[1][2] - ort[1][1] * ort[0][2]);
-    if (det < 0.0) {
-      throw new NotARotationMatrixException(
-              LocalizedFormats.CLOSEST_ORTHOGONAL_MATRIX_HAS_NEGATIVE_DETERMINANT,
-              det);
-    }
-
-    double[] quat = mat2quat(ort);
-    q0 = quat[0];
-    q1 = quat[1];
-    q2 = quat[2];
-    q3 = quat[3];
-
-  }
-
-  /** Build the rotation that transforms a pair of vectors into another pair.
-
-   * <p>Except for possible scale factors, if the instance were applied to
-   * the pair (u<sub>1</sub>, u<sub>2</sub>) it will produce the pair
-   * (v<sub>1</sub>, v<sub>2</sub>).</p>
-
-   * <p>If the angular separation between u<sub>1</sub> and u<sub>2</sub> is
-   * not the same as the angular separation between v<sub>1</sub> and
-   * v<sub>2</sub>, then a corrected v'<sub>2</sub> will be used rather than
-   * v<sub>2</sub>, the corrected vector will be in the (&plusmn;v<sub>1</sub>,
-   * +v<sub>2</sub>) half-plane.</p>
-
-   * @param u1 first vector of the origin pair
-   * @param u2 second vector of the origin pair
-   * @param v1 desired image of u1 by the rotation
-   * @param v2 desired image of u2 by the rotation
-   * @exception MathArithmeticException if the norm of one of the vectors is zero,
-   * or if one of the pair is degenerated (i.e. the vectors of the pair are collinear)
-   */
-  public Rotation(Cartesian3D u1, Cartesian3D u2, Cartesian3D v1, Cartesian3D v2)
-      throws MathArithmeticException {
-
-      // build orthonormalized base from u1, u2
-      // this fails when vectors are null or collinear, which is forbidden to define a rotation
-      final Cartesian3D u3 = u1.crossProduct(u2).normalize();
-      u2 = u3.crossProduct(u1).normalize();
-      u1 = u1.normalize();
-
-      // build an orthonormalized base from v1, v2
-      // this fails when vectors are null or collinear, which is forbidden to define a rotation
-      final Cartesian3D v3 = v1.crossProduct(v2).normalize();
-      v2 = v3.crossProduct(v1).normalize();
-      v1 = v1.normalize();
-
-      // buid a matrix transforming the first base into the second one
-      final double[][] m = new double[][] {
-          {
-              LinearCombination.value(u1.getX(), v1.getX(), u2.getX(), v2.getX(), u3.getX(), v3.getX()),
-              LinearCombination.value(u1.getY(), v1.getX(), u2.getY(), v2.getX(), u3.getY(), v3.getX()),
-              LinearCombination.value(u1.getZ(), v1.getX(), u2.getZ(), v2.getX(), u3.getZ(), v3.getX())
-          },
-          {
-              LinearCombination.value(u1.getX(), v1.getY(), u2.getX(), v2.getY(), u3.getX(), v3.getY()),
-              LinearCombination.value(u1.getY(), v1.getY(), u2.getY(), v2.getY(), u3.getY(), v3.getY()),
-              LinearCombination.value(u1.getZ(), v1.getY(), u2.getZ(), v2.getY(), u3.getZ(), v3.getY())
-          },
-          {
-              LinearCombination.value(u1.getX(), v1.getZ(), u2.getX(), v2.getZ(), u3.getX(), v3.getZ()),
-              LinearCombination.value(u1.getY(), v1.getZ(), u2.getY(), v2.getZ(), u3.getY(), v3.getZ()),
-              LinearCombination.value(u1.getZ(), v1.getZ(), u2.getZ(), v2.getZ(), u3.getZ(), v3.getZ())
-          }
-      };
-
-      double[] quat = mat2quat(m);
-      q0 = quat[0];
-      q1 = quat[1];
-      q2 = quat[2];
-      q3 = quat[3];
-
-  }
-
-  /** Build one of the rotations that transform one vector into another one.
-
-   * <p>Except for a possible scale factor, if the instance were
-   * applied to the vector u it will produce the vector v. There is an
-   * infinite number of such rotations, this constructor choose the
-   * one with the smallest associated angle (i.e. the one whose axis
-   * is orthogonal to the (u, v) plane). If u and v are collinear, an
-   * arbitrary rotation axis is chosen.</p>
-
-   * @param u origin vector
-   * @param v desired image of u by the rotation
-   * @exception MathArithmeticException if the norm of one of the vectors is zero
-   */
-  public Rotation(Cartesian3D u, Cartesian3D v) throws MathArithmeticException {
-
-    double normProduct = u.getNorm() * v.getNorm();
-    if (normProduct == 0) {
-        throw new MathArithmeticException(LocalizedFormats.ZERO_NORM_FOR_ROTATION_DEFINING_VECTOR);
-    }
-
-    double dot = u.dotProduct(v);
-
-    if (dot < ((2.0e-15 - 1.0) * normProduct)) {
-      // special case u = -v: we select a PI angle rotation around
-      // an arbitrary vector orthogonal to u
-      Cartesian3D w = u.orthogonal();
-      q0 = 0.0;
-      q1 = -w.getX();
-      q2 = -w.getY();
-      q3 = -w.getZ();
-    } else {
-      // general case: (u, v) defines a plane, we select
-      // the shortest possible rotation: axis orthogonal to this plane
-      q0 = FastMath.sqrt(0.5 * (1.0 + dot / normProduct));
-      double coeff = 1.0 / (2.0 * q0 * normProduct);
-      Cartesian3D q = v.crossProduct(u);
-      q1 = coeff * q.getX();
-      q2 = coeff * q.getY();
-      q3 = coeff * q.getZ();
-    }
-
-  }
-
-  /** Build a rotation from three Cardan or Euler elementary rotations.
-
-   * <p>
-   * Calling this constructor is equivalent to call
-   * {@link #Rotation(RotationOrder, RotationConvention, double, double, double)
-   * new Rotation(order, RotationConvention.VECTOR_OPERATOR, alpha1, alpha2, alpha3)}
-   * </p>
-
-   * @param order order of rotations to use
-   * @param alpha1 angle of the first elementary rotation
-   * @param alpha2 angle of the second elementary rotation
-   * @param alpha3 angle of the third elementary rotation
-   * @deprecated as of 3.6, replaced with {@link
-   * #Rotation(RotationOrder, RotationConvention, double, double, double)}
-   */
-  @Deprecated
-  public Rotation(RotationOrder order,
-                  double alpha1, double alpha2, double alpha3) {
-      this(order, RotationConvention.VECTOR_OPERATOR, alpha1, alpha2, alpha3);
-  }
-
-  /** Build a rotation from three Cardan or Euler elementary rotations.
-
-   * <p>Cardan rotations are three successive rotations around the
-   * canonical axes X, Y and Z, each axis being used once. There are
-   * 6 such sets of rotations (XYZ, XZY, YXZ, YZX, ZXY and ZYX). Euler
-   * rotations are three successive rotations around the canonical
-   * axes X, Y and Z, the first and last rotations being around the
-   * same axis. There are 6 such sets of rotations (XYX, XZX, YXY,
-   * YZY, ZXZ and ZYZ), the most popular one being ZXZ.</p>
-   * <p>Beware that many people routinely use the term Euler angles even
-   * for what really are Cardan angles (this confusion is especially
-   * widespread in the aerospace business where Roll, Pitch and Yaw angles
-   * are often wrongly tagged as Euler angles).</p>
-
-   * @param order order of rotations to compose, from left to right
-   * (i.e. we will use {@code r1.compose(r2.compose(r3, convention), convention)})
-   * @param convention convention to use for the semantics of the angle
-   * @param alpha1 angle of the first elementary rotation
-   * @param alpha2 angle of the second elementary rotation
-   * @param alpha3 angle of the third elementary rotation
-   * @since 3.6
-   */
-  public Rotation(RotationOrder order, RotationConvention convention,
-                  double alpha1, double alpha2, double alpha3) {
-      Rotation r1 = new Rotation(order.getA1(), alpha1, convention);
-      Rotation r2 = new Rotation(order.getA2(), alpha2, convention);
-      Rotation r3 = new Rotation(order.getA3(), alpha3, convention);
-      Rotation composed = r1.compose(r2.compose(r3, convention), convention);
-      q0 = composed.q0;
-      q1 = composed.q1;
-      q2 = composed.q2;
-      q3 = composed.q3;
-  }
-
-  /** Convert an orthogonal rotation matrix to a quaternion.
-   * @param ort orthogonal rotation matrix
-   * @return quaternion corresponding to the matrix
-   */
-  private static double[] mat2quat(final double[][] ort) {
-
-      final double[] quat = new double[4];
-
-      // There are different ways to compute the quaternions elements
-      // from the matrix. They all involve computing one element from
-      // the diagonal of the matrix, and computing the three other ones
-      // using a formula involving a division by the first element,
-      // which unfortunately can be zero. Since the norm of the
-      // quaternion is 1, we know at least one element has an absolute
-      // value greater or equal to 0.5, so it is always possible to
-      // select the right formula and avoid division by zero and even
-      // numerical inaccuracy. Checking the elements in turn and using
-      // the first one greater than 0.45 is safe (this leads to a simple
-      // test since qi = 0.45 implies 4 qi^2 - 1 = -0.19)
-      double s = ort[0][0] + ort[1][1] + ort[2][2];
-      if (s > -0.19) {
-          // compute q0 and deduce q1, q2 and q3
-          quat[0] = 0.5 * FastMath.sqrt(s + 1.0);
-          double inv = 0.25 / quat[0];
-          quat[1] = inv * (ort[1][2] - ort[2][1]);
-          quat[2] = inv * (ort[2][0] - ort[0][2]);
-          quat[3] = inv * (ort[0][1] - ort[1][0]);
-      } else {
-          s = ort[0][0] - ort[1][1] - ort[2][2];
-          if (s > -0.19) {
-              // compute q1 and deduce q0, q2 and q3
-              quat[1] = 0.5 * FastMath.sqrt(s + 1.0);
-              double inv = 0.25 / quat[1];
-              quat[0] = inv * (ort[1][2] - ort[2][1]);
-              quat[2] = inv * (ort[0][1] + ort[1][0]);
-              quat[3] = inv * (ort[0][2] + ort[2][0]);
-          } else {
-              s = ort[1][1] - ort[0][0] - ort[2][2];
-              if (s > -0.19) {
-                  // compute q2 and deduce q0, q1 and q3
-                  quat[2] = 0.5 * FastMath.sqrt(s + 1.0);
-                  double inv = 0.25 / quat[2];
-                  quat[0] = inv * (ort[2][0] - ort[0][2]);
-                  quat[1] = inv * (ort[0][1] + ort[1][0]);
-                  quat[3] = inv * (ort[2][1] + ort[1][2]);
-              } else {
-                  // compute q3 and deduce q0, q1 and q2
-                  s = ort[2][2] - ort[0][0] - ort[1][1];
-                  quat[3] = 0.5 * FastMath.sqrt(s + 1.0);
-                  double inv = 0.25 / quat[3];
-                  quat[0] = inv * (ort[0][1] - ort[1][0]);
-                  quat[1] = inv * (ort[0][2] + ort[2][0]);
-                  quat[2] = inv * (ort[2][1] + ort[1][2]);
-              }
-          }
-      }
-
-      return quat;
-
-  }
-
-  /** Revert a rotation.
-   * Build a rotation which reverse the effect of another
-   * rotation. This means that if r(u) = v, then r.revert(v) = u. The
-   * instance is not changed.
-   * @return a new rotation whose effect is the reverse of the effect
-   * of the instance
-   */
-  public Rotation revert() {
-    return new Rotation(-q0, q1, q2, q3, false);
-  }
-
-  /** Get the scalar coordinate of the quaternion.
-   * @return scalar coordinate of the quaternion
-   */
-  public double getQ0() {
-    return q0;
-  }
-
-  /** Get the first coordinate of the vectorial part of the quaternion.
-   * @return first coordinate of the vectorial part of the quaternion
-   */
-  public double getQ1() {
-    return q1;
-  }
-
-  /** Get the second coordinate of the vectorial part of the quaternion.
-   * @return second coordinate of the vectorial part of the quaternion
-   */
-  public double getQ2() {
-    return q2;
-  }
-
-  /** Get the third coordinate of the vectorial part of the quaternion.
-   * @return third coordinate of the vectorial part of the quaternion
-   */
-  public double getQ3() {
-    return q3;
-  }
-
-  /** Get the normalized axis of the rotation.
-   * <p>
-   * Calling this method is equivalent to call
-   * {@link #getAxis(RotationConvention) getAxis(RotationConvention.VECTOR_OPERATOR)}
-   * </p>
-   * @return normalized axis of the rotation
-   * @see #Rotation(Cartesian3D, double, RotationConvention)
-   * @deprecated as of 3.6, replaced with {@link #getAxis(RotationConvention)}
-   */
-  @Deprecated
-  public Cartesian3D getAxis() {
-    return getAxis(RotationConvention.VECTOR_OPERATOR);
-  }
-
-  /** Get the normalized axis of the rotation.
-   * <p>
-   * Note that as {@link #getAngle()} always returns an angle
-   * between 0 and &pi;, changing the convention changes the
-   * direction of the axis, not the sign of the angle.
-   * </p>
-   * @param convention convention to use for the semantics of the angle
-   * @return normalized axis of the rotation
-   * @see #Rotation(Cartesian3D, double, RotationConvention)
-   * @since 3.6
-   */
-  public Cartesian3D getAxis(final RotationConvention convention) {
-    final double squaredSine = q1 * q1 + q2 * q2 + q3 * q3;
-    if (squaredSine == 0) {
-      return convention == RotationConvention.VECTOR_OPERATOR ? Cartesian3D.PLUS_I : Cartesian3D.MINUS_I;
-    } else {
-        final double sgn = convention == RotationConvention.VECTOR_OPERATOR ? +1 : -1;
-        if (q0 < 0) {
-            final double inverse = sgn / FastMath.sqrt(squaredSine);
-            return new Cartesian3D(q1 * inverse, q2 * inverse, q3 * inverse);
-        }
-        final double inverse = -sgn / FastMath.sqrt(squaredSine);
-        return new Cartesian3D(q1 * inverse, q2 * inverse, q3 * inverse);
-    }
-  }
-
-  /** Get the angle of the rotation.
-   * @return angle of the rotation (between 0 and &pi;)
-   * @see #Rotation(Cartesian3D, double)
-   */
-  public double getAngle() {
-    if ((q0 < -0.1) || (q0 > 0.1)) {
-      return 2 * FastMath.asin(FastMath.sqrt(q1 * q1 + q2 * q2 + q3 * q3));
-    } else if (q0 < 0) {
-      return 2 * FastMath.acos(-q0);
-    }
-    return 2 * FastMath.acos(q0);
-  }
-
-  /** Get the Cardan or Euler angles corresponding to the instance.
-
-   * <p>
-   * Calling this method is equivalent to call
-   * {@link #getAngles(RotationOrder, RotationConvention)
-   * getAngles(order, RotationConvention.VECTOR_OPERATOR)}
-   * </p>
-
-   * @param order rotation order to use
-   * @return an array of three angles, in the order specified by the set
-   * @exception CardanEulerSingularityException if the rotation is
-   * singular with respect to the angles set specified
-   * @deprecated as of 3.6, replaced with {@link #getAngles(RotationOrder, RotationConvention)}
-   */
-  @Deprecated
-  public double[] getAngles(RotationOrder order)
-      throws CardanEulerSingularityException {
-      return getAngles(order, RotationConvention.VECTOR_OPERATOR);
-  }
-
-  /** Get the Cardan or Euler angles corresponding to the instance.
-
-   * <p>The equations show that each rotation can be defined by two
-   * different values of the Cardan or Euler angles set. For example
-   * if Cardan angles are used, the rotation defined by the angles
-   * a<sub>1</sub>, a<sub>2</sub> and a<sub>3</sub> is the same as
-   * the rotation defined by the angles &pi; + a<sub>1</sub>, &pi;
-   * - a<sub>2</sub> and &pi; + a<sub>3</sub>. This method implements
-   * the following arbitrary choices:</p>
-   * <ul>
-   *   <li>for Cardan angles, the chosen set is the one for which the
-   *   second angle is between -&pi;/2 and &pi;/2 (i.e its cosine is
-   *   positive),</li>
-   *   <li>for Euler angles, the chosen set is the one for which the
-   *   second angle is between 0 and &pi; (i.e its sine is positive).</li>
-   * </ul>
-
-   * <p>Cardan and Euler angle have a very disappointing drawback: all
-   * of them have singularities. This means that if the instance is
-   * too close to the singularities corresponding to the given
-   * rotation order, it will be impossible to retrieve the angles. For
-   * Cardan angles, this is often called gimbal lock. There is
-   * <em>nothing</em> to do to prevent this, it is an intrinsic problem
-   * with Cardan and Euler representation (but not a problem with the
-   * rotation itself, which is perfectly well defined). For Cardan
-   * angles, singularities occur when the second angle is close to
-   * -&pi;/2 or +&pi;/2, for Euler angle singularities occur when the
-   * second angle is close to 0 or &pi;, this implies that the identity
-   * rotation is always singular for Euler angles!</p>
-
-   * @param order rotation order to use
-   * @param convention convention to use for the semantics of the angle
-   * @return an array of three angles, in the order specified by the set
-   * @exception CardanEulerSingularityException if the rotation is
-   * singular with respect to the angles set specified
-   * @since 3.6
-   */
-  public double[] getAngles(RotationOrder order, RotationConvention convention)
-      throws CardanEulerSingularityException {
-
-      if (convention == RotationConvention.VECTOR_OPERATOR) {
-          if (order == RotationOrder.XYZ) {
-
-              // r (Cartesian3D.plusK) coordinates are :
-              //  sin (theta), -cos (theta) sin (phi), cos (theta) cos (phi)
-              // (-r) (Cartesian3D.plusI) coordinates are :
-              // cos (psi) cos (theta), -sin (psi) cos (theta), sin (theta)
-              // and we can choose to have theta in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_K);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_I);
-              if  ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(-(v1.getY()), v1.getZ()),
-                  FastMath.asin(v2.getZ()),
-                  FastMath.atan2(-(v2.getY()), v2.getX())
-              };
-
-          } else if (order == RotationOrder.XZY) {
-
-              // r (Cartesian3D.plusJ) coordinates are :
-              // -sin (psi), cos (psi) cos (phi), cos (psi) sin (phi)
-              // (-r) (Cartesian3D.plusI) coordinates are :
-              // cos (theta) cos (psi), -sin (psi), sin (theta) cos (psi)
-              // and we can choose to have psi in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_J);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_I);
-              if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(v1.getZ(), v1.getY()),
-                 -FastMath.asin(v2.getY()),
-                  FastMath.atan2(v2.getZ(), v2.getX())
-              };
-
-          } else if (order == RotationOrder.YXZ) {
-
-              // r (Cartesian3D.plusK) coordinates are :
-              //  cos (phi) sin (theta), -sin (phi), cos (phi) cos (theta)
-              // (-r) (Cartesian3D.plusJ) coordinates are :
-              // sin (psi) cos (phi), cos (psi) cos (phi), -sin (phi)
-              // and we can choose to have phi in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_K);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_J);
-              if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(v1.getX(), v1.getZ()),
-                 -FastMath.asin(v2.getZ()),
-                  FastMath.atan2(v2.getX(), v2.getY())
-              };
-
-          } else if (order == RotationOrder.YZX) {
-
-              // r (Cartesian3D.plusI) coordinates are :
-              // cos (psi) cos (theta), sin (psi), -cos (psi) sin (theta)
-              // (-r) (Cartesian3D.plusJ) coordinates are :
-              // sin (psi), cos (phi) cos (psi), -sin (phi) cos (psi)
-              // and we can choose to have psi in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_I);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_J);
-              if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(-(v1.getZ()), v1.getX()),
-                  FastMath.asin(v2.getX()),
-                  FastMath.atan2(-(v2.getZ()), v2.getY())
-              };
-
-          } else if (order == RotationOrder.ZXY) {
-
-              // r (Cartesian3D.plusJ) coordinates are :
-              // -cos (phi) sin (psi), cos (phi) cos (psi), sin (phi)
-              // (-r) (Cartesian3D.plusK) coordinates are :
-              // -sin (theta) cos (phi), sin (phi), cos (theta) cos (phi)
-              // and we can choose to have phi in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_J);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_K);
-              if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(-(v1.getX()), v1.getY()),
-                  FastMath.asin(v2.getY()),
-                  FastMath.atan2(-(v2.getX()), v2.getZ())
-              };
-
-          } else if (order == RotationOrder.ZYX) {
-
-              // r (Cartesian3D.plusI) coordinates are :
-              //  cos (theta) cos (psi), cos (theta) sin (psi), -sin (theta)
-              // (-r) (Cartesian3D.plusK) coordinates are :
-              // -sin (theta), sin (phi) cos (theta), cos (phi) cos (theta)
-              // and we can choose to have theta in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_I);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_K);
-              if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(v1.getY(), v1.getX()),
-                 -FastMath.asin(v2.getX()),
-                  FastMath.atan2(v2.getY(), v2.getZ())
-              };
-
-          } else if (order == RotationOrder.XYX) {
-
-              // r (Cartesian3D.plusI) coordinates are :
-              //  cos (theta), sin (phi1) sin (theta), -cos (phi1) sin (theta)
-              // (-r) (Cartesian3D.plusI) coordinates are :
-              // cos (theta), sin (theta) sin (phi2), sin (theta) cos (phi2)
-              // and we can choose to have theta in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_I);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_I);
-              if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v1.getY(), -v1.getZ()),
-                  FastMath.acos(v2.getX()),
-                  FastMath.atan2(v2.getY(), v2.getZ())
-              };
-
-          } else if (order == RotationOrder.XZX) {
-
-              // r (Cartesian3D.plusI) coordinates are :
-              //  cos (psi), cos (phi1) sin (psi), sin (phi1) sin (psi)
-              // (-r) (Cartesian3D.plusI) coordinates are :
-              // cos (psi), -sin (psi) cos (phi2), sin (psi) sin (phi2)
-              // and we can choose to have psi in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_I);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_I);
-              if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v1.getZ(), v1.getY()),
-                  FastMath.acos(v2.getX()),
-                  FastMath.atan2(v2.getZ(), -v2.getY())
-              };
-
-          } else if (order == RotationOrder.YXY) {
-
-              // r (Cartesian3D.plusJ) coordinates are :
-              //  sin (theta1) sin (phi), cos (phi), cos (theta1) sin (phi)
-              // (-r) (Cartesian3D.plusJ) coordinates are :
-              // sin (phi) sin (theta2), cos (phi), -sin (phi) cos (theta2)
-              // and we can choose to have phi in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_J);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_J);
-              if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v1.getX(), v1.getZ()),
-                  FastMath.acos(v2.getY()),
-                  FastMath.atan2(v2.getX(), -v2.getZ())
-              };
-
-          } else if (order == RotationOrder.YZY) {
-
-              // r (Cartesian3D.plusJ) coordinates are :
-              //  -cos (theta1) sin (psi), cos (psi), sin (theta1) sin (psi)
-              // (-r) (Cartesian3D.plusJ) coordinates are :
-              // sin (psi) cos (theta2), cos (psi), sin (psi) sin (theta2)
-              // and we can choose to have psi in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_J);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_J);
-              if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v1.getZ(), -v1.getX()),
-                  FastMath.acos(v2.getY()),
-                  FastMath.atan2(v2.getZ(), v2.getX())
-              };
-
-          } else if (order == RotationOrder.ZXZ) {
-
-              // r (Cartesian3D.plusK) coordinates are :
-              //  sin (psi1) sin (phi), -cos (psi1) sin (phi), cos (phi)
-              // (-r) (Cartesian3D.plusK) coordinates are :
-              // sin (phi) sin (psi2), sin (phi) cos (psi2), cos (phi)
-              // and we can choose to have phi in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_K);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_K);
-              if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v1.getX(), -v1.getY()),
-                  FastMath.acos(v2.getZ()),
-                  FastMath.atan2(v2.getX(), v2.getY())
-              };
-
-          } else { // last possibility is ZYZ
-
-              // r (Cartesian3D.plusK) coordinates are :
-              //  cos (psi1) sin (theta), sin (psi1) sin (theta), cos (theta)
-              // (-r) (Cartesian3D.plusK) coordinates are :
-              // -sin (theta) cos (psi2), sin (theta) sin (psi2), cos (theta)
-              // and we can choose to have theta in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_K);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_K);
-              if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v1.getY(), v1.getX()),
-                  FastMath.acos(v2.getZ()),
-                  FastMath.atan2(v2.getY(), -v2.getX())
-              };
-
-          }
-      } else {
-          if (order == RotationOrder.XYZ) {
-
-              // r (Cartesian3D.plusI) coordinates are :
-              //  cos (theta) cos (psi), -cos (theta) sin (psi), sin (theta)
-              // (-r) (Cartesian3D.plusK) coordinates are :
-              // sin (theta), -sin (phi) cos (theta), cos (phi) cos (theta)
-              // and we can choose to have theta in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_I);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_K);
-              if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(-v2.getY(), v2.getZ()),
-                  FastMath.asin(v2.getX()),
-                  FastMath.atan2(-v1.getY(), v1.getX())
-              };
-
-          } else if (order == RotationOrder.XZY) {
-
-              // r (Cartesian3D.plusI) coordinates are :
-              // cos (psi) cos (theta), -sin (psi), cos (psi) sin (theta)
-              // (-r) (Cartesian3D.plusJ) coordinates are :
-              // -sin (psi), cos (phi) cos (psi), sin (phi) cos (psi)
-              // and we can choose to have psi in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_I);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_J);
-              if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(v2.getZ(), v2.getY()),
-                 -FastMath.asin(v2.getX()),
-                  FastMath.atan2(v1.getZ(), v1.getX())
-              };
-
-          } else if (order == RotationOrder.YXZ) {
-
-              // r (Cartesian3D.plusJ) coordinates are :
-              // cos (phi) sin (psi), cos (phi) cos (psi), -sin (phi)
-              // (-r) (Cartesian3D.plusK) coordinates are :
-              // sin (theta) cos (phi), -sin (phi), cos (theta) cos (phi)
-              // and we can choose to have phi in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_J);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_K);
-              if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(v2.getX(), v2.getZ()),
-                 -FastMath.asin(v2.getY()),
-                  FastMath.atan2(v1.getX(), v1.getY())
-              };
-
-          } else if (order == RotationOrder.YZX) {
-
-              // r (Cartesian3D.plusJ) coordinates are :
-              // sin (psi), cos (psi) cos (phi), -cos (psi) sin (phi)
-              // (-r) (Cartesian3D.plusI) coordinates are :
-              // cos (theta) cos (psi), sin (psi), -sin (theta) cos (psi)
-              // and we can choose to have psi in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_J);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_I);
-              if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(-v2.getZ(), v2.getX()),
-                  FastMath.asin(v2.getY()),
-                  FastMath.atan2(-v1.getZ(), v1.getY())
-              };
-
-          } else if (order == RotationOrder.ZXY) {
-
-              // r (Cartesian3D.plusK) coordinates are :
-              //  -cos (phi) sin (theta), sin (phi), cos (phi) cos (theta)
-              // (-r) (Cartesian3D.plusJ) coordinates are :
-              // -sin (psi) cos (phi), cos (psi) cos (phi), sin (phi)
-              // and we can choose to have phi in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_K);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_J);
-              if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(-v2.getX(), v2.getY()),
-                  FastMath.asin(v2.getZ()),
-                  FastMath.atan2(-v1.getX(), v1.getZ())
-              };
-
-          } else if (order == RotationOrder.ZYX) {
-
-              // r (Cartesian3D.plusK) coordinates are :
-              //  -sin (theta), cos (theta) sin (phi), cos (theta) cos (phi)
-              // (-r) (Cartesian3D.plusI) coordinates are :
-              // cos (psi) cos (theta), sin (psi) cos (theta), -sin (theta)
-              // and we can choose to have theta in the interval [-PI/2 ; +PI/2]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_K);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_I);
-              if  ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(true);
-              }
-              return new double[] {
-                  FastMath.atan2(v2.getY(), v2.getX()),
-                 -FastMath.asin(v2.getZ()),
-                  FastMath.atan2(v1.getY(), v1.getZ())
-              };
-
-          } else if (order == RotationOrder.XYX) {
-
-              // r (Cartesian3D.plusI) coordinates are :
-              //  cos (theta), sin (phi2) sin (theta), cos (phi2) sin (theta)
-              // (-r) (Cartesian3D.plusI) coordinates are :
-              // cos (theta), sin (theta) sin (phi1), -sin (theta) cos (phi1)
-              // and we can choose to have theta in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_I);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_I);
-              if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v2.getY(), -v2.getZ()),
-                  FastMath.acos(v2.getX()),
-                  FastMath.atan2(v1.getY(), v1.getZ())
-              };
-
-          } else if (order == RotationOrder.XZX) {
-
-              // r (Cartesian3D.plusI) coordinates are :
-              //  cos (psi), -cos (phi2) sin (psi), sin (phi2) sin (psi)
-              // (-r) (Cartesian3D.plusI) coordinates are :
-              // cos (psi), sin (psi) cos (phi1), sin (psi) sin (phi1)
-              // and we can choose to have psi in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_I);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_I);
-              if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v2.getZ(), v2.getY()),
-                  FastMath.acos(v2.getX()),
-                  FastMath.atan2(v1.getZ(), -v1.getY())
-              };
-
-          } else if (order == RotationOrder.YXY) {
-
-              // r (Cartesian3D.plusJ) coordinates are :
-              // sin (phi) sin (theta2), cos (phi), -sin (phi) cos (theta2)
-              // (-r) (Cartesian3D.plusJ) coordinates are :
-              //  sin (theta1) sin (phi), cos (phi), cos (theta1) sin (phi)
-              // and we can choose to have phi in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_J);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_J);
-              if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v2.getX(), v2.getZ()),
-                  FastMath.acos(v2.getY()),
-                  FastMath.atan2(v1.getX(), -v1.getZ())
-              };
-
-          } else if (order == RotationOrder.YZY) {
-
-              // r (Cartesian3D.plusJ) coordinates are :
-              // sin (psi) cos (theta2), cos (psi), sin (psi) sin (theta2)
-              // (-r) (Cartesian3D.plusJ) coordinates are :
-              //  -cos (theta1) sin (psi), cos (psi), sin (theta1) sin (psi)
-              // and we can choose to have psi in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_J);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_J);
-              if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v2.getZ(), -v2.getX()),
-                  FastMath.acos(v2.getY()),
-                  FastMath.atan2(v1.getZ(), v1.getX())
-              };
-
-          } else if (order == RotationOrder.ZXZ) {
-
-              // r (Cartesian3D.plusK) coordinates are :
-              // sin (phi) sin (psi2), sin (phi) cos (psi2), cos (phi)
-              // (-r) (Cartesian3D.plusK) coordinates are :
-              //  sin (psi1) sin (phi), -cos (psi1) sin (phi), cos (phi)
-              // and we can choose to have phi in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_K);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_K);
-              if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v2.getX(), -v2.getY()),
-                  FastMath.acos(v2.getZ()),
-                  FastMath.atan2(v1.getX(), v1.getY())
-              };
-
-          } else { // last possibility is ZYZ
-
-              // r (Cartesian3D.plusK) coordinates are :
-              // -sin (theta) cos (psi2), sin (theta) sin (psi2), cos (theta)
-              // (-r) (Cartesian3D.plusK) coordinates are :
-              //  cos (psi1) sin (theta), sin (psi1) sin (theta), cos (theta)
-              // and we can choose to have theta in the interval [0 ; PI]
-              Cartesian3D v1 = applyTo(Cartesian3D.PLUS_K);
-              Cartesian3D v2 = applyInverseTo(Cartesian3D.PLUS_K);
-              if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new CardanEulerSingularityException(false);
-              }
-              return new double[] {
-                  FastMath.atan2(v2.getY(), v2.getX()),
-                  FastMath.acos(v2.getZ()),
-                  FastMath.atan2(v1.getY(), -v1.getX())
-              };
-
-          }
-      }
-
-  }
-
-  /** Get the 3X3 matrix corresponding to the instance
-   * @return the matrix corresponding to the instance
-   */
-  public double[][] getMatrix() {
-
-    // products
-    double q0q0  = q0 * q0;
-    double q0q1  = q0 * q1;
-    double q0q2  = q0 * q2;
-    double q0q3  = q0 * q3;
-    double q1q1  = q1 * q1;
-    double q1q2  = q1 * q2;
-    double q1q3  = q1 * q3;
-    double q2q2  = q2 * q2;
-    double q2q3  = q2 * q3;
-    double q3q3  = q3 * q3;
-
-    // create the matrix
-    double[][] m = new double[3][];
-    m[0] = new double[3];
-    m[1] = new double[3];
-    m[2] = new double[3];
-
-    m [0][0] = 2.0 * (q0q0 + q1q1) - 1.0;
-    m [1][0] = 2.0 * (q1q2 - q0q3);
-    m [2][0] = 2.0 * (q1q3 + q0q2);
-
-    m [0][1] = 2.0 * (q1q2 + q0q3);
-    m [1][1] = 2.0 * (q0q0 + q2q2) - 1.0;
-    m [2][1] = 2.0 * (q2q3 - q0q1);
-
-    m [0][2] = 2.0 * (q1q3 - q0q2);
-    m [1][2] = 2.0 * (q2q3 + q0q1);
-    m [2][2] = 2.0 * (q0q0 + q3q3) - 1.0;
-
-    return m;
-
-  }
-
-  /** Apply the rotation to a vector.
-   * @param u vector to apply the rotation to
-   * @return a new vector which is the image of u by the rotation
-   */
-  public Cartesian3D applyTo(Cartesian3D u) {
-
-    double x = u.getX();
-    double y = u.getY();
-    double z = u.getZ();
-
-    double s = q1 * x + q2 * y + q3 * z;
-
-    return new Cartesian3D(2 * (q0 * (x * q0 - (q2 * z - q3 * y)) + s * q1) - x,
-                        2 * (q0 * (y * q0 - (q3 * x - q1 * z)) + s * q2) - y,
-                        2 * (q0 * (z * q0 - (q1 * y - q2 * x)) + s * q3) - z);
-
-  }
-
-  /** Apply the rotation to a vector stored in an array.
-   * @param in an array with three items which stores vector to rotate
-   * @param out an array with three items to put result to (it can be the same
-   * array as in)
-   */
-  public void applyTo(final double[] in, final double[] out) {
-
-      final double x = in[0];
-      final double y = in[1];
-      final double z = in[2];
-
-      final double s = q1 * x + q2 * y + q3 * z;
-
-      out[0] = 2 * (q0 * (x * q0 - (q2 * z - q3 * y)) + s * q1) - x;
-      out[1] = 2 * (q0 * (y * q0 - (q3 * x - q1 * z)) + s * q2) - y;
-      out[2] = 2 * (q0 * (z * q0 - (q1 * y - q2 * x)) + s * q3) - z;
-
-  }
-
-  /** Apply the inverse of the rotation to a vector.
-   * @param u vector to apply the inverse of the rotation to
-   * @return a new vector which such that u is its image by the rotation
-   */
-  public Cartesian3D applyInverseTo(Cartesian3D u) {
-
-    double x = u.getX();
-    double y = u.getY();
-    double z = u.getZ();
-
-    double s = q1 * x + q2 * y + q3 * z;
-    double m0 = -q0;
-
-    return new Cartesian3D(2 * (m0 * (x * m0 - (q2 * z - q3 * y)) + s * q1) - x,
-                        2 * (m0 * (y * m0 - (q3 * x - q1 * z)) + s * q2) - y,
-                        2 * (m0 * (z * m0 - (q1 * y - q2 * x)) + s * q3) - z);
-
-  }
-
-  /** Apply the inverse of the rotation to a vector stored in an array.
-   * @param in an array with three items which stores vector to rotate
-   * @param out an array with three items to put result to (it can be the same
-   * array as in)
-   */
-  public void applyInverseTo(final double[] in, final double[] out) {
-
-      final double x = in[0];
-      final double y = in[1];
-      final double z = in[2];
-
-      final double s = q1 * x + q2 * y + q3 * z;
-      final double m0 = -q0;
-
-      out[0] = 2 * (m0 * (x * m0 - (q2 * z - q3 * y)) + s * q1) - x;
-      out[1] = 2 * (m0 * (y * m0 - (q3 * x - q1 * z)) + s * q2) - y;
-      out[2] = 2 * (m0 * (z * m0 - (q1 * y - q2 * x)) + s * q3) - z;
-
-  }
-
-  /** Apply the instance to another rotation.
-   * <p>
-   * Calling this method is equivalent to call
-   * {@link #compose(Rotation, RotationConvention)
-   * compose(r, RotationConvention.VECTOR_OPERATOR)}.
-   * </p>
-   * @param r rotation to apply the rotation to
-   * @return a new rotation which is the composition of r by the instance
-   */
-  public Rotation applyTo(Rotation r) {
-    return compose(r, RotationConvention.VECTOR_OPERATOR);
-  }
-
-  /** Compose the instance with another rotation.
-   * <p>
-   * If the semantics of the rotations composition corresponds to a
-   * {@link RotationConvention#VECTOR_OPERATOR vector operator} convention,
-   * applying the instance to a rotation is computing the composition
-   * in an order compliant with the following rule : let {@code u} be any
-   * vector and {@code v} its image by {@code r1} (i.e.
-   * {@code r1.applyTo(u) = v}). Let {@code w} be the image of {@code v} by
-   * rotation {@code r2} (i.e. {@code r2.applyTo(v) = w}). Then
-   * {@code w = comp.applyTo(u)}, where
-   * {@code comp = r2.compose(r1, RotationConvention.VECTOR_OPERATOR)}.
-   * </p>
-   * <p>
-   * If the semantics of the rotations composition corresponds to a
-   * {@link RotationConvention#FRAME_TRANSFORM frame transform} convention,
-   * the application order will be reversed. So keeping the exact same
-   * meaning of all {@code r1}, {@code r2}, {@code u}, {@code v}, {@code w}
-   * and  {@code comp} as above, {@code comp} could also be computed as
-   * {@code comp = r1.compose(r2, RotationConvention.FRAME_TRANSFORM)}.
-   * </p>
-   * @param r rotation to apply the rotation to
-   * @param convention convention to use for the semantics of the angle
-   * @return a new rotation which is the composition of r by the instance
-   */
-  public Rotation compose(final Rotation r, final RotationConvention convention) {
-    return convention == RotationConvention.VECTOR_OPERATOR ?
-           composeInternal(r) : r.composeInternal(this);
-  }
-
-  /** Compose the instance with another rotation using vector operator convention.
-   * @param r rotation to apply the rotation to
-   * @return a new rotation which is the composition of r by the instance
-   * using vector operator convention
-   */
-  private Rotation composeInternal(final Rotation r) {
-    return new Rotation(r.q0 * q0 - (r.q1 * q1 + r.q2 * q2 + r.q3 * q3),
-                        r.q1 * q0 + r.q0 * q1 + (r.q2 * q3 - r.q3 * q2),
-                        r.q2 * q0 + r.q0 * q2 + (r.q3 * q1 - r.q1 * q3),
-                        r.q3 * q0 + r.q0 * q3 + (r.q1 * q2 - r.q2 * q1),
-                        false);
-  }
-
-  /** Apply the inverse of the instance to another rotation.
-   * <p>
-   * Calling this method is equivalent to call
-   * {@link #composeInverse(Rotation, RotationConvention)
-   * composeInverse(r, RotationConvention.VECTOR_OPERATOR)}.
-   * </p>
-   * @param r rotation to apply the rotation to
-   * @return a new rotation which is the composition of r by the inverse
-   * of the instance
-   */
-  public Rotation applyInverseTo(Rotation r) {
-    return composeInverse(r, RotationConvention.VECTOR_OPERATOR);
-  }
-
-  /** Compose the inverse of the instance with another rotation.
-   * <p>
-   * If the semantics of the rotations composition corresponds to a
-   * {@link RotationConvention#VECTOR_OPERATOR vector operator} convention,
-   * applying the inverse of the instance to a rotation is computing
-   * the composition in an order compliant with the following rule :
-   * let {@code u} be any vector and {@code v} its image by {@code r1}
-   * (i.e. {@code r1.applyTo(u) = v}). Let {@code w} be the inverse image
-   * of {@code v} by {@code r2} (i.e. {@code r2.applyInverseTo(v) = w}).
-   * Then {@code w = comp.applyTo(u)}, where
-   * {@code comp = r2.composeInverse(r1)}.
-   * </p>
-   * <p>
-   * If the semantics of the rotations composition corresponds to a
-   * {@link RotationConvention#FRAME_TRANSFORM frame transform} convention,
-   * the application order will be reversed, which means it is the
-   * <em>innermost</em> rotation that will be reversed. So keeping the exact same
-   * meaning of all {@code r1}, {@code r2}, {@code u}, {@code v}, {@code w}
-   * and  {@code comp} as above, {@code comp} could also be computed as
-   * {@code comp = r1.revert().composeInverse(r2.revert(), RotationConvention.FRAME_TRANSFORM)}.
-   * </p>
-   * @param r rotation to apply the rotation to
-   * @param convention convention to use for the semantics of the angle
-   * @return a new rotation which is the composition of r by the inverse
-   * of the instance
-   */
-  public Rotation composeInverse(final Rotation r, final RotationConvention convention) {
-    return convention == RotationConvention.VECTOR_OPERATOR ?
-           composeInverseInternal(r) : r.composeInternal(revert());
-  }
-
-  /** Compose the inverse of the instance with another rotation
-   * using vector operator convention.
-   * @param r rotation to apply the rotation to
-   * @return a new rotation which is the composition of r by the inverse
-   * of the instance using vector operator convention
-   */
-  private Rotation composeInverseInternal(Rotation r) {
-    return new Rotation(-r.q0 * q0 - (r.q1 * q1 + r.q2 * q2 + r.q3 * q3),
-                        -r.q1 * q0 + r.q0 * q1 + (r.q2 * q3 - r.q3 * q2),
-                        -r.q2 * q0 + r.q0 * q2 + (r.q3 * q1 - r.q1 * q3),
-                        -r.q3 * q0 + r.q0 * q3 + (r.q1 * q2 - r.q2 * q1),
-                        false);
-  }
-
-  /** Perfect orthogonality on a 3X3 matrix.
-   * @param m initial matrix (not exactly orthogonal)
-   * @param threshold convergence threshold for the iterative
-   * orthogonality correction (convergence is reached when the
-   * difference between two steps of the Frobenius norm of the
-   * correction is below this threshold)
-   * @return an orthogonal matrix close to m
-   * @exception NotARotationMatrixException if the matrix cannot be
-   * orthogonalized with the given threshold after 10 iterations
-   */
-  private double[][] orthogonalizeMatrix(double[][] m, double threshold)
-    throws NotARotationMatrixException {
-    double[] m0 = m[0];
-    double[] m1 = m[1];
-    double[] m2 = m[2];
-    double x00 = m0[0];
-    double x01 = m0[1];
-    double x02 = m0[2];
-    double x10 = m1[0];
-    double x11 = m1[1];
-    double x12 = m1[2];
-    double x20 = m2[0];
-    double x21 = m2[1];
-    double x22 = m2[2];
-    double fn = 0;
-    double fn1;
-
-    double[][] o = new double[3][3];
-    double[] o0 = o[0];
-    double[] o1 = o[1];
-    double[] o2 = o[2];
-
-    // iterative correction: Xn+1 = Xn - 0.5 * (Xn.Mt.Xn - M)
-    int i = 0;
-    while (++i < 11) {
-
-      // Mt.Xn
-      double mx00 = m0[0] * x00 + m1[0] * x10 + m2[0] * x20;
-      double mx10 = m0[1] * x00 + m1[1] * x10 + m2[1] * x20;
-      double mx20 = m0[2] * x00 + m1[2] * x10 + m2[2] * x20;
-      double mx01 = m0[0] * x01 + m1[0] * x11 + m2[0] * x21;
-      double mx11 = m0[1] * x01 + m1[1] * x11 + m2[1] * x21;
-      double mx21 = m0[2] * x01 + m1[2] * x11 + m2[2] * x21;
-      double mx02 = m0[0] * x02 + m1[0] * x12 + m2[0] * x22;
-      double mx12 = m0[1] * x02 + m1[1] * x12 + m2[1] * x22;
-      double mx22 = m0[2] * x02 + m1[2] * x12 + m2[2] * x22;
-
-      // Xn+1
-      o0[0] = x00 - 0.5 * (x00 * mx00 + x01 * mx10 + x02 * mx20 - m0[0]);
-      o0[1] = x01 - 0.5 * (x00 * mx01 + x01 * mx11 + x02 * mx21 - m0[1]);
-      o0[2] = x02 - 0.5 * (x00 * mx02 + x01 * mx12 + x02 * mx22 - m0[2]);
-      o1[0] = x10 - 0.5 * (x10 * mx00 + x11 * mx10 + x12 * mx20 - m1[0]);
-      o1[1] = x11 - 0.5 * (x10 * mx01 + x11 * mx11 + x12 * mx21 - m1[1]);
-      o1[2] = x12 - 0.5 * (x10 * mx02 + x11 * mx12 + x12 * mx22 - m1[2]);
-      o2[0] = x20 - 0.5 * (x20 * mx00 + x21 * mx10 + x22 * mx20 - m2[0]);
-      o2[1] = x21 - 0.5 * (x20 * mx01 + x21 * mx11 + x22 * mx21 - m2[1]);
-      o2[2] = x22 - 0.5 * (x20 * mx02 + x21 * mx12 + x22 * mx22 - m2[2]);
-
-      // correction on each elements
-      double corr00 = o0[0] - m0[0];
-      double corr01 = o0[1] - m0[1];
-      double corr02 = o0[2] - m0[2];
-      double corr10 = o1[0] - m1[0];
-      double corr11 = o1[1] - m1[1];
-      double corr12 = o1[2] - m1[2];
-      double corr20 = o2[0] - m2[0];
-      double corr21 = o2[1] - m2[1];
-      double corr22 = o2[2] - m2[2];
-
-      // Frobenius norm of the correction
-      fn1 = corr00 * corr00 + corr01 * corr01 + corr02 * corr02 +
-            corr10 * corr10 + corr11 * corr11 + corr12 * corr12 +
-            corr20 * corr20 + corr21 * corr21 + corr22 * corr22;
-
-      // convergence test
-      if (FastMath.abs(fn1 - fn) <= threshold) {
-          return o;
-      }
-
-      // prepare next iteration
-      x00 = o0[0];
-      x01 = o0[1];
-      x02 = o0[2];
-      x10 = o1[0];
-      x11 = o1[1];
-      x12 = o1[2];
-      x20 = o2[0];
-      x21 = o2[1];
-      x22 = o2[2];
-      fn  = fn1;
-
-    }
-
-    // the algorithm did not converge after 10 iterations
-    throw new NotARotationMatrixException(
-            LocalizedFormats.UNABLE_TO_ORTHOGONOLIZE_MATRIX,
-            i - 1);
-  }
-
-  /** Compute the <i>distance</i> between two rotations.
-   * <p>The <i>distance</i> is intended here as a way to check if two
-   * rotations are almost similar (i.e. they transform vectors the same way)
-   * or very different. It is mathematically defined as the angle of
-   * the rotation r that prepended to one of the rotations gives the other
-   * one:</p>
-   * <div style="white-space: pre"><code>
-   *        r<sub>1</sub>(r) = r<sub>2</sub>
-   * </code></div>
-   * <p>This distance is an angle between 0 and &pi;. Its value is the smallest
-   * possible upper bound of the angle in radians between r<sub>1</sub>(v)
-   * and r<sub>2</sub>(v) for all possible vectors v. This upper bound is
-   * reached for some v. The distance is equal to 0 if and only if the two
-   * rotations are identical.</p>
-   * <p>Comparing two rotations should always be done using this value rather
-   * than for example comparing the components of the quaternions. It is much
-   * more stable, and has a geometric meaning. Also comparing quaternions
-   * components is error prone since for example quaternions (0.36, 0.48, -0.48, -0.64)
-   * and (-0.36, -0.48, 0.48, 0.64) represent exactly the same rotation despite
-   * their components are different (they are exact opposites).</p>
-   * @param r1 first rotation
-   * @param r2 second rotation
-   * @return <i>distance</i> between r1 and r2
-   */
-  public static double distance(Rotation r1, Rotation r2) {
-      return r1.composeInverseInternal(r2).getAngle();
-  }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/RotationOrder.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/RotationOrder.java
index 020de0e..9fae622 100644
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/RotationOrder.java
+++ b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/RotationOrder.java
@@ -17,6 +17,8 @@
 
 package org.apache.commons.math4.geometry.euclidean.threed;
 
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+
 /**
  * This class is a utility representing a rotation order specification
  * for Cardan or Euler angles specification.
@@ -35,96 +37,96 @@
      * around Z
      */
     public static final RotationOrder XYZ =
-      new RotationOrder("XYZ", Cartesian3D.PLUS_I, Cartesian3D.PLUS_J, Cartesian3D.PLUS_K);
+      new RotationOrder("XYZ", Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Y, Vector3D.Unit.PLUS_Z);
 
     /** Set of Cardan angles.
      * this ordered set of rotations is around X, then around Z, then
      * around Y
      */
     public static final RotationOrder XZY =
-      new RotationOrder("XZY", Cartesian3D.PLUS_I, Cartesian3D.PLUS_K, Cartesian3D.PLUS_J);
+      new RotationOrder("XZY", Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_Y);
 
     /** Set of Cardan angles.
      * this ordered set of rotations is around Y, then around X, then
      * around Z
      */
     public static final RotationOrder YXZ =
-      new RotationOrder("YXZ", Cartesian3D.PLUS_J, Cartesian3D.PLUS_I, Cartesian3D.PLUS_K);
+      new RotationOrder("YXZ", Vector3D.Unit.PLUS_Y, Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z);
 
     /** Set of Cardan angles.
      * this ordered set of rotations is around Y, then around Z, then
      * around X
      */
     public static final RotationOrder YZX =
-      new RotationOrder("YZX", Cartesian3D.PLUS_J, Cartesian3D.PLUS_K, Cartesian3D.PLUS_I);
+      new RotationOrder("YZX", Vector3D.Unit.PLUS_Y, Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X);
 
     /** Set of Cardan angles.
      * this ordered set of rotations is around Z, then around X, then
      * around Y
      */
     public static final RotationOrder ZXY =
-      new RotationOrder("ZXY", Cartesian3D.PLUS_K, Cartesian3D.PLUS_I, Cartesian3D.PLUS_J);
+      new RotationOrder("ZXY", Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Y);
 
     /** Set of Cardan angles.
      * this ordered set of rotations is around Z, then around Y, then
      * around X
      */
     public static final RotationOrder ZYX =
-      new RotationOrder("ZYX", Cartesian3D.PLUS_K, Cartesian3D.PLUS_J, Cartesian3D.PLUS_I);
+      new RotationOrder("ZYX", Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_Y, Vector3D.Unit.PLUS_X);
 
     /** Set of Euler angles.
      * this ordered set of rotations is around X, then around Y, then
      * around X
      */
     public static final RotationOrder XYX =
-      new RotationOrder("XYX", Cartesian3D.PLUS_I, Cartesian3D.PLUS_J, Cartesian3D.PLUS_I);
+      new RotationOrder("XYX", Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Y, Vector3D.Unit.PLUS_X);
 
     /** Set of Euler angles.
      * this ordered set of rotations is around X, then around Z, then
      * around X
      */
     public static final RotationOrder XZX =
-      new RotationOrder("XZX", Cartesian3D.PLUS_I, Cartesian3D.PLUS_K, Cartesian3D.PLUS_I);
+      new RotationOrder("XZX", Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X);
 
     /** Set of Euler angles.
      * this ordered set of rotations is around Y, then around X, then
      * around Y
      */
     public static final RotationOrder YXY =
-      new RotationOrder("YXY", Cartesian3D.PLUS_J, Cartesian3D.PLUS_I, Cartesian3D.PLUS_J);
+      new RotationOrder("YXY", Vector3D.Unit.PLUS_Y, Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Y);
 
     /** Set of Euler angles.
      * this ordered set of rotations is around Y, then around Z, then
      * around Y
      */
     public static final RotationOrder YZY =
-      new RotationOrder("YZY", Cartesian3D.PLUS_J, Cartesian3D.PLUS_K, Cartesian3D.PLUS_J);
+      new RotationOrder("YZY", Vector3D.Unit.PLUS_Y, Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_Y);
 
     /** Set of Euler angles.
      * this ordered set of rotations is around Z, then around X, then
      * around Z
      */
     public static final RotationOrder ZXZ =
-      new RotationOrder("ZXZ", Cartesian3D.PLUS_K, Cartesian3D.PLUS_I, Cartesian3D.PLUS_K);
+      new RotationOrder("ZXZ", Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z);
 
     /** Set of Euler angles.
      * this ordered set of rotations is around Z, then around Y, then
      * around Z
      */
     public static final RotationOrder ZYZ =
-      new RotationOrder("ZYZ", Cartesian3D.PLUS_K, Cartesian3D.PLUS_J, Cartesian3D.PLUS_K);
+      new RotationOrder("ZYZ", Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_Y, Vector3D.Unit.PLUS_Z);
 
     /** Name of the rotations order. */
     private final String name;
 
     /** Axis of the first rotation. */
-    private final Cartesian3D a1;
+    private final Vector3D a1;
 
     /** Axis of the second rotation. */
-    private final Cartesian3D a2;
+    private final Vector3D a2;
 
     /** Axis of the third rotation. */
-    private final Cartesian3D a3;
+    private final Vector3D a3;
 
     /** Private constructor.
      * This is a utility class that cannot be instantiated by the user,
@@ -135,7 +137,7 @@
      * @param a3 axis of the third rotation
      */
     private RotationOrder(final String name,
-                          final Cartesian3D a1, final Cartesian3D a2, final Cartesian3D a3) {
+                          final Vector3D a1, final Vector3D a2, final Vector3D a3) {
         this.name = name;
         this.a1   = a1;
         this.a2   = a2;
@@ -153,21 +155,21 @@
     /** Get the axis of the first rotation.
      * @return axis of the first rotation
      */
-    public Cartesian3D getA1() {
+    public Vector3D getA1() {
         return a1;
     }
 
     /** Get the axis of the second rotation.
      * @return axis of the second rotation
      */
-    public Cartesian3D getA2() {
+    public Vector3D getA2() {
         return a2;
     }
 
     /** Get the axis of the second rotation.
      * @return axis of the second rotation
      */
-    public Cartesian3D getA3() {
+    public Vector3D getA3() {
         return a3;
     }
 
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Segment.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Segment.java
deleted file mode 100644
index 6ced496..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Segment.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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;
-
-
-/** Simple container for a two-points segment.
- * @since 3.0
- */
-public class Segment {
-
-    /** Start point of the segment. */
-    private final Cartesian3D start;
-
-    /** End point of the segments. */
-    private final Cartesian3D end;
-
-    /** Line containing the segment. */
-    private final Line     line;
-
-    /** Build a segment.
-     * @param start start point of the segment
-     * @param end end point of the segment
-     * @param line line containing the segment
-     */
-    public Segment(final Cartesian3D start, final Cartesian3D end, final Line line) {
-        this.start  = start;
-        this.end    = end;
-        this.line   = line;
-    }
-
-    /** Get the start point of the segment.
-     * @return start point of the segment
-     */
-    public Cartesian3D getStart() {
-        return start;
-    }
-
-    /** Get the end point of the segment.
-     * @return end point of the segment
-     */
-    public Cartesian3D getEnd() {
-        return end;
-    }
-
-    /** Get the line containing the segment.
-     * @return line containing the segment
-     */
-    public Line getLine() {
-        return line;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SphereGenerator.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SphereGenerator.java
deleted file mode 100644
index 8ed5a6a..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SphereGenerator.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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.util.Arrays;
-import java.util.List;
-
-import org.apache.commons.math4.fraction.BigFraction;
-import org.apache.commons.math4.geometry.enclosing.EnclosingBall;
-import org.apache.commons.math4.geometry.enclosing.SupportBallGenerator;
-import org.apache.commons.math4.geometry.euclidean.twod.DiskGenerator;
-import org.apache.commons.math4.geometry.euclidean.twod.Euclidean2D;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.math4.util.FastMath;
-
-/** Class generating an enclosing ball from its support points.
- * @since 3.3
- */
-public class SphereGenerator implements SupportBallGenerator<Euclidean3D, Cartesian3D> {
-
-    /** {@inheritDoc} */
-    @Override
-    public EnclosingBall<Euclidean3D, Cartesian3D> ballOnSupport(final List<Cartesian3D> support) {
-
-        if (support.size() < 1) {
-            return new EnclosingBall<>(Cartesian3D.ZERO, Double.NEGATIVE_INFINITY);
-        } else {
-            final Cartesian3D vA = support.get(0);
-            if (support.size() < 2) {
-                return new EnclosingBall<>(vA, 0, vA);
-            } else {
-                final Cartesian3D vB = support.get(1);
-                if (support.size() < 3) {
-                    return new EnclosingBall<>(new Cartesian3D(0.5, vA, 0.5, vB),
-                                                                    0.5 * vA.distance(vB),
-                                                                    vA, vB);
-                } else {
-                    final Cartesian3D vC = support.get(2);
-                    if (support.size() < 4) {
-
-                        // delegate to 2D disk generator
-                        final Plane p = new Plane(vA, vB, vC,
-                                                  1.0e-10 * (vA.getNorm1() + vB.getNorm1() + vC.getNorm1()));
-                        final EnclosingBall<Euclidean2D, Cartesian2D> disk =
-                                new DiskGenerator().ballOnSupport(Arrays.asList(p.toSubSpace(vA),
-                                                                                p.toSubSpace(vB),
-                                                                                p.toSubSpace(vC)));
-
-                        // convert back to 3D
-                        return new EnclosingBall<>(p.toSpace(disk.getCenter()),
-                                                                        disk.getRadius(), vA, vB, vC);
-
-                    } else {
-                        final Cartesian3D vD = support.get(3);
-                        // a sphere is 3D can be defined as:
-                        // (1)   (x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 = r^2
-                        // which can be written:
-                        // (2)   (x^2 + y^2 + z^2) - 2 x_0 x - 2 y_0 y - 2 z_0 z + (x_0^2 + y_0^2 + z_0^2 - r^2) = 0
-                        // or simply:
-                        // (3)   (x^2 + y^2 + z^2) + a x + b y + c z + d = 0
-                        // with sphere center coordinates -a/2, -b/2, -c/2
-                        // If the sphere exists, a b, c and d are a non zero solution to
-                        // [ (x^2  + y^2  + z^2)    x    y   z    1 ]   [ 1 ]   [ 0 ]
-                        // [ (xA^2 + yA^2 + zA^2)   xA   yA  zA   1 ]   [ a ]   [ 0 ]
-                        // [ (xB^2 + yB^2 + zB^2)   xB   yB  zB   1 ] * [ b ] = [ 0 ]
-                        // [ (xC^2 + yC^2 + zC^2)   xC   yC  zC   1 ]   [ c ]   [ 0 ]
-                        // [ (xD^2 + yD^2 + zD^2)   xD   yD  zD   1 ]   [ d ]   [ 0 ]
-                        // So the determinant of the matrix is zero. Computing this determinant
-                        // by expanding it using the minors m_ij of first row leads to
-                        // (4)   m_11 (x^2 + y^2 + z^2) - m_12 x + m_13 y - m_14 z + m_15 = 0
-                        // So by identifying equations (2) and (4) we get the coordinates
-                        // of center as:
-                        //      x_0 = +m_12 / (2 m_11)
-                        //      y_0 = -m_13 / (2 m_11)
-                        //      z_0 = +m_14 / (2 m_11)
-                        // Note that the minors m_11, m_12, m_13 and m_14 all have the last column
-                        // filled with 1.0, hence simplifying the computation
-                        final BigFraction[] c2 = new BigFraction[] {
-                            new BigFraction(vA.getX()), new BigFraction(vB.getX()),
-                            new BigFraction(vC.getX()), new BigFraction(vD.getX())
-                        };
-                        final BigFraction[] c3 = new BigFraction[] {
-                            new BigFraction(vA.getY()), new BigFraction(vB.getY()),
-                            new BigFraction(vC.getY()), new BigFraction(vD.getY())
-                        };
-                        final BigFraction[] c4 = new BigFraction[] {
-                            new BigFraction(vA.getZ()), new BigFraction(vB.getZ()),
-                            new BigFraction(vC.getZ()), new BigFraction(vD.getZ())
-                        };
-                        final BigFraction[] c1 = new BigFraction[] {
-                            c2[0].multiply(c2[0]).add(c3[0].multiply(c3[0])).add(c4[0].multiply(c4[0])),
-                            c2[1].multiply(c2[1]).add(c3[1].multiply(c3[1])).add(c4[1].multiply(c4[1])),
-                            c2[2].multiply(c2[2]).add(c3[2].multiply(c3[2])).add(c4[2].multiply(c4[2])),
-                            c2[3].multiply(c2[3]).add(c3[3].multiply(c3[3])).add(c4[3].multiply(c4[3]))
-                        };
-                        final BigFraction twoM11  = minor(c2, c3, c4).multiply(2);
-                        final BigFraction m12     = minor(c1, c3, c4);
-                        final BigFraction m13     = minor(c1, c2, c4);
-                        final BigFraction m14     = minor(c1, c2, c3);
-                        final BigFraction centerX = m12.divide(twoM11);
-                        final BigFraction centerY = m13.divide(twoM11).negate();
-                        final BigFraction centerZ = m14.divide(twoM11);
-                        final BigFraction dx      = c2[0].subtract(centerX);
-                        final BigFraction dy      = c3[0].subtract(centerY);
-                        final BigFraction dz      = c4[0].subtract(centerZ);
-                        final BigFraction r2      = dx.multiply(dx).add(dy.multiply(dy)).add(dz.multiply(dz));
-                        return new EnclosingBall<>(new Cartesian3D(centerX.doubleValue(),
-                                                                                     centerY.doubleValue(),
-                                                                                     centerZ.doubleValue()),
-                                                                        FastMath.sqrt(r2.doubleValue()),
-                                                                        vA, vB, vC, vD);
-                    }
-                }
-            }
-        }
-    }
-
-    /** Compute a dimension 4 minor, when 4<sup>th</sup> column is known to be filled with 1.0.
-     * @param c1 first column
-     * @param c2 second column
-     * @param c3 third column
-     * @return value of the minor computed has an exact fraction
-     */
-    private BigFraction minor(final BigFraction[] c1, final BigFraction[] c2, final BigFraction[] c3) {
-        return      c2[0].multiply(c3[1]).multiply(c1[2].subtract(c1[3])).
-                add(c2[0].multiply(c3[2]).multiply(c1[3].subtract(c1[1]))).
-                add(c2[0].multiply(c3[3]).multiply(c1[1].subtract(c1[2]))).
-                add(c2[1].multiply(c3[0]).multiply(c1[3].subtract(c1[2]))).
-                add(c2[1].multiply(c3[2]).multiply(c1[0].subtract(c1[3]))).
-                add(c2[1].multiply(c3[3]).multiply(c1[2].subtract(c1[0]))).
-                add(c2[2].multiply(c3[0]).multiply(c1[1].subtract(c1[3]))).
-                add(c2[2].multiply(c3[1]).multiply(c1[3].subtract(c1[0]))).
-                add(c2[2].multiply(c3[3]).multiply(c1[0].subtract(c1[1]))).
-                add(c2[3].multiply(c3[0]).multiply(c1[2].subtract(c1[1]))).
-                add(c2[3].multiply(c3[1]).multiply(c1[0].subtract(c1[2]))).
-                add(c2[3].multiply(c3[2]).multiply(c1[1].subtract(c1[0])));
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SphericalCoordinates.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SphericalCoordinates.java
deleted file mode 100644
index 5f07644..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SphericalCoordinates.java
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * 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.Serializable;
-
-import org.apache.commons.math4.util.FastMath;
-
-/** This class provides conversions related to <a
- * href="http://mathworld.wolfram.com/SphericalCoordinates.html">spherical coordinates</a>.
- * <p>
- * The conventions used here are the mathematical ones, i.e. spherical coordinates are
- * related to Cartesian coordinates as follows:
- * </p>
- * <ul>
- *   <li>x = r cos(&theta;) sin(&Phi;)</li>
- *   <li>y = r sin(&theta;) sin(&Phi;)</li>
- *   <li>z = r cos(&Phi;)</li>
- * </ul>
- * <ul>
- *   <li>r       = &radic;(x<sup>2</sup>+y<sup>2</sup>+z<sup>2</sup>)</li>
- *   <li>&theta; = atan2(y, x)</li>
- *   <li>&Phi;   = acos(z/r)</li>
- * </ul>
- * <p>
- * r is the radius, &theta; is the azimuthal angle in the x-y plane and &Phi; is the polar
- * (co-latitude) angle. These conventions are <em>different</em> from the conventions used
- * in physics (and in particular in spherical harmonics) where the meanings of &theta; and
- * &Phi; are reversed.
- * </p>
- * <p>
- * This class provides conversion of coordinates and also of gradient and Hessian
- * between spherical and Cartesian coordinates.
- * </p>
- * @since 3.2
- */
-public class SphericalCoordinates implements Serializable {
-
-    /** Serializable UID. */
-    private static final long serialVersionUID = 20130206L;
-
-    /** Cartesian coordinates. */
-    private final Cartesian3D v;
-
-    /** Radius. */
-    private final double r;
-
-    /** Azimuthal angle in the x-y plane &theta;. */
-    private final double theta;
-
-    /** Polar angle (co-latitude) &Phi;. */
-    private final double phi;
-
-    /** Jacobian of (r, &theta; &Phi;). */
-    private double[][] jacobian;
-
-    /** Hessian of radius. */
-    private double[][] rHessian;
-
-    /** Hessian of azimuthal angle in the x-y plane &theta;. */
-    private double[][] thetaHessian;
-
-    /** Hessian of polar (co-latitude) angle &Phi;. */
-    private double[][] phiHessian;
-
-    /** Build a spherical coordinates transformer from Cartesian coordinates.
-     * @param v Cartesian coordinates
-     */
-    public SphericalCoordinates(final Cartesian3D v) {
-
-        // Cartesian coordinates
-        this.v = v;
-
-        // remaining spherical coordinates
-        this.r     = v.getNorm();
-        this.theta = v.getAlpha();
-        this.phi   = FastMath.acos(v.getZ() / r);
-
-    }
-
-    /** Build a spherical coordinates transformer from spherical coordinates.
-     * @param r radius
-     * @param theta azimuthal angle in x-y plane
-     * @param phi polar (co-latitude) angle
-     */
-    public SphericalCoordinates(final double r, final double theta, final double phi) {
-
-        final double cosTheta = FastMath.cos(theta);
-        final double sinTheta = FastMath.sin(theta);
-        final double cosPhi   = FastMath.cos(phi);
-        final double sinPhi   = FastMath.sin(phi);
-
-        // spherical coordinates
-        this.r     = r;
-        this.theta = theta;
-        this.phi   = phi;
-
-        // Cartesian coordinates
-        this.v  = new Cartesian3D(r * cosTheta * sinPhi,
-                               r * sinTheta * sinPhi,
-                               r * cosPhi);
-
-    }
-
-    /** Get the Cartesian coordinates.
-     * @return Cartesian coordinates
-     */
-    public Cartesian3D getCartesian() {
-        return v;
-    }
-
-    /** Get the radius.
-     * @return radius r
-     * @see #getTheta()
-     * @see #getPhi()
-     */
-    public double getR() {
-        return r;
-    }
-
-    /** Get the azimuthal angle in x-y plane.
-     * @return azimuthal angle in x-y plane &theta;
-     * @see #getR()
-     * @see #getPhi()
-     */
-    public double getTheta() {
-        return theta;
-    }
-
-    /** Get the polar (co-latitude) angle.
-     * @return polar (co-latitude) angle &Phi;
-     * @see #getR()
-     * @see #getTheta()
-     */
-    public double getPhi() {
-        return phi;
-    }
-
-    /** Convert a gradient with respect to spherical coordinates into a gradient
-     * with respect to Cartesian coordinates.
-     * @param sGradient gradient with respect to spherical coordinates
-     * {df/dr, df/d&theta;, df/d&Phi;}
-     * @return gradient with respect to Cartesian coordinates
-     * {df/dx, df/dy, df/dz}
-     */
-    public double[] toCartesianGradient(final double[] sGradient) {
-
-        // lazy evaluation of Jacobian
-        computeJacobian();
-
-        // compose derivatives as gradient^T . J
-        // the expressions have been simplified since we know jacobian[1][2] = dTheta/dZ = 0
-        return new double[] {
-            sGradient[0] * jacobian[0][0] + sGradient[1] * jacobian[1][0] + sGradient[2] * jacobian[2][0],
-            sGradient[0] * jacobian[0][1] + sGradient[1] * jacobian[1][1] + sGradient[2] * jacobian[2][1],
-            sGradient[0] * jacobian[0][2]                                 + sGradient[2] * jacobian[2][2]
-        };
-
-    }
-
-    /** Convert a Hessian with respect to spherical coordinates into a Hessian
-     * with respect to Cartesian coordinates.
-     * <p>
-     * As Hessian are always symmetric, we use only the lower left part of the provided
-     * spherical Hessian, so the upper part may not be initialized. However, we still
-     * do fill up the complete array we create, with guaranteed symmetry.
-     * </p>
-     * @param sHessian Hessian with respect to spherical coordinates
-     * {{d<sup>2</sup>f/dr<sup>2</sup>, d<sup>2</sup>f/drd&theta;, d<sup>2</sup>f/drd&Phi;},
-     *  {d<sup>2</sup>f/drd&theta;, d<sup>2</sup>f/d&theta;<sup>2</sup>, d<sup>2</sup>f/d&theta;d&Phi;},
-     *  {d<sup>2</sup>f/drd&Phi;, d<sup>2</sup>f/d&theta;d&Phi;, d<sup>2</sup>f/d&Phi;<sup>2</sup>}
-     * @param sGradient gradient with respect to spherical coordinates
-     * {df/dr, df/d&theta;, df/d&Phi;}
-     * @return Hessian with respect to Cartesian coordinates
-     * {{d<sup>2</sup>f/dx<sup>2</sup>, d<sup>2</sup>f/dxdy, d<sup>2</sup>f/dxdz},
-     *  {d<sup>2</sup>f/dxdy, d<sup>2</sup>f/dy<sup>2</sup>, d<sup>2</sup>f/dydz},
-     *  {d<sup>2</sup>f/dxdz, d<sup>2</sup>f/dydz, d<sup>2</sup>f/dz<sup>2</sup>}}
-     */
-    public double[][] toCartesianHessian(final double[][] sHessian, final double[] sGradient) {
-
-        computeJacobian();
-        computeHessians();
-
-        // compose derivative as J^T . H_f . J + df/dr H_r + df/dtheta H_theta + df/dphi H_phi
-        // the expressions have been simplified since we know jacobian[1][2] = dTheta/dZ = 0
-        // and H_theta is only a 2x2 matrix as it does not depend on z
-        final double[][] hj = new double[3][3];
-        final double[][] cHessian = new double[3][3];
-
-        // compute H_f . J
-        // beware we use ONLY the lower-left part of sHessian
-        hj[0][0] = sHessian[0][0] * jacobian[0][0] + sHessian[1][0] * jacobian[1][0] + sHessian[2][0] * jacobian[2][0];
-        hj[0][1] = sHessian[0][0] * jacobian[0][1] + sHessian[1][0] * jacobian[1][1] + sHessian[2][0] * jacobian[2][1];
-        hj[0][2] = sHessian[0][0] * jacobian[0][2]                                   + sHessian[2][0] * jacobian[2][2];
-        hj[1][0] = sHessian[1][0] * jacobian[0][0] + sHessian[1][1] * jacobian[1][0] + sHessian[2][1] * jacobian[2][0];
-        hj[1][1] = sHessian[1][0] * jacobian[0][1] + sHessian[1][1] * jacobian[1][1] + sHessian[2][1] * jacobian[2][1];
-        // don't compute hj[1][2] as it is not used below
-        hj[2][0] = sHessian[2][0] * jacobian[0][0] + sHessian[2][1] * jacobian[1][0] + sHessian[2][2] * jacobian[2][0];
-        hj[2][1] = sHessian[2][0] * jacobian[0][1] + sHessian[2][1] * jacobian[1][1] + sHessian[2][2] * jacobian[2][1];
-        hj[2][2] = sHessian[2][0] * jacobian[0][2]                                   + sHessian[2][2] * jacobian[2][2];
-
-        // compute lower-left part of J^T . H_f . J
-        cHessian[0][0] = jacobian[0][0] * hj[0][0] + jacobian[1][0] * hj[1][0] + jacobian[2][0] * hj[2][0];
-        cHessian[1][0] = jacobian[0][1] * hj[0][0] + jacobian[1][1] * hj[1][0] + jacobian[2][1] * hj[2][0];
-        cHessian[2][0] = jacobian[0][2] * hj[0][0]                             + jacobian[2][2] * hj[2][0];
-        cHessian[1][1] = jacobian[0][1] * hj[0][1] + jacobian[1][1] * hj[1][1] + jacobian[2][1] * hj[2][1];
-        cHessian[2][1] = jacobian[0][2] * hj[0][1]                             + jacobian[2][2] * hj[2][1];
-        cHessian[2][2] = jacobian[0][2] * hj[0][2]                             + jacobian[2][2] * hj[2][2];
-
-        // add gradient contribution
-        cHessian[0][0] += sGradient[0] * rHessian[0][0] + sGradient[1] * thetaHessian[0][0] + sGradient[2] * phiHessian[0][0];
-        cHessian[1][0] += sGradient[0] * rHessian[1][0] + sGradient[1] * thetaHessian[1][0] + sGradient[2] * phiHessian[1][0];
-        cHessian[2][0] += sGradient[0] * rHessian[2][0]                                     + sGradient[2] * phiHessian[2][0];
-        cHessian[1][1] += sGradient[0] * rHessian[1][1] + sGradient[1] * thetaHessian[1][1] + sGradient[2] * phiHessian[1][1];
-        cHessian[2][1] += sGradient[0] * rHessian[2][1]                                     + sGradient[2] * phiHessian[2][1];
-        cHessian[2][2] += sGradient[0] * rHessian[2][2]                                     + sGradient[2] * phiHessian[2][2];
-
-        // ensure symmetry
-        cHessian[0][1] = cHessian[1][0];
-        cHessian[0][2] = cHessian[2][0];
-        cHessian[1][2] = cHessian[2][1];
-
-        return cHessian;
-
-    }
-
-    /** Lazy evaluation of (r, &theta;, &phi;) Jacobian.
-     */
-    private void computeJacobian() {
-        if (jacobian == null) {
-
-            // intermediate variables
-            final double x    = v.getX();
-            final double y    = v.getY();
-            final double z    = v.getZ();
-            final double rho2 = x * x + y * y;
-            final double rho  = FastMath.sqrt(rho2);
-            final double r2   = rho2 + z * z;
-
-            jacobian = new double[3][3];
-
-            // row representing the gradient of r
-            jacobian[0][0] = x / r;
-            jacobian[0][1] = y / r;
-            jacobian[0][2] = z / r;
-
-            // row representing the gradient of theta
-            jacobian[1][0] = -y / rho2;
-            jacobian[1][1] =  x / rho2;
-            // jacobian[1][2] is already set to 0 at allocation time
-
-            // row representing the gradient of phi
-            jacobian[2][0] = x * z / (rho * r2);
-            jacobian[2][1] = y * z / (rho * r2);
-            jacobian[2][2] = -rho / r2;
-
-        }
-    }
-
-    /** Lazy evaluation of Hessians.
-     */
-    private void computeHessians() {
-
-        if (rHessian == null) {
-
-            // intermediate variables
-            final double x      = v.getX();
-            final double y      = v.getY();
-            final double z      = v.getZ();
-            final double x2     = x * x;
-            final double y2     = y * y;
-            final double z2     = z * z;
-            final double rho2   = x2 + y2;
-            final double rho    = FastMath.sqrt(rho2);
-            final double r2     = rho2 + z2;
-            final double xOr    = x / r;
-            final double yOr    = y / r;
-            final double zOr    = z / r;
-            final double xOrho2 = x / rho2;
-            final double yOrho2 = y / rho2;
-            final double xOr3   = xOr / r2;
-            final double yOr3   = yOr / r2;
-            final double zOr3   = zOr / r2;
-
-            // lower-left part of Hessian of r
-            rHessian = new double[3][3];
-            rHessian[0][0] = y * yOr3 + z * zOr3;
-            rHessian[1][0] = -x * yOr3;
-            rHessian[2][0] = -z * xOr3;
-            rHessian[1][1] = x * xOr3 + z * zOr3;
-            rHessian[2][1] = -y * zOr3;
-            rHessian[2][2] = x * xOr3 + y * yOr3;
-
-            // upper-right part is symmetric
-            rHessian[0][1] = rHessian[1][0];
-            rHessian[0][2] = rHessian[2][0];
-            rHessian[1][2] = rHessian[2][1];
-
-            // lower-left part of Hessian of azimuthal angle theta
-            thetaHessian = new double[2][2];
-            thetaHessian[0][0] = 2 * xOrho2 * yOrho2;
-            thetaHessian[1][0] = yOrho2 * yOrho2 - xOrho2 * xOrho2;
-            thetaHessian[1][1] = -2 * xOrho2 * yOrho2;
-
-            // upper-right part is symmetric
-            thetaHessian[0][1] = thetaHessian[1][0];
-
-            // lower-left part of Hessian of polar (co-latitude) angle phi
-            final double rhor2       = rho * r2;
-            final double rho2r2      = rho * rhor2;
-            final double rhor4       = rhor2 * r2;
-            final double rho3r4      = rhor4 * rho2;
-            final double r2P2rho2    = 3 * rho2 + z2;
-            phiHessian = new double[3][3];
-            phiHessian[0][0] = z * (rho2r2 - x2 * r2P2rho2) / rho3r4;
-            phiHessian[1][0] = -x * y * z * r2P2rho2 / rho3r4;
-            phiHessian[2][0] = x * (rho2 - z2) / rhor4;
-            phiHessian[1][1] = z * (rho2r2 - y2 * r2P2rho2) / rho3r4;
-            phiHessian[2][1] = y * (rho2 - z2) / rhor4;
-            phiHessian[2][2] = 2 * rho * zOr3 / r;
-
-            // upper-right part is symmetric
-            phiHessian[0][1] = phiHessian[1][0];
-            phiHessian[0][2] = phiHessian[2][0];
-            phiHessian[1][2] = phiHessian[2][1];
-
-        }
-
-    }
-
-    /**
-     * Replace the instance with a data transfer object for serialization.
-     * @return data transfer object that will be serialized
-     */
-    private Object writeReplace() {
-        return new DataTransferObject(v.getX(), v.getY(), v.getZ());
-    }
-
-    /** Internal class used only for serialization. */
-    private static class DataTransferObject implements Serializable {
-
-        /** Serializable UID. */
-        private static final long serialVersionUID = 20130206L;
-
-        /** Abscissa.
-         * @serial
-         */
-        private final double x;
-
-        /** Ordinate.
-         * @serial
-         */
-        private final double y;
-
-        /** Height.
-         * @serial
-         */
-        private final double z;
-
-        /** Simple constructor.
-         * @param x abscissa
-         * @param y ordinate
-         * @param z height
-         */
-        DataTransferObject(final double x, final double y, final double z) {
-            this.x = x;
-            this.y = y;
-            this.z = z;
-        }
-
-        /** Replace the deserialized data transfer object with a {@link SphericalCoordinates}.
-         * @return replacement {@link SphericalCoordinates}
-         */
-        private Object readResolve() {
-            return new SphericalCoordinates(new Cartesian3D(x, y, z));
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SubLine.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SubLine.java
deleted file mode 100644
index 8eab249..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SubLine.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.euclidean.oned.Euclidean1D;
-import org.apache.commons.math4.geometry.euclidean.oned.Interval;
-import org.apache.commons.math4.geometry.euclidean.oned.IntervalsSet;
-import org.apache.commons.math4.geometry.euclidean.oned.Cartesian1D;
-import org.apache.commons.math4.geometry.partitioning.Region.Location;
-
-/** This class represents a subset of a {@link Line}.
- * @since 3.0
- */
-public class SubLine {
-
-    /** Underlying line. */
-    private final Line line;
-
-    /** Remaining region of the hyperplane. */
-    private final IntervalsSet remainingRegion;
-
-    /** Simple constructor.
-     * @param line underlying line
-     * @param remainingRegion remaining region of the line
-     */
-    public SubLine(final Line line, final IntervalsSet remainingRegion) {
-        this.line            = line;
-        this.remainingRegion = remainingRegion;
-    }
-
-    /** Create a sub-line from two endpoints.
-     * @param start start point
-     * @param end end point
-     * @param tolerance tolerance below which points are considered identical
-     * @exception MathIllegalArgumentException if the points are equal
-     * @since 3.3
-     */
-    public SubLine(final Cartesian3D start, final Cartesian3D end, final double tolerance)
-        throws MathIllegalArgumentException {
-        this(new Line(start, end, tolerance), buildIntervalSet(start, end, tolerance));
-    }
-
-    /** Create a sub-line from a segment.
-     * @param segment single segment forming the sub-line
-     * @exception MathIllegalArgumentException if the segment endpoints are equal
-     */
-    public SubLine(final Segment segment) throws MathIllegalArgumentException {
-        this(segment.getLine(),
-             buildIntervalSet(segment.getStart(), segment.getEnd(), segment.getLine().getTolerance()));
-    }
-
-    /** Get the endpoints of the sub-line.
-     * <p>
-     * A subline may be any arbitrary number of disjoints segments, so the endpoints
-     * are provided as a list of endpoint pairs. Each element of the list represents
-     * one segment, and each segment contains a start point at index 0 and an end point
-     * at index 1. If the sub-line is unbounded in the negative infinity direction,
-     * the start point of the first segment will have infinite coordinates. If the
-     * sub-line is unbounded in the positive infinity direction, the end point of the
-     * last segment will have infinite coordinates. So a sub-line covering the whole
-     * line will contain just one row and both elements of this row will have infinite
-     * coordinates. If the sub-line is empty, the returned list will contain 0 segments.
-     * </p>
-     * @return list of segments endpoints
-     */
-    public List<Segment> getSegments() {
-
-        final List<Interval> list = remainingRegion.asList();
-        final List<Segment> segments = new ArrayList<>(list.size());
-
-        for (final Interval interval : list) {
-            final Cartesian3D start = line.toSpace(new Cartesian1D(interval.getInf()));
-            final Cartesian3D end   = line.toSpace(new Cartesian1D(interval.getSup()));
-            segments.add(new Segment(start, end, line));
-        }
-
-        return segments;
-
-    }
-
-    /** Get the intersection of the instance and another sub-line.
-     * <p>
-     * This method is related to the {@link Line#intersection(Line)
-     * intersection} method in the {@link Line Line} class, but in addition
-     * to compute the point along infinite lines, it also checks the point
-     * lies on both sub-line ranges.
-     * </p>
-     * @param subLine other sub-line which may intersect instance
-     * @param includeEndPoints if true, endpoints are considered to belong to
-     * instance (i.e. they are closed sets) and may be returned, otherwise endpoints
-     * are considered to not belong to instance (i.e. they are open sets) and intersection
-     * occurring on endpoints lead to null being returned
-     * @return the intersection point if there is one, null if the sub-lines don't intersect
-     */
-    public Cartesian3D intersection(final SubLine subLine, final boolean includeEndPoints) {
-
-        // compute the intersection on infinite line
-        Cartesian3D v1D = line.intersection(subLine.line);
-        if (v1D == null) {
-            return null;
-        }
-
-        // check location of point with respect to first sub-line
-        Location loc1 = remainingRegion.checkPoint((Point<Euclidean1D>) line.toSubSpace((Point<Euclidean3D>) v1D));
-
-        // check location of point with respect to second sub-line
-        Location loc2 = subLine.remainingRegion.checkPoint((Point<Euclidean1D>) subLine.line.toSubSpace((Point<Euclidean3D>) v1D));
-
-        if (includeEndPoints) {
-            return ((loc1 != Location.OUTSIDE) && (loc2 != Location.OUTSIDE)) ? v1D : null;
-        } else {
-            return ((loc1 == Location.INSIDE) && (loc2 == Location.INSIDE)) ? v1D : null;
-        }
-
-    }
-
-    /** Build an interval set from two points.
-     * @param start start point
-     * @param end end point
-     * @return an interval set
-     * @param tolerance tolerance below which points are considered identical
-     * @exception MathIllegalArgumentException if the points are equal
-     */
-    private static IntervalsSet buildIntervalSet(final Cartesian3D start, final Cartesian3D end, final double tolerance)
-        throws MathIllegalArgumentException {
-        final Line line = new Line(start, end, tolerance);
-        return new IntervalsSet(line.toSubSpace((Point<Euclidean3D>) start).getX(),
-                                line.toSubSpace((Point<Euclidean3D>) end).getX(),
-                                tolerance);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SubPlane.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SubPlane.java
deleted file mode 100644
index adc6860..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SubPlane.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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 org.apache.commons.math4.geometry.euclidean.oned.Cartesian1D;
-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.Cartesian2D;
-import org.apache.commons.math4.geometry.partitioning.AbstractSubHyperplane;
-import org.apache.commons.math4.geometry.partitioning.BSPTree;
-import org.apache.commons.math4.geometry.partitioning.Hyperplane;
-import org.apache.commons.math4.geometry.partitioning.Region;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-
-/** This class represents a sub-hyperplane for {@link Plane}.
- * @since 3.0
- */
-public class SubPlane extends AbstractSubHyperplane<Euclidean3D, Euclidean2D> {
-
-    /** Simple constructor.
-     * @param hyperplane underlying hyperplane
-     * @param remainingRegion remaining region of the hyperplane
-     */
-    public SubPlane(final Hyperplane<Euclidean3D> hyperplane,
-                    final Region<Euclidean2D> remainingRegion) {
-        super(hyperplane, remainingRegion);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected AbstractSubHyperplane<Euclidean3D, Euclidean2D> buildNew(final Hyperplane<Euclidean3D> hyperplane,
-                                                                       final Region<Euclidean2D> remainingRegion) {
-        return new SubPlane(hyperplane, remainingRegion);
-    }
-
-    /** Split the instance in two parts by an hyperplane.
-     * @param hyperplane splitting hyperplane
-     * @return an object containing both the part of the instance
-     * on the plus side of the instance and the part of the
-     * instance on the minus side of the instance
-     */
-    @Override
-    public SplitSubHyperplane<Euclidean3D> split(Hyperplane<Euclidean3D> hyperplane) {
-
-        final Plane otherPlane = (Plane) hyperplane;
-        final Plane thisPlane  = (Plane) getHyperplane();
-        final Line  inter      = otherPlane.intersection(thisPlane);
-        final double tolerance = thisPlane.getTolerance();
-
-        if (inter == null) {
-            // the hyperplanes are parallel
-            final double global = otherPlane.getOffset(thisPlane);
-            if (global < -tolerance) {
-                return new SplitSubHyperplane<>(null, this);
-            } else if (global > tolerance) {
-                return new SplitSubHyperplane<>(this, null);
-            } else {
-                return new SplitSubHyperplane<>(null, null);
-            }
-        }
-
-        // the hyperplanes do intersect
-        Cartesian2D p = thisPlane.toSubSpace(inter.toSpace(Cartesian1D.ZERO));
-        Cartesian2D q = thisPlane.toSubSpace(inter.toSpace(Cartesian1D.ONE));
-        Cartesian3D crossP = Cartesian3D.crossProduct(inter.getDirection(), thisPlane.getNormal());
-        if (crossP.dotProduct(otherPlane.getNormal()) < 0) {
-            final Cartesian2D tmp = p;
-            p           = q;
-            q           = tmp;
-        }
-        final SubHyperplane<Euclidean2D> l2DMinus =
-            new org.apache.commons.math4.geometry.euclidean.twod.Line(p, q, tolerance).wholeHyperplane();
-        final SubHyperplane<Euclidean2D> l2DPlus =
-            new org.apache.commons.math4.geometry.euclidean.twod.Line(q, p, tolerance).wholeHyperplane();
-
-        final BSPTree<Euclidean2D> splitTree = getRemainingRegion().getTree(false).split(l2DMinus);
-        final BSPTree<Euclidean2D> plusTree  = getRemainingRegion().isEmpty(splitTree.getPlus()) ?
-                                               new BSPTree<Euclidean2D>(Boolean.FALSE) :
-                                               new BSPTree<>(l2DPlus, new BSPTree<Euclidean2D>(Boolean.FALSE),
-                                                                        splitTree.getPlus(), null);
-
-        final BSPTree<Euclidean2D> minusTree = getRemainingRegion().isEmpty(splitTree.getMinus()) ?
-                                               new BSPTree<Euclidean2D>(Boolean.FALSE) :
-                                                   new BSPTree<>(l2DMinus, new BSPTree<Euclidean2D>(Boolean.FALSE),
-                                                                            splitTree.getMinus(), null);
-
-        return new SplitSubHyperplane<>(new SubPlane(thisPlane.copySelf(), new PolygonsSet(plusTree, tolerance)),
-                                                   new SubPlane(thisPlane.copySelf(), new PolygonsSet(minusTree, tolerance)));
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3D.java
deleted file mode 100644
index 15400f7..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3D.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 org.apache.commons.math4.geometry.Vector;
-
-/**
- * This class implements vectors in a three-dimensional space.
- * @since 1.2
- */
-public abstract class Vector3D implements Vector<Euclidean3D> {
-
-    /** Get the abscissa of the vector.
-     * @return abscissa of the vector
-     * @see Cartesian3D#Cartesian3D(double, double, double)
-     */
-    public abstract double getX();
-
-    /** Get the ordinate of the vector.
-     * @return ordinate of the vector
-     * @see Cartesian3D#Cartesian3D(double, double, double)
-     */
-    public abstract double getY();
-
-    /** Get the height of the vector.
-     * @return height of the vector
-     * @see Cartesian3D#Cartesian3D(double, double, double)
-     */
-    public abstract double getZ();
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DFormat.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DFormat.java
deleted file mode 100644
index 1991c53..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DFormat.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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.text.FieldPosition;
-import java.text.NumberFormat;
-import java.text.ParsePosition;
-import java.util.Locale;
-
-import org.apache.commons.math4.exception.MathParseException;
-import org.apache.commons.math4.geometry.Vector;
-import org.apache.commons.math4.geometry.VectorFormat;
-import org.apache.commons.math4.util.CompositeFormat;
-
-/**
- * Formats a 3D vector in components list format "{x; y; z}".
- * <p>The prefix and suffix "{" and "}" and the separator "; " can be replaced by
- * any user-defined strings. The number format for components can be configured.</p>
- * <p>White space is ignored at parse time, even if it is in the prefix, suffix
- * or separator specifications. So even if the default separator does include a space
- * character that is used at format time, both input string "{1;1;1}" and
- * " { 1 ; 1 ; 1 } " will be parsed without error and the same vector will be
- * returned. In the second case, however, the parse position after parsing will be
- * just after the closing curly brace, i.e. just before the trailing space.</p>
- * <p><b>Note:</b> using "," as a separator may interfere with the grouping separator
- * of the default {@link NumberFormat} for the current locale. Thus it is advised
- * to use a {@link NumberFormat} instance with disabled grouping in such a case.</p>
- *
- */
-public class Vector3DFormat extends VectorFormat<Euclidean3D> {
-
-    /**
-     * Create an instance with default settings.
-     * <p>The instance uses the default prefix, suffix and separator:
-     * "{", "}", and "; " and the default number format for components.</p>
-     */
-    public Vector3DFormat() {
-        super(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR,
-              CompositeFormat.getDefaultNumberFormat());
-    }
-
-    /**
-     * Create an instance with a custom number format for components.
-     * @param format the custom format for components.
-     */
-    public Vector3DFormat(final NumberFormat format) {
-        super(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, format);
-    }
-
-    /**
-     * Create an instance with custom prefix, suffix and separator.
-     * @param prefix prefix to use instead of the default "{"
-     * @param suffix suffix to use instead of the default "}"
-     * @param separator separator to use instead of the default "; "
-     */
-    public Vector3DFormat(final String prefix, final String suffix,
-                         final String separator) {
-        super(prefix, suffix, separator, CompositeFormat.getDefaultNumberFormat());
-    }
-
-    /**
-     * Create an instance with custom prefix, suffix, separator and format
-     * for components.
-     * @param prefix prefix to use instead of the default "{"
-     * @param suffix suffix to use instead of the default "}"
-     * @param separator separator to use instead of the default "; "
-     * @param format the custom format for components.
-     */
-    public Vector3DFormat(final String prefix, final String suffix,
-                         final String separator, final NumberFormat format) {
-        super(prefix, suffix, separator, format);
-    }
-
-    /**
-     * Returns the default 3D vector format for the current locale.
-     * @return the default 3D vector format.
-     */
-    public static Vector3DFormat getInstance() {
-        return getInstance(Locale.getDefault());
-    }
-
-    /**
-     * Returns the default 3D vector format for the given locale.
-     * @param locale the specific locale used by the format.
-     * @return the 3D vector format specific to the given locale.
-     */
-    public static Vector3DFormat getInstance(final Locale locale) {
-        return new Vector3DFormat(CompositeFormat.getDefaultNumberFormat(locale));
-    }
-
-    /**
-     * Formats a {@link Vector3D} object to produce a string.
-     * @param vector the object to format.
-     * @param toAppendTo where the text is to be appended
-     * @param pos On input: an alignment field, if desired. On output: the
-     *            offsets of the alignment field
-     * @return the value passed in as toAppendTo.
-     */
-    @Override
-    public StringBuffer format(final Vector<Euclidean3D> vector, final StringBuffer toAppendTo,
-                               final FieldPosition pos) {
-        final Vector3D v3 = (Vector3D) vector;
-        return format(toAppendTo, pos, v3.getX(), v3.getY(), v3.getZ());
-    }
-
-    /**
-     * Parses a string to produce a {@link Vector3D} object.
-     * @param source the string to parse
-     * @return the parsed {@link Vector3D} object.
-     * @throws MathParseException if the beginning of the specified string
-     * cannot be parsed.
-     */
-    @Override
-    public Vector3D parse(final String source) throws MathParseException {
-        ParsePosition parsePosition = new ParsePosition(0);
-        Vector3D result = parse(source, parsePosition);
-        if (parsePosition.getIndex() == 0) {
-            throw new MathParseException(source,
-                                         parsePosition.getErrorIndex(),
-                                         Vector3D.class);
-        }
-        return result;
-    }
-
-    /**
-     * Parses a string to produce a {@link Vector3D} object.
-     * @param source the string to parse
-     * @param pos input/ouput parsing parameter.
-     * @return the parsed {@link Vector3D} object.
-     */
-    @Override
-    public Vector3D parse(final String source, final ParsePosition pos) {
-        final double[] coordinates = parseCoordinates(3, source, pos);
-        if (coordinates == null) {
-            return null;
-        }
-        return new Cartesian3D(coordinates[0], coordinates[1], coordinates[2]);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/package-info.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/package-info.java
deleted file mode 100644
index 92e2739..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- *
- * <p>
- * This package provides basic 3D geometry components.
- * </p>
- *
- */
-package org.apache.commons.math4.geometry.euclidean.threed;
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Cartesian2D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Cartesian2D.java
deleted file mode 100644
index 1198ff6..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Cartesian2D.java
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * 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.twod;
-
-import java.text.NumberFormat;
-
-import org.apache.commons.numbers.arrays.LinearCombination;
-import org.apache.commons.math4.exception.DimensionMismatchException;
-import org.apache.commons.math4.exception.MathArithmeticException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-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.math4.util.MathUtils;
-
-/** This class represents a 2D point or a 2D vector.
- * <p>An instance of Cartesian2D represents the point with the corresponding
- * coordinates.</p>
- * <p>An instance of Cartesian2D also represents the vector which begins at
- * the origin and ends at the point corresponding to the coordinates.</p>
- * <p>Instances of this class are guaranteed to be immutable.</p>
- * @since 4.0
- */
-public class Cartesian2D extends Vector2D implements Point<Euclidean2D> {
-
-    /** Origin (coordinates: 0, 0). */
-    public static final Cartesian2D ZERO   = new Cartesian2D(0, 0);
-
-    // CHECKSTYLE: stop ConstantName
-    /** A vector with all coordinates set to NaN. */
-    public static final Cartesian2D NaN = new Cartesian2D(Double.NaN, Double.NaN);
-    // CHECKSTYLE: resume ConstantName
-
-    /** A vector with all coordinates set to positive infinity. */
-    public static final Cartesian2D POSITIVE_INFINITY =
-        new Cartesian2D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
-
-    /** A vector with all coordinates set to negative infinity. */
-    public static final Cartesian2D NEGATIVE_INFINITY =
-        new Cartesian2D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
-
-    /** Serializable UID. */
-    private static final long serialVersionUID = 266938651998679754L;
-
-    /** Abscissa. */
-    private final double x;
-
-    /** Ordinate. */
-    private final double y;
-
-    /** Simple constructor.
-     * Build a vector from its coordinates
-     * @param x abscissa
-     * @param y ordinate
-     * @see #getX()
-     * @see #getY()
-     */
-    public Cartesian2D(double x, double y) {
-        this.x = x;
-        this.y = y;
-    }
-
-    /** Simple constructor.
-     * Build a vector from its coordinates
-     * @param v coordinates array
-     * @exception DimensionMismatchException if array does not have 2 elements
-     * @see #toArray()
-     */
-    public Cartesian2D(double[] v) throws DimensionMismatchException {
-        if (v.length != 2) {
-            throw new DimensionMismatchException(v.length, 2);
-        }
-        this.x = v[0];
-        this.y = v[1];
-    }
-
-    /** Multiplicative constructor
-     * Build a vector from another one and a scale factor.
-     * The vector built will be a * u
-     * @param a scale factor
-     * @param u base (unscaled) vector
-     */
-    public Cartesian2D(double a, Cartesian2D u) {
-        this.x = a * u.x;
-        this.y = a * u.y;
-    }
-
-    /** Linear constructor
-     * Build a vector from two other ones and corresponding scale factors.
-     * The vector built will be a1 * u1 + a2 * u2
-     * @param a1 first scale factor
-     * @param u1 first base (unscaled) vector
-     * @param a2 second scale factor
-     * @param u2 second base (unscaled) vector
-     */
-    public Cartesian2D(double a1, Cartesian2D u1, double a2, Cartesian2D u2) {
-        this.x = a1 * u1.x + a2 * u2.x;
-        this.y = a1 * u1.y + a2 * u2.y;
-    }
-
-    /** Linear constructor
-     * Build a vector from three other ones and corresponding scale factors.
-     * The vector built will be a1 * u1 + a2 * u2 + a3 * u3
-     * @param a1 first scale factor
-     * @param u1 first base (unscaled) vector
-     * @param a2 second scale factor
-     * @param u2 second base (unscaled) vector
-     * @param a3 third scale factor
-     * @param u3 third base (unscaled) vector
-     */
-    public Cartesian2D(double a1, Cartesian2D u1, double a2, Cartesian2D u2,
-                   double a3, Cartesian2D u3) {
-        this.x = a1 * u1.x + a2 * u2.x + a3 * u3.x;
-        this.y = a1 * u1.y + a2 * u2.y + a3 * u3.y;
-    }
-
-    /** Linear constructor
-     * Build a vector from four other ones and corresponding scale factors.
-     * The vector built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4
-     * @param a1 first scale factor
-     * @param u1 first base (unscaled) vector
-     * @param a2 second scale factor
-     * @param u2 second base (unscaled) vector
-     * @param a3 third scale factor
-     * @param u3 third base (unscaled) vector
-     * @param a4 fourth scale factor
-     * @param u4 fourth base (unscaled) vector
-     */
-    public Cartesian2D(double a1, Cartesian2D u1, double a2, Cartesian2D u2,
-                   double a3, Cartesian2D u3, double a4, Cartesian2D u4) {
-        this.x = a1 * u1.x + a2 * u2.x + a3 * u3.x + a4 * u4.x;
-        this.y = a1 * u1.y + a2 * u2.y + a3 * u3.y + a4 * u4.y;
-    }
-
-    /** Get the abscissa of the vector.
-     * @return abscissa of the vector
-     * @see #Cartesian2D(double, double)
-     */
-    public double getX() {
-        return x;
-    }
-
-    /** Get the ordinate of the vector.
-     * @return ordinate of the vector
-     * @see #Cartesian2D(double, double)
-     */
-    public double getY() {
-        return y;
-    }
-
-    /** Get the vector coordinates as a dimension 2 array.
-     * @return vector coordinates
-     * @see #Cartesian2D(double[])
-     */
-    public double[] toArray() {
-        return new double[] { x, y };
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Space getSpace() {
-        return Euclidean2D.getInstance();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian2D getZero() {
-        return ZERO;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNorm1() {
-        return FastMath.abs(x) + FastMath.abs(y);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNorm() {
-        return FastMath.sqrt (x * x + y * y);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNormSq() {
-        return x * x + y * y;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getNormInf() {
-        return FastMath.max(FastMath.abs(x), FastMath.abs(y));
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian2D add(Vector<Euclidean2D> v) {
-        Cartesian2D v2 = (Cartesian2D) v;
-        return new Cartesian2D(x + v2.getX(), y + v2.getY());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian2D add(double factor, Vector<Euclidean2D> v) {
-        Cartesian2D v2 = (Cartesian2D) v;
-        return new Cartesian2D(x + factor * v2.getX(), y + factor * v2.getY());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian2D subtract(Vector<Euclidean2D> p) {
-        Cartesian2D p3 = (Cartesian2D) p;
-        return new Cartesian2D(x - p3.x, y - p3.y);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian2D subtract(double factor, Vector<Euclidean2D> v) {
-        Cartesian2D v2 = (Cartesian2D) v;
-        return new Cartesian2D(x - factor * v2.getX(), y - factor * v2.getY());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian2D normalize() throws MathArithmeticException {
-        double s = getNorm();
-        if (s == 0) {
-            throw new MathArithmeticException(LocalizedFormats.CANNOT_NORMALIZE_A_ZERO_NORM_VECTOR);
-        }
-        return scalarMultiply(1 / s);
-    }
-
-    /** Compute the angular separation between two vectors.
-     * <p>This method computes the angular separation between two
-     * vectors using the dot product for well separated vectors and the
-     * cross product for almost aligned vectors. This allows to have a
-     * good accuracy in all cases, even for vectors very close to each
-     * other.</p>
-     * @param v1 first vector
-     * @param v2 second vector
-     * @return angular separation between v1 and v2
-     * @exception MathArithmeticException if either vector has a null norm
-     */
-    public static double angle(Cartesian2D v1, Cartesian2D v2) throws MathArithmeticException {
-
-        double normProduct = v1.getNorm() * v2.getNorm();
-        if (normProduct == 0) {
-            throw new MathArithmeticException(LocalizedFormats.ZERO_NORM);
-        }
-
-        double dot = v1.dotProduct(v2);
-        double threshold = normProduct * 0.9999;
-        if ((dot < -threshold) || (dot > threshold)) {
-            // the vectors are almost aligned, compute using the sine
-            final double n = FastMath.abs(LinearCombination.value(v1.x, v2.y, -v1.y, v2.x));
-            if (dot >= 0) {
-                return FastMath.asin(n / normProduct);
-            }
-            return FastMath.PI - FastMath.asin(n / normProduct);
-        }
-
-        // the vectors are sufficiently separated to use the cosine
-        return FastMath.acos(dot / normProduct);
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian2D negate() {
-        return new Cartesian2D(-x, -y);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian2D scalarMultiply(double a) {
-        return new Cartesian2D(a * x, a * y);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isNaN() {
-        return Double.isNaN(x) || Double.isNaN(y);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isInfinite() {
-        return !isNaN() && (Double.isInfinite(x) || Double.isInfinite(y));
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distance1(Vector<Euclidean2D> p) {
-        Cartesian2D p3 = (Cartesian2D) p;
-        final double dx = FastMath.abs(p3.x - x);
-        final double dy = FastMath.abs(p3.y - y);
-        return dx + dy;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distance(Point<Euclidean2D> p) {
-        return distance((Cartesian2D) p);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distance(Vector<Euclidean2D> v) {
-        return distance((Cartesian2D) v);
-    }
-
-    /** Compute the distance between the instance and other coordinates.
-     * @param c other coordinates
-     * @return the distance between the instance and c
-     */
-    public double distance(Cartesian2D c) {
-        final double dx = c.x - x;
-        final double dy = c.y - y;
-        return FastMath.sqrt(dx * dx + dy * dy);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distanceInf(Vector<Euclidean2D> p) {
-        Cartesian2D p3 = (Cartesian2D) p;
-        final double dx = FastMath.abs(p3.x - x);
-        final double dy = FastMath.abs(p3.y - y);
-        return FastMath.max(dx, dy);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distanceSq(Vector<Euclidean2D> p) {
-        Cartesian2D p3 = (Cartesian2D) p;
-        final double dx = p3.x - x;
-        final double dy = p3.y - y;
-        return dx * dx + dy * dy;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double dotProduct(final Vector<Euclidean2D> v) {
-        final Cartesian2D v2 = (Cartesian2D) v;
-        return LinearCombination.value(x, v2.x, y, v2.y);
-    }
-
-    /**
-     * Compute the cross-product of the instance and the given vector.
-     * <p>
-     * The cross product can be used to determine the location of a point
-     * with regard to the line formed by (p1, p2) and is calculated as:
-     * \[
-     *    P = (x_2 - x_1)(y_3 - y_1) - (y_2 - y_1)(x_3 - x_1)
-     * \]
-     * with \(p3 = (x_3, y_3)\) being this instance.
-     * <p>
-     * If the result is 0, the points are collinear, i.e. lie on a single straight line L;
-     * if it is positive, this point lies to the left, otherwise to the right of the line
-     * formed by (p1, p2).
-     *
-     * @param p1 first point of the line
-     * @param p2 second point of the line
-     * @return the cross-product
-     *
-     * @see <a href="http://en.wikipedia.org/wiki/Cross_product">Cross product (Wikipedia)</a>
-     */
-    public double crossProduct(final Cartesian2D p1, final Cartesian2D p2) {
-        final double x1 = p2.getX() - p1.getX();
-        final double y1 = getY() - p1.getY();
-        final double x2 = getX() - p1.getX();
-        final double y2 = p2.getY() - p1.getY();
-        return LinearCombination.value(x1, y1, -x2, y2);
-    }
-
-    /** Compute the distance between two points according to the L<sub>2</sub> norm.
-     * <p>Calling this method is equivalent to calling:
-     * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
-     * vector is built</p>
-     * @param p1 first point
-     * @param p2 second point
-     * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
-     */
-    public static double distance(Cartesian2D p1, Cartesian2D p2) {
-        return p1.distance(p2);
-    }
-
-    /** Compute the distance between two points according to the L<sub>&infin;</sub> norm.
-     * <p>Calling this method is equivalent to calling:
-     * <code>p1.subtract(p2).getNormInf()</code> except that no intermediate
-     * vector is built</p>
-     * @param p1 first point
-     * @param p2 second point
-     * @return the distance between p1 and p2 according to the L<sub>&infin;</sub> norm
-     */
-    public static double distanceInf(Cartesian2D p1, Cartesian2D p2) {
-        return p1.distanceInf(p2);
-    }
-
-    /** Compute the square of the distance between two points.
-     * <p>Calling this method is equivalent to calling:
-     * <code>p1.subtract(p2).getNormSq()</code> except that no intermediate
-     * vector is built</p>
-     * @param p1 first point
-     * @param p2 second point
-     * @return the square of the distance between p1 and p2
-     */
-    public static double distanceSq(Cartesian2D p1, Cartesian2D p2) {
-        return p1.distanceSq(p2);
-    }
-
-    /**
-     * Test for the equality of two 2D instances.
-     * <p>
-     * If all coordinates of two 2D vectors are exactly the same, and none are
-     * <code>Double.NaN</code>, the two 2D instances are considered to be equal.
-     * </p>
-     * <p>
-     * <code>NaN</code> coordinates are considered to affect globally the vector
-     * and be equals to each other - i.e, if either (or all) coordinates of the
-     * 2D vector are equal to <code>Double.NaN</code>, the 2D vector is equal to
-     * {@link #NaN}.
-     * </p>
-     *
-     * @param other Object to test for equality to this
-     * @return true if two 2D Cartesian objects are equal, false if
-     *         object is null, not an instance of Cartesian2D, or
-     *         not equal to this Cartesian2D instance
-     *
-     */
-    @Override
-    public boolean equals(Object other) {
-
-        if (this == other) {
-            return true;
-        }
-
-        if (other instanceof Cartesian2D) {
-            final Cartesian2D rhs = (Cartesian2D)other;
-            if (rhs.isNaN()) {
-                return this.isNaN();
-            }
-
-            return (x == rhs.x) && (y == rhs.y);
-        }
-        return false;
-    }
-
-    /**
-     * Get a hashCode for the 2D coordinates.
-     * <p>
-     * All NaN values have the same hash code.</p>
-     *
-     * @return a hash code value for this object
-     */
-    @Override
-    public int hashCode() {
-        if (isNaN()) {
-            return 542;
-        }
-        return 122 * (76 * MathUtils.hash(x) +  MathUtils.hash(y));
-    }
-
-    /** Get a string representation of this vector.
-     * @return a string representation of this vector
-     */
-    @Override
-    public String toString() {
-        return Vector2DFormat.getInstance().format(this);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public String toString(final NumberFormat format) {
-        return new Vector2DFormat(format).format(this);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/DiskGenerator.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/DiskGenerator.java
deleted file mode 100644
index ba2b7cc..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/DiskGenerator.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.twod;
-
-import java.util.List;
-
-import org.apache.commons.math4.fraction.BigFraction;
-import org.apache.commons.math4.geometry.enclosing.EnclosingBall;
-import org.apache.commons.math4.geometry.enclosing.SupportBallGenerator;
-import org.apache.commons.math4.util.FastMath;
-
-/** Class generating an enclosing ball from its support points.
- * @since 3.3
- */
-public class DiskGenerator implements SupportBallGenerator<Euclidean2D, Cartesian2D> {
-
-    /** {@inheritDoc} */
-    @Override
-    public EnclosingBall<Euclidean2D, Cartesian2D> ballOnSupport(final List<Cartesian2D> support) {
-
-        if (support.size() < 1) {
-            return new EnclosingBall<>(Cartesian2D.ZERO, Double.NEGATIVE_INFINITY);
-        } else {
-            final Cartesian2D vA = support.get(0);
-            if (support.size() < 2) {
-                return new EnclosingBall<>(vA, 0, vA);
-            } else {
-                final Cartesian2D vB = support.get(1);
-                if (support.size() < 3) {
-                    return new EnclosingBall<>(new Cartesian2D(0.5, vA, 0.5, vB),
-                                                                    0.5 * vA.distance(vB),
-                                                                    vA, vB);
-                } else {
-                    final Cartesian2D vC = support.get(2);
-                    // a disk is 2D can be defined as:
-                    // (1)   (x - x_0)^2 + (y - y_0)^2 = r^2
-                    // which can be written:
-                    // (2)   (x^2 + y^2) - 2 x_0 x - 2 y_0 y + (x_0^2 + y_0^2 - r^2) = 0
-                    // or simply:
-                    // (3)   (x^2 + y^2) + a x + b y + c = 0
-                    // with disk center coordinates -a/2, -b/2
-                    // If the disk exists, a, b and c are a non-zero solution to
-                    // [ (x^2  + y^2 )   x    y   1 ]   [ 1 ]   [ 0 ]
-                    // [ (xA^2 + yA^2)   xA   yA  1 ]   [ a ]   [ 0 ]
-                    // [ (xB^2 + yB^2)   xB   yB  1 ] * [ b ] = [ 0 ]
-                    // [ (xC^2 + yC^2)   xC   yC  1 ]   [ c ]   [ 0 ]
-                    // So the determinant of the matrix is zero. Computing this determinant
-                    // by expanding it using the minors m_ij of first row leads to
-                    // (4)   m_11 (x^2 + y^2) - m_12 x + m_13 y - m_14 = 0
-                    // So by identifying equations (2) and (4) we get the coordinates
-                    // of center as:
-                    //      x_0 = +m_12 / (2 m_11)
-                    //      y_0 = -m_13 / (2 m_11)
-                    // Note that the minors m_11, m_12 and m_13 all have the last column
-                    // filled with 1.0, hence simplifying the computation
-                    final BigFraction[] c2 = new BigFraction[] {
-                        new BigFraction(vA.getX()), new BigFraction(vB.getX()), new BigFraction(vC.getX())
-                    };
-                    final BigFraction[] c3 = new BigFraction[] {
-                        new BigFraction(vA.getY()), new BigFraction(vB.getY()), new BigFraction(vC.getY())
-                    };
-                    final BigFraction[] c1 = new BigFraction[] {
-                        c2[0].multiply(c2[0]).add(c3[0].multiply(c3[0])),
-                        c2[1].multiply(c2[1]).add(c3[1].multiply(c3[1])),
-                        c2[2].multiply(c2[2]).add(c3[2].multiply(c3[2]))
-                    };
-                    final BigFraction twoM11  = minor(c2, c3).multiply(2);
-                    final BigFraction m12     = minor(c1, c3);
-                    final BigFraction m13     = minor(c1, c2);
-                    final BigFraction centerX = m12.divide(twoM11);
-                    final BigFraction centerY = m13.divide(twoM11).negate();
-                    final BigFraction dx      = c2[0].subtract(centerX);
-                    final BigFraction dy      = c3[0].subtract(centerY);
-                    final BigFraction r2      = dx.multiply(dx).add(dy.multiply(dy));
-                    return new EnclosingBall<>(new Cartesian2D(centerX.doubleValue(),
-                                                                                 centerY.doubleValue()),
-                                                                    FastMath.sqrt(r2.doubleValue()),
-                                                                    vA, vB, vC);
-                }
-            }
-        }
-    }
-
-    /** Compute a dimension 3 minor, when 3<sup>d</sup> column is known to be filled with 1.0.
-     * @param c1 first column
-     * @param c2 second column
-     * @return value of the minor computed has an exact fraction
-     */
-    private BigFraction minor(final BigFraction[] c1, final BigFraction[] c2) {
-        return      c2[0].multiply(c1[2].subtract(c1[1])).
-                add(c2[1].multiply(c1[0].subtract(c1[2]))).
-                add(c2[2].multiply(c1[1].subtract(c1[0])));
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Euclidean2D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Euclidean2D.java
deleted file mode 100644
index dc30c98..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Euclidean2D.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.twod;
-
-import java.io.Serializable;
-
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.euclidean.oned.Euclidean1D;
-
-/**
- * This class implements a two-dimensional space.
- * @since 3.0
- */
-public class Euclidean2D implements Serializable, Space {
-
-    /** Serializable version identifier. */
-    private static final long serialVersionUID = 4793432849757649566L;
-
-    /** Private constructor for the singleton.
-     */
-    private Euclidean2D() {
-    }
-
-    /** Get the unique instance.
-     * @return the unique instance
-     */
-    public static Euclidean2D getInstance() {
-        return LazyHolder.INSTANCE;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int getDimension() {
-        return 2;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Euclidean1D getSubSpace() {
-        return Euclidean1D.getInstance();
-    }
-
-    // CHECKSTYLE: stop HideUtilityClassConstructor
-    /** Holder for the instance.
-     * <p>We use here the Initialization On Demand Holder Idiom.</p>
-     */
-    private static class LazyHolder {
-        /** Cached field instance. */
-        private static final Euclidean2D INSTANCE = new Euclidean2D();
-    }
-    // CHECKSTYLE: resume HideUtilityClassConstructor
-
-    /** Handle deserialization of the singleton.
-     * @return the singleton instance
-     */
-    private Object readResolve() {
-        // return the singleton instance
-        return LazyHolder.INSTANCE;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Line.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Line.java
deleted file mode 100644
index 670d8f4..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Line.java
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * 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.twod;
-
-import org.apache.commons.numbers.arrays.LinearCombination;
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Vector;
-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.Cartesian1D;
-import org.apache.commons.math4.geometry.partitioning.Embedding;
-import org.apache.commons.math4.geometry.partitioning.Hyperplane;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-import org.apache.commons.math4.geometry.partitioning.Transform;
-import org.apache.commons.math4.util.FastMath;
-
-/** This class represents an oriented line in the 2D plane.
-
- * <p>An oriented line can be defined either by prolongating a line
- * segment between two points past these points, or by one point and
- * an angular direction (in trigonometric orientation).</p>
-
- * <p>Since it is oriented the two half planes at its two sides are
- * unambiguously identified as a left half plane and a right half
- * plane. This can be used to identify the interior and the exterior
- * in a simple way by local properties only when part of a line is
- * used to define part of a polygon boundary.</p>
-
- * <p>A line can also be used to completely define a reference frame
- * in the plane. It is sufficient to select one specific point in the
- * line (the orthogonal projection of the original reference frame on
- * the line) and to use the unit vector in the line direction and the
- * orthogonal vector oriented from left half plane to right half
- * plane. We define two coordinates by the process, the
- * <em>abscissa</em> along the line, and the <em>offset</em> across
- * the line. All points of the plane are uniquely identified by these
- * two coordinates. The line is the set of points at zero offset, the
- * left half plane is the set of points with negative offsets and the
- * right half plane is the set of points with positive offsets.</p>
-
- * @since 3.0
- */
-public class Line implements Hyperplane<Euclidean2D>, Embedding<Euclidean2D, Euclidean1D> {
-    /** Angle with respect to the abscissa axis. */
-    private double angle;
-
-    /** Cosine of the line angle. */
-    private double cos;
-
-    /** Sine of the line angle. */
-    private double sin;
-
-    /** Offset of the frame origin. */
-    private double originOffset;
-
-    /** Tolerance below which points are considered identical. */
-    private final double tolerance;
-
-    /** Reverse line. */
-    private Line reverse;
-
-    /** Build a line from two points.
-     * <p>The line is oriented from p1 to p2</p>
-     * @param p1 first point
-     * @param p2 second point
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public Line(final Cartesian2D p1, final Cartesian2D p2, final double tolerance) {
-        reset(p1, p2);
-        this.tolerance = tolerance;
-    }
-
-    /** Build a line from a point and an angle.
-     * @param p point belonging to the line
-     * @param angle angle of the line with respect to abscissa axis
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public Line(final Cartesian2D p, final double angle, final double tolerance) {
-        reset(p, angle);
-        this.tolerance = tolerance;
-    }
-
-    /** Build a line from its internal characteristics.
-     * @param angle angle of the line with respect to abscissa axis
-     * @param cos cosine of the angle
-     * @param sin sine of the angle
-     * @param originOffset offset of the origin
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    private Line(final double angle, final double cos, final double sin,
-                 final double originOffset, final double tolerance) {
-        this.angle        = angle;
-        this.cos          = cos;
-        this.sin          = sin;
-        this.originOffset = originOffset;
-        this.tolerance    = tolerance;
-        this.reverse      = null;
-    }
-
-    /** Copy constructor.
-     * <p>The created instance is completely independent from the
-     * original instance, it is a deep copy.</p>
-     * @param line line to copy
-     */
-    public Line(final Line line) {
-        angle        = PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(line.angle);
-        cos          = line.cos;
-        sin          = line.sin;
-        originOffset = line.originOffset;
-        tolerance    = line.tolerance;
-        reverse      = null;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Line copySelf() {
-        return new Line(this);
-    }
-
-    /** Reset the instance as if built from two points.
-     * <p>The line is oriented from p1 to p2</p>
-     * @param p1 first point
-     * @param p2 second point
-     */
-    public void reset(final Cartesian2D p1, final Cartesian2D p2) {
-        unlinkReverse();
-        final double dx = p2.getX() - p1.getX();
-        final double dy = p2.getY() - p1.getY();
-        final double d = FastMath.hypot(dx, dy);
-        if (d == 0.0) {
-            angle        = 0.0;
-            cos          = 1.0;
-            sin          = 0.0;
-            originOffset = p1.getY();
-        } else {
-            angle        = FastMath.PI + FastMath.atan2(-dy, -dx);
-            cos          = dx / d;
-            sin          = dy / d;
-            originOffset = LinearCombination.value(p2.getX(), p1.getY(), -p1.getX(), p2.getY()) / d;
-        }
-    }
-
-    /** Reset the instance as if built from a line and an angle.
-     * @param p point belonging to the line
-     * @param alpha angle of the line with respect to abscissa axis
-     */
-    public void reset(final Cartesian2D p, final double alpha) {
-        unlinkReverse();
-        this.angle   = PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(alpha);
-        cos          = FastMath.cos(this.angle);
-        sin          = FastMath.sin(this.angle);
-        originOffset = LinearCombination.value(cos, p.getY(), -sin, p.getX());
-    }
-
-    /** Revert the instance.
-     */
-    public void revertSelf() {
-        unlinkReverse();
-        if (angle < FastMath.PI) {
-            angle += FastMath.PI;
-        } else {
-            angle -= FastMath.PI;
-        }
-        cos          = -cos;
-        sin          = -sin;
-        originOffset = -originOffset;
-    }
-
-    /** Unset the link between an instance and its reverse.
-     */
-    private void unlinkReverse() {
-        if (reverse != null) {
-            reverse.reverse = null;
-        }
-        reverse = null;
-    }
-
-    /** Get the reverse of the instance.
-     * <p>Get a line with reversed orientation with respect to the
-     * instance.</p>
-     * <p>
-     * As long as neither the instance nor its reverse are modified
-     * (i.e. as long as none of the {@link #reset(Cartesian2D, Cartesian2D)},
-     * {@link #reset(Cartesian2D, double)}, {@link #revertSelf()},
-     * {@link #setAngle(double)} or {@link #setOriginOffset(double)}
-     * methods are called), then the line and its reverse remain linked
-     * together so that {@code line.getReverse().getReverse() == line}.
-     * When one of the line is modified, the link is deleted as both
-     * instance becomes independent.
-     * </p>
-     * @return a new line, with orientation opposite to the instance orientation
-     */
-    public Line getReverse() {
-        if (reverse == null) {
-            reverse = new Line((angle < FastMath.PI) ? (angle + FastMath.PI) : (angle - FastMath.PI),
-                               -cos, -sin, -originOffset, tolerance);
-            reverse.reverse = this;
-        }
-        return reverse;
-    }
-
-    /** Transform a space point into a sub-space point.
-     * @param vector n-dimension point of the space
-     * @return (n-1)-dimension point of the sub-space corresponding to
-     * the specified space point
-     */
-    public Cartesian1D toSubSpace(Vector<Euclidean2D> vector) {
-        return toSubSpace((Cartesian2D) vector);
-    }
-
-    /** Transform a sub-space point into a space point.
-     * @param vector (n-1)-dimension point of the sub-space
-     * @return n-dimension point of the space corresponding to the
-     * specified sub-space point
-     */
-    public Cartesian2D toSpace(Vector<Euclidean1D> vector) {
-        return toSpace((Cartesian1D) vector);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian1D toSubSpace(final Point<Euclidean2D> point) {
-        return toSubSpace((Cartesian2D) point);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian2D toSpace(final Point<Euclidean1D> point) {
-        return toSpace((Cartesian1D) point);
-    }
-
-    /** Transform a space point into a sub-space point.
-     * @param cartesian n-dimension point of the space
-     * @return (n-1)-dimension point of the sub-space corresponding to
-     * the specified space point
-     */
-    public Cartesian1D toSubSpace(final Cartesian2D cartesian) {
-        return new Cartesian1D(LinearCombination.value(cos, cartesian.getX(), sin, cartesian.getY()));
-    }
-
-    /** Transform a sub-space point into a space point.
-     * @param cartesian (n-1)-dimension point of the sub-space
-     * @return n-dimension point of the space corresponding to the
-     * specified sub-space point
-     */
-    public Cartesian2D toSpace(Cartesian1D cartesian) {
-        final double abscissa = cartesian.getX();
-        return new Cartesian2D(LinearCombination.value(abscissa, cos, -originOffset, sin),
-                            LinearCombination.value(abscissa, sin,  originOffset, cos));
-    }
-
-    /** Get the intersection point of the instance and another line.
-     * @param other other line
-     * @return intersection point of the instance and the other line
-     * or null if there are no intersection points
-     */
-    public Cartesian2D intersection(final Line other) {
-        final double d = LinearCombination.value(sin, other.cos, -other.sin, cos);
-        if (FastMath.abs(d) < tolerance) {
-            return null;
-        }
-        return new Cartesian2D(LinearCombination.value(cos, other.originOffset, -other.cos, originOffset) / d,
-                            LinearCombination.value(sin, other.originOffset, -other.sin, originOffset) / d);
-    }
-
-    /** {@inheritDoc}
-     * @since 3.3
-     */
-    @Override
-    public Point<Euclidean2D> project(Point<Euclidean2D> point) {
-        return toSpace(toSubSpace(point));
-    }
-
-    /** {@inheritDoc}
-     * @since 3.3
-     */
-    @Override
-    public double getTolerance() {
-        return tolerance;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public SubLine wholeHyperplane() {
-        return new SubLine(this, new IntervalsSet(tolerance));
-    }
-
-    /** Build a region covering the whole space.
-     * @return a region containing the instance (really a {@link
-     * PolygonsSet PolygonsSet} instance)
-     */
-    @Override
-    public PolygonsSet wholeSpace() {
-        return new PolygonsSet(tolerance);
-    }
-
-    /** Get the offset (oriented distance) of a parallel line.
-     * <p>This method should be called only for parallel lines otherwise
-     * the result is not meaningful.</p>
-     * <p>The offset is 0 if both lines are the same, it is
-     * positive if the line is on the right side of the instance and
-     * negative if it is on the left side, according to its natural
-     * orientation.</p>
-     * @param line line to check
-     * @return offset of the line
-     */
-    public double getOffset(final Line line) {
-        return originOffset +
-               (LinearCombination.value(cos, line.cos, sin, line.sin) > 0 ? -line.originOffset : line.originOffset);
-    }
-
-    /** Get the offset (oriented distance) of a vector.
-     * @param vector vector to check
-     * @return offset of the vector
-     */
-    public double getOffset(Vector<Euclidean2D> vector) {
-        return getOffset((Cartesian2D) vector);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getOffset(final Point<Euclidean2D> point) {
-        return getOffset((Cartesian2D) point);
-    }
-
-    /** Get the offset (oriented distance) of a point.
-     * @param cartesian point to check
-     * @return offset of the point
-     */
-    public double getOffset(Cartesian2D cartesian) {
-        return LinearCombination.value(sin, cartesian.getX(), -cos, cartesian.getY(), 1.0, originOffset);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean sameOrientationAs(final Hyperplane<Euclidean2D> other) {
-        final Line otherL = (Line) other;
-        return LinearCombination.value(sin, otherL.sin, cos, otherL.cos) >= 0.0;
-    }
-
-    /** Get one point from the plane.
-     * @param abscissa desired abscissa for the point
-     * @param offset desired offset for the point
-     * @return one point in the plane, with given abscissa and offset
-     * relative to the line
-     */
-    public Cartesian2D getPointAt(final Cartesian1D abscissa, final double offset) {
-        final double x       = abscissa.getX();
-        final double dOffset = offset - originOffset;
-        return new Cartesian2D(LinearCombination.value(x, cos,  dOffset, sin),
-                            LinearCombination.value(x, sin, -dOffset, cos));
-    }
-
-    /** Check if the line contains a point.
-     * @param p point to check
-     * @return true if p belongs to the line
-     */
-    public boolean contains(final Cartesian2D p) {
-        return FastMath.abs(getOffset(p)) < tolerance;
-    }
-
-    /** Compute the distance between the instance and a point.
-     * <p>This is a shortcut for invoking FastMath.abs(getOffset(p)),
-     * and provides consistency with what is in the
-     * org.apache.commons.math4.geometry.euclidean.threed.Line class.</p>
-     *
-     * @param p to check
-     * @return distance between the instance and the point
-     * @since 3.1
-     */
-    public double distance(final Cartesian2D p) {
-        return FastMath.abs(getOffset(p));
-    }
-
-    /** Check the instance is parallel to another line.
-     * @param line other line to check
-     * @return true if the instance is parallel to the other line
-     * (they can have either the same or opposite orientations)
-     */
-    public boolean isParallelTo(final Line line) {
-        return FastMath.abs(LinearCombination.value(sin, line.cos, -cos, line.sin)) < tolerance;
-    }
-
-    /** Translate the line to force it passing by a point.
-     * @param p point by which the line should pass
-     */
-    public void translateToPoint(final Cartesian2D p) {
-        originOffset = LinearCombination.value(cos, p.getY(), -sin, p.getX());
-    }
-
-    /** Get the angle of the line.
-     * @return the angle of the line with respect to the abscissa axis
-     */
-    public double getAngle() {
-        return PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(angle);
-    }
-
-    /** Set the angle of the line.
-     * @param angle new angle of the line with respect to the abscissa axis
-     */
-    public void setAngle(final double angle) {
-        unlinkReverse();
-        this.angle = PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(angle);
-        cos        = FastMath.cos(this.angle);
-        sin        = FastMath.sin(this.angle);
-    }
-
-    /** Get the offset of the origin.
-     * @return the offset of the origin
-     */
-    public double getOriginOffset() {
-        return originOffset;
-    }
-
-    /** Set the offset of the origin.
-     * @param offset offset of the origin
-     */
-    public void setOriginOffset(final double offset) {
-        unlinkReverse();
-        originOffset = offset;
-    }
-
-    /** Get a {@link org.apache.commons.math4.geometry.partitioning.Transform
-     * Transform} embedding an affine transform.
-     * @param cXX transform factor between input abscissa and output abscissa
-     * @param cYX transform factor between input abscissa and output ordinate
-     * @param cXY transform factor between input ordinate and output abscissa
-     * @param cYY transform factor between input ordinate and output ordinate
-     * @param cX1 transform addendum for output abscissa
-     * @param cY1 transform addendum for output ordinate
-     * @return a new transform that can be applied to either {@link
-     * Cartesian2D}, {@link Line Line} or {@link
-     * org.apache.commons.math4.geometry.partitioning.SubHyperplane
-     * SubHyperplane} instances
-     * @exception MathIllegalArgumentException if the transform is non invertible
-     * @since 4.0
-     */
-    public static Transform<Euclidean2D, Euclidean1D> getTransform(final double cXX,
-                                                                   final double cYX,
-                                                                   final double cXY,
-                                                                   final double cYY,
-                                                                   final double cX1,
-                                                                   final double cY1)
-        throws MathIllegalArgumentException {
-        return new LineTransform(cXX, cYX, cXY, cYY, cX1, cY1);
-    }
-
-    /** Class embedding an affine transform.
-     * <p>This class is used in order to apply an affine transform to a
-     * line. Using a specific object allow to perform some computations
-     * on the transform only once even if the same transform is to be
-     * applied to a large number of lines (for example to a large
-     * polygon)./<p>
-     */
-    private static class LineTransform implements Transform<Euclidean2D, Euclidean1D> {
-
-        /** Transform factor between input abscissa and output abscissa. */
-        private final double cXX;
-
-        /** Transform factor between input abscissa and output ordinate. */
-        private final double cYX;
-
-        /** Transform factor between input ordinate and output abscissa. */
-        private final double cXY;
-
-        /** Transform factor between input ordinate and output ordinate. */
-        private final double cYY;
-
-        /** Transform addendum for output abscissa. */
-        private final double cX1;
-
-        /** Transform addendum for output ordinate. */
-        private final double cY1;
-
-        /** cXY * cY1 - cYY * cX1. */
-        private final double c1Y;
-
-        /** cXX * cY1 - cYX * cX1. */
-        private final double c1X;
-
-        /** cXX * cYY - cYX * cXY. */
-        private final double c11;
-
-        /** Build an affine line transform from a n {@code AffineTransform}.
-         * @param cXX transform factor between input abscissa and output abscissa
-         * @param cYX transform factor between input abscissa and output ordinate
-         * @param cXY transform factor between input ordinate and output abscissa
-         * @param cYY transform factor between input ordinate and output ordinate
-         * @param cX1 transform addendum for output abscissa
-         * @param cY1 transform addendum for output ordinate
-         * @exception MathIllegalArgumentException if the transform is non invertible
-         * @since 4.0
-         */
-        LineTransform(final double cXX, final double cYX, final double cXY,
-                      final double cYY, final double cX1, final double cY1)
-            throws MathIllegalArgumentException {
-
-            this.cXX = cXX;
-            this.cYX = cYX;
-            this.cXY = cXY;
-            this.cYY = cYY;
-            this.cX1 = cX1;
-            this.cY1 = cY1;
-
-            c1Y = LinearCombination.value(cXY, cY1, -cYY, cX1);
-            c1X = LinearCombination.value(cXX, cY1, -cYX, cX1);
-            c11 = LinearCombination.value(cXX, cYY, -cYX, cXY);
-
-            if (FastMath.abs(c11) < 1.0e-20) {
-                throw new MathIllegalArgumentException(LocalizedFormats.NON_INVERTIBLE_TRANSFORM);
-            }
-
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Cartesian2D apply(final Point<Euclidean2D> point) {
-            final Cartesian2D p2D = (Cartesian2D) point;
-            final double  x   = p2D.getX();
-            final double  y   = p2D.getY();
-            return new Cartesian2D(LinearCombination.value(cXX, x, cXY, y, cX1, 1),
-                                LinearCombination.value(cYX, x, cYY, y, cY1, 1));
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Line apply(final Hyperplane<Euclidean2D> hyperplane) {
-            final Line   line    = (Line) hyperplane;
-            final double rOffset = LinearCombination.value(c1X, line.cos, c1Y, line.sin, c11, line.originOffset);
-            final double rCos    = LinearCombination.value(cXX, line.cos, cXY, line.sin);
-            final double rSin    = LinearCombination.value(cYX, line.cos, cYY, line.sin);
-            final double inv     = 1.0 / FastMath.sqrt(rSin * rSin + rCos * rCos);
-            return new Line(FastMath.PI + FastMath.atan2(-rSin, -rCos),
-                            inv * rCos, inv * rSin,
-                            inv * rOffset, line.tolerance);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public SubHyperplane<Euclidean1D> apply(final SubHyperplane<Euclidean1D> sub,
-                                                final Hyperplane<Euclidean2D> original,
-                                                final Hyperplane<Euclidean2D> transformed) {
-            final OrientedPoint op     = (OrientedPoint) sub.getHyperplane();
-            final Line originalLine    = (Line) original;
-            final Line transformedLine = (Line) transformed;
-            final Cartesian1D newLoc =
-                transformedLine.toSubSpace(apply(originalLine.toSpace(op.getLocation())));
-            return new OrientedPoint(newLoc, op.isDirect(), originalLine.tolerance).wholeHyperplane();
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/NestedLoops.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/NestedLoops.java
deleted file mode 100644
index dcfc76a..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/NestedLoops.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * 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.twod;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.euclidean.oned.IntervalsSet;
-import org.apache.commons.math4.geometry.partitioning.Region;
-import org.apache.commons.math4.geometry.partitioning.RegionFactory;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-
-/** This class represent a tree of nested 2D boundary loops.
-
- * <p>This class is used for piecewise polygons construction.
- * Polygons are built using the outline edges as
- * representative of boundaries, the orientation of these lines are
- * meaningful. However, we want to allow the user to specify its
- * outline loops without having to take care of this orientation. This
- * class is devoted to correct mis-oriented loops.<p>
-
- * <p>Orientation is computed assuming the piecewise polygon is finite,
- * i.e. the outermost loops have their exterior side facing points at
- * infinity, and hence are oriented counter-clockwise. The orientation of
- * internal loops is computed as the reverse of the orientation of
- * their immediate surrounding loop.</p>
-
- * @since 3.0
- */
-class NestedLoops {
-
-    /** Boundary loop. */
-    private Cartesian2D[] loop;
-
-    /** Surrounded loops. */
-    private List<NestedLoops> surrounded;
-
-    /** Polygon enclosing a finite region. */
-    private Region<Euclidean2D> polygon;
-
-    /** Indicator for original loop orientation. */
-    private boolean originalIsClockwise;
-
-    /** Tolerance below which points are considered identical. */
-    private final double tolerance;
-
-    /** Simple Constructor.
-     * <p>Build an empty tree of nested loops. This instance will become
-     * the root node of a complete tree, it is not associated with any
-     * loop by itself, the outermost loops are in the root tree child
-     * nodes.</p>
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    NestedLoops(final double tolerance) {
-        this.surrounded = new ArrayList<>();
-        this.tolerance  = tolerance;
-    }
-
-    /** Constructor.
-     * <p>Build a tree node with neither parent nor children</p>
-     * @param loop boundary loop (will be reversed in place if needed)
-     * @param tolerance tolerance below which points are considered identical
-     * @exception MathIllegalArgumentException if an outline has an open boundary loop
-     * @since 3.3
-     */
-    private NestedLoops(final Cartesian2D[] loop, final double tolerance)
-        throws MathIllegalArgumentException {
-
-        if (loop[0] == null) {
-            throw new MathIllegalArgumentException(LocalizedFormats.OUTLINE_BOUNDARY_LOOP_OPEN);
-        }
-
-        this.loop       = loop;
-        this.surrounded = new ArrayList<>();
-        this.tolerance  = tolerance;
-
-        // build the polygon defined by the loop
-        final ArrayList<SubHyperplane<Euclidean2D>> edges = new ArrayList<>();
-        Cartesian2D current = loop[loop.length - 1];
-        for (int i = 0; i < loop.length; ++i) {
-            final Cartesian2D previous = current;
-            current = loop[i];
-            final Line   line   = new Line(previous, current, tolerance);
-            final IntervalsSet region =
-                new IntervalsSet(line.toSubSpace((Point<Euclidean2D>) previous).getX(),
-                                 line.toSubSpace((Point<Euclidean2D>) current).getX(),
-                                 tolerance);
-            edges.add(new SubLine(line, region));
-        }
-        polygon = new PolygonsSet(edges, tolerance);
-
-        // ensure the polygon encloses a finite region of the plane
-        if (Double.isInfinite(polygon.getSize())) {
-            polygon = new RegionFactory<Euclidean2D>().getComplement(polygon);
-            originalIsClockwise = false;
-        } else {
-            originalIsClockwise = true;
-        }
-
-    }
-
-    /** Add a loop in a tree.
-     * @param bLoop boundary loop (will be reversed in place if needed)
-     * @exception MathIllegalArgumentException if an outline has crossing
-     * boundary loops or open boundary loops
-     */
-    public void add(final Cartesian2D[] bLoop) throws MathIllegalArgumentException {
-        add(new NestedLoops(bLoop, tolerance));
-    }
-
-    /** Add a loop in a tree.
-     * @param node boundary loop (will be reversed in place if needed)
-     * @exception MathIllegalArgumentException if an outline has boundary
-     * loops that cross each other
-     */
-    private void add(final NestedLoops node) throws MathIllegalArgumentException {
-
-        // check if we can go deeper in the tree
-        for (final NestedLoops child : surrounded) {
-            if (child.polygon.contains(node.polygon)) {
-                child.add(node);
-                return;
-            }
-        }
-
-        // check if we can absorb some of the instance children
-        for (final Iterator<NestedLoops> iterator = surrounded.iterator(); iterator.hasNext();) {
-            final NestedLoops child = iterator.next();
-            if (node.polygon.contains(child.polygon)) {
-                node.surrounded.add(child);
-                iterator.remove();
-            }
-        }
-
-        // we should be separate from the remaining children
-        RegionFactory<Euclidean2D> factory = new RegionFactory<>();
-        for (final NestedLoops child : surrounded) {
-            if (!factory.intersection(node.polygon, child.polygon).isEmpty()) {
-                throw new MathIllegalArgumentException(LocalizedFormats.CROSSING_BOUNDARY_LOOPS);
-            }
-        }
-
-        surrounded.add(node);
-
-    }
-
-    /** Correct the orientation of the loops contained in the tree.
-     * <p>This is this method that really inverts the loops that where
-     * provided through the {@link #add(Cartesian2D[]) add} method if
-     * they are mis-oriented</p>
-     */
-    public void correctOrientation() {
-        for (NestedLoops child : surrounded) {
-            child.setClockWise(true);
-        }
-    }
-
-    /** Set the loop orientation.
-     * @param clockwise if true, the loop should be set to clockwise
-     * orientation
-     */
-    private void setClockWise(final boolean clockwise) {
-
-        if (originalIsClockwise ^ clockwise) {
-            // we need to inverse the original loop
-            int min = -1;
-            int max = loop.length;
-            while (++min < --max) {
-                final Cartesian2D tmp = loop[min];
-                loop[min] = loop[max];
-                loop[max] = tmp;
-            }
-        }
-
-        // go deeper in the tree
-        for (final NestedLoops child : surrounded) {
-            child.setClockWise(!clockwise);
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/PolygonsSet.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/PolygonsSet.java
deleted file mode 100644
index d69b734..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/PolygonsSet.java
+++ /dev/null
@@ -1,1111 +0,0 @@
-/*
- * 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.twod;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.euclidean.oned.Euclidean1D;
-import org.apache.commons.math4.geometry.euclidean.oned.Interval;
-import org.apache.commons.math4.geometry.euclidean.oned.IntervalsSet;
-import org.apache.commons.math4.geometry.euclidean.oned.Cartesian1D;
-import org.apache.commons.math4.geometry.partitioning.AbstractRegion;
-import org.apache.commons.math4.geometry.partitioning.AbstractSubHyperplane;
-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.Hyperplane;
-import org.apache.commons.math4.geometry.partitioning.Side;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.numbers.core.Precision;
-
-/** This class represents a 2D region: a set of polygons.
- * @since 3.0
- */
-public class PolygonsSet extends AbstractRegion<Euclidean2D, Euclidean1D> {
-
-    /** Vertices organized as boundary loops. */
-    private Cartesian2D[][] vertices;
-
-    /** Build a polygons set representing the whole plane.
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public PolygonsSet(final double tolerance) {
-        super(tolerance);
-    }
-
-    /** Build a polygons set from a BSP tree.
-     * <p>The leaf nodes of the BSP tree <em>must</em> have a
-     * {@code Boolean} attribute representing the inside status of
-     * the corresponding cell (true for inside cells, false for outside
-     * cells). In order to avoid building too many small objects, it is
-     * recommended to use the predefined constants
-     * {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
-     * <p>
-     * This constructor is aimed at expert use, as building the tree may
-     * be a difficult task. It is not intended for general use and for
-     * performances reasons does not check thoroughly its input, as this would
-     * require walking the full tree each time. Failing to provide a tree with
-     * the proper attributes, <em>will</em> therefore generate problems like
-     * {@link NullPointerException} or {@link ClassCastException} only later on.
-     * This limitation is known and explains why this constructor is for expert
-     * use only. The caller does have the responsibility to provided correct arguments.
-     * </p>
-     * @param tree inside/outside BSP tree representing the region
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public PolygonsSet(final BSPTree<Euclidean2D> tree, final double tolerance) {
-        super(tree, tolerance);
-    }
-
-    /** Build a polygons set from a Boundary REPresentation (B-rep).
-     * <p>The boundary is provided as a collection of {@link
-     * SubHyperplane sub-hyperplanes}. Each sub-hyperplane has the
-     * interior part of the region on its minus side and the exterior on
-     * its plus side.</p>
-     * <p>The boundary elements can be in any order, and can form
-     * several non-connected sets (like for example polygons with holes
-     * or a set of disjoint polygons considered as a whole). In
-     * fact, the elements do not even need to be connected together
-     * (their topological connections are not used here). However, if the
-     * boundary does not really separate an inside open from an outside
-     * open (open having here its topological meaning), then subsequent
-     * calls to the {@link
-     * org.apache.commons.math4.geometry.partitioning.Region#checkPoint(org.apache.commons.math4.geometry.Point)
-     * checkPoint} method will not be meaningful anymore.</p>
-     * <p>If the boundary is empty, the region will represent the whole
-     * space.</p>
-     * @param boundary collection of boundary elements, as a
-     * collection of {@link SubHyperplane SubHyperplane} objects
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public PolygonsSet(final Collection<SubHyperplane<Euclidean2D>> boundary, final double tolerance) {
-        super(boundary, tolerance);
-    }
-
-    /** Build a parallellepipedic box.
-     * @param xMin low bound along the x direction
-     * @param xMax high bound along the x direction
-     * @param yMin low bound along the y direction
-     * @param yMax high bound along the y direction
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public PolygonsSet(final double xMin, final double xMax,
-                       final double yMin, final double yMax,
-                       final double tolerance) {
-        super(boxBoundary(xMin, xMax, yMin, yMax, tolerance), tolerance);
-    }
-
-    /** Build a polygon from a simple list of vertices.
-     * <p>The boundary is provided as a list of points considering to
-     * represent the vertices of a simple loop. The interior part of the
-     * region is on the left side of this path and the exterior is on its
-     * right side.</p>
-     * <p>This constructor does not handle polygons with a boundary
-     * forming several disconnected paths (such as polygons with holes).</p>
-     * <p>For cases where this simple constructor applies, it is expected to
-     * be numerically more robust than the {@link #PolygonsSet(Collection,double) general
-     * constructor} using {@link SubHyperplane subhyperplanes}.</p>
-     * <p>If the list is empty, the region will represent the whole
-     * space.</p>
-     * <p>
-     * Polygons with thin pikes or dents are inherently difficult to handle because
-     * they involve lines with almost opposite directions at some vertices. Polygons
-     * whose vertices come from some physical measurement with noise are also
-     * difficult because an edge that should be straight may be broken in lots of
-     * different pieces with almost equal directions. In both cases, computing the
-     * lines intersections is not numerically robust due to the almost 0 or almost
-     * &pi; angle. Such cases need to carefully adjust the {@code hyperplaneThickness}
-     * parameter. A too small value would often lead to completely wrong polygons
-     * with large area wrongly identified as inside or outside. Large values are
-     * often much safer. As a rule of thumb, a value slightly below the size of the
-     * most accurate detail needed is a good value for the {@code hyperplaneThickness}
-     * parameter.
-     * </p>
-     * @param hyperplaneThickness tolerance below which points are considered to
-     * belong to the hyperplane (which is therefore more a slab)
-     * @param vertices vertices of the simple loop boundary
-     */
-    public PolygonsSet(final double hyperplaneThickness, final Cartesian2D ... vertices) {
-        super(verticesToTree(hyperplaneThickness, vertices), hyperplaneThickness);
-    }
-
-    /** Create a list of hyperplanes representing the boundary of a box.
-     * @param xMin low bound along the x direction
-     * @param xMax high bound along the x direction
-     * @param yMin low bound along the y direction
-     * @param yMax high bound along the y direction
-     * @param tolerance tolerance below which points are considered identical
-     * @return boundary of the box
-     */
-    private static Line[] boxBoundary(final double xMin, final double xMax,
-                                      final double yMin, final double yMax,
-                                      final double tolerance) {
-        if ((xMin >= xMax - tolerance) || (yMin >= yMax - tolerance)) {
-            // too thin box, build an empty polygons set
-            return null;
-        }
-        final Cartesian2D minMin = new Cartesian2D(xMin, yMin);
-        final Cartesian2D minMax = new Cartesian2D(xMin, yMax);
-        final Cartesian2D maxMin = new Cartesian2D(xMax, yMin);
-        final Cartesian2D maxMax = new Cartesian2D(xMax, yMax);
-        return new Line[] {
-            new Line(minMin, maxMin, tolerance),
-            new Line(maxMin, maxMax, tolerance),
-            new Line(maxMax, minMax, tolerance),
-            new Line(minMax, minMin, tolerance)
-        };
-    }
-
-    /** Build the BSP tree of a polygons set from a simple list of vertices.
-     * <p>The boundary is provided as a list of points considering to
-     * represent the vertices of a simple loop. The interior part of the
-     * region is on the left side of this path and the exterior is on its
-     * right side.</p>
-     * <p>This constructor does not handle polygons with a boundary
-     * forming several disconnected paths (such as polygons with holes).</p>
-     * <p>For cases where this simple constructor applies, it is expected to
-     * be numerically more robust than the {@link #PolygonsSet(Collection,double) general
-     * constructor} using {@link SubHyperplane subhyperplanes}.</p>
-     * @param hyperplaneThickness tolerance below which points are consider to
-     * belong to the hyperplane (which is therefore more a slab)
-     * @param vertices vertices of the simple loop boundary
-     * @return the BSP tree of the input vertices
-     */
-    private static BSPTree<Euclidean2D> verticesToTree(final double hyperplaneThickness,
-                                                       final Cartesian2D ... vertices) {
-
-        final int n = vertices.length;
-        if (n == 0) {
-            // the tree represents the whole space
-            return new BSPTree<>(Boolean.TRUE);
-        }
-
-        // build the vertices
-        final Vertex[] vArray = new Vertex[n];
-        for (int i = 0; i < n; ++i) {
-            vArray[i] = new Vertex(vertices[i]);
-        }
-
-        // build the edges
-        List<Edge> edges = new ArrayList<>(n);
-        for (int i = 0; i < n; ++i) {
-
-            // get the endpoints of the edge
-            final Vertex start = vArray[i];
-            final Vertex end   = vArray[(i + 1) % n];
-
-            // get the line supporting the edge, taking care not to recreate it
-            // if it was already created earlier due to another edge being aligned
-            // with the current one
-            Line line = start.sharedLineWith(end);
-            if (line == null) {
-                line = new Line(start.getLocation(), end.getLocation(), hyperplaneThickness);
-            }
-
-            // create the edge and store it
-            edges.add(new Edge(start, end, line));
-
-            // check if another vertex also happens to be on this line
-            for (final Vertex vertex : vArray) {
-                if (vertex != start && vertex != end &&
-                    FastMath.abs(line.getOffset((Point<Euclidean2D>) vertex.getLocation())) <= hyperplaneThickness) {
-                    vertex.bindWith(line);
-                }
-            }
-
-        }
-
-        // build the tree top-down
-        final BSPTree<Euclidean2D> tree = new BSPTree<>();
-        insertEdges(hyperplaneThickness, tree, edges);
-
-        return tree;
-
-    }
-
-    /** Recursively build a tree by inserting cut sub-hyperplanes.
-     * @param hyperplaneThickness tolerance below which points are consider to
-     * belong to the hyperplane (which is therefore more a slab)
-     * @param node current tree node (it is a leaf node at the beginning
-     * of the call)
-     * @param edges list of edges to insert in the cell defined by this node
-     * (excluding edges not belonging to the cell defined by this node)
-     */
-    private static void insertEdges(final double hyperplaneThickness,
-                                    final BSPTree<Euclidean2D> node,
-                                    final List<Edge> edges) {
-
-        // find an edge with an hyperplane that can be inserted in the node
-        int index = 0;
-        Edge inserted =null;
-        while (inserted == null && index < edges.size()) {
-            inserted = edges.get(index++);
-            if (inserted.getNode() == null) {
-                if (node.insertCut(inserted.getLine())) {
-                    inserted.setNode(node);
-                } else {
-                    inserted = null;
-                }
-            } else {
-                inserted = null;
-            }
-        }
-
-        if (inserted == null) {
-            // no suitable edge was found, the node remains a leaf node
-            // we need to set its inside/outside boolean indicator
-            final BSPTree<Euclidean2D> parent = node.getParent();
-            if (parent == null || node == parent.getMinus()) {
-                node.setAttribute(Boolean.TRUE);
-            } else {
-                node.setAttribute(Boolean.FALSE);
-            }
-            return;
-        }
-
-        // we have split the node by inserting an edge as a cut sub-hyperplane
-        // distribute the remaining edges in the two sub-trees
-        final List<Edge> plusList  = new ArrayList<>();
-        final List<Edge> minusList = new ArrayList<>();
-        for (final Edge edge : edges) {
-            if (edge != inserted) {
-                final double startOffset = inserted.getLine().getOffset((Point<Euclidean2D>) edge.getStart().getLocation());
-                final double endOffset   = inserted.getLine().getOffset((Point<Euclidean2D>) edge.getEnd().getLocation());
-                Side startSide = (FastMath.abs(startOffset) <= hyperplaneThickness) ?
-                                 Side.HYPER : ((startOffset < 0) ? Side.MINUS : Side.PLUS);
-                Side endSide   = (FastMath.abs(endOffset) <= hyperplaneThickness) ?
-                                 Side.HYPER : ((endOffset < 0) ? Side.MINUS : Side.PLUS);
-                switch (startSide) {
-                    case PLUS:
-                        if (endSide == Side.MINUS) {
-                            // we need to insert a split point on the hyperplane
-                            final Vertex splitPoint = edge.split(inserted.getLine());
-                            minusList.add(splitPoint.getOutgoing());
-                            plusList.add(splitPoint.getIncoming());
-                        } else {
-                            plusList.add(edge);
-                        }
-                        break;
-                    case MINUS:
-                        if (endSide == Side.PLUS) {
-                            // we need to insert a split point on the hyperplane
-                            final Vertex splitPoint = edge.split(inserted.getLine());
-                            minusList.add(splitPoint.getIncoming());
-                            plusList.add(splitPoint.getOutgoing());
-                        } else {
-                            minusList.add(edge);
-                        }
-                        break;
-                    default:
-                        if (endSide == Side.PLUS) {
-                            plusList.add(edge);
-                        } else if (endSide == Side.MINUS) {
-                            minusList.add(edge);
-                        }
-                        break;
-                }
-            }
-        }
-
-        // recurse through lower levels
-        if (!plusList.isEmpty()) {
-            insertEdges(hyperplaneThickness, node.getPlus(),  plusList);
-        } else {
-            node.getPlus().setAttribute(Boolean.FALSE);
-        }
-        if (!minusList.isEmpty()) {
-            insertEdges(hyperplaneThickness, node.getMinus(), minusList);
-        } else {
-            node.getMinus().setAttribute(Boolean.TRUE);
-        }
-
-    }
-
-    /** Internal class for holding vertices while they are processed to build a BSP tree. */
-    private static class Vertex {
-
-        /** Vertex location. */
-        private final Cartesian2D location;
-
-        /** Incoming edge. */
-        private Edge incoming;
-
-        /** Outgoing edge. */
-        private Edge outgoing;
-
-        /** Lines bound with this vertex. */
-        private final List<Line> lines;
-
-        /** Build a non-processed vertex not owned by any node yet.
-         * @param location vertex location
-         */
-        Vertex(final Cartesian2D location) {
-            this.location = location;
-            this.incoming = null;
-            this.outgoing = null;
-            this.lines    = new ArrayList<>();
-        }
-
-        /** Get Vertex location.
-         * @return vertex location
-         */
-        public Cartesian2D getLocation() {
-            return location;
-        }
-
-        /** Bind a line considered to contain this vertex.
-         * @param line line to bind with this vertex
-         */
-        public void bindWith(final Line line) {
-            lines.add(line);
-        }
-
-        /** Get the common line bound with both the instance and another vertex, if any.
-         * <p>
-         * When two vertices are both bound to the same line, this means they are
-         * already handled by node associated with this line, so there is no need
-         * to create a cut hyperplane for them.
-         * </p>
-         * @param vertex other vertex to check instance against
-         * @return line bound with both the instance and another vertex, or null if the
-         * two vertices do not share a line yet
-         */
-        public Line sharedLineWith(final Vertex vertex) {
-            for (final Line line1 : lines) {
-                for (final Line line2 : vertex.lines) {
-                    if (line1 == line2) {
-                        return line1;
-                    }
-                }
-            }
-            return null;
-        }
-
-        /** Set incoming edge.
-         * <p>
-         * The line supporting the incoming edge is automatically bound
-         * with the instance.
-         * </p>
-         * @param incoming incoming edge
-         */
-        public void setIncoming(final Edge incoming) {
-            this.incoming = incoming;
-            bindWith(incoming.getLine());
-        }
-
-        /** Get incoming edge.
-         * @return incoming edge
-         */
-        public Edge getIncoming() {
-            return incoming;
-        }
-
-        /** Set outgoing edge.
-         * <p>
-         * The line supporting the outgoing edge is automatically bound
-         * with the instance.
-         * </p>
-         * @param outgoing outgoing edge
-         */
-        public void setOutgoing(final Edge outgoing) {
-            this.outgoing = outgoing;
-            bindWith(outgoing.getLine());
-        }
-
-        /** Get outgoing edge.
-         * @return outgoing edge
-         */
-        public Edge getOutgoing() {
-            return outgoing;
-        }
-
-    }
-
-    /** Internal class for holding edges while they are processed to build a BSP tree. */
-    private static class Edge {
-
-        /** Start vertex. */
-        private final Vertex start;
-
-        /** End vertex. */
-        private final Vertex end;
-
-        /** Line supporting the edge. */
-        private final Line line;
-
-        /** Node whose cut hyperplane contains this edge. */
-        private BSPTree<Euclidean2D> node;
-
-        /** Build an edge not contained in any node yet.
-         * @param start start vertex
-         * @param end end vertex
-         * @param line line supporting the edge
-         */
-        Edge(final Vertex start, final Vertex end, final Line line) {
-
-            this.start = start;
-            this.end   = end;
-            this.line  = line;
-            this.node  = null;
-
-            // connect the vertices back to the edge
-            start.setOutgoing(this);
-            end.setIncoming(this);
-
-        }
-
-        /** Get start vertex.
-         * @return start vertex
-         */
-        public Vertex getStart() {
-            return start;
-        }
-
-        /** Get end vertex.
-         * @return end vertex
-         */
-        public Vertex getEnd() {
-            return end;
-        }
-
-        /** Get the line supporting this edge.
-         * @return line supporting this edge
-         */
-        public Line getLine() {
-            return line;
-        }
-
-        /** Set the node whose cut hyperplane contains this edge.
-         * @param node node whose cut hyperplane contains this edge
-         */
-        public void setNode(final BSPTree<Euclidean2D> node) {
-            this.node = node;
-        }
-
-        /** Get the node whose cut hyperplane contains this edge.
-         * @return node whose cut hyperplane contains this edge
-         * (null if edge has not yet been inserted into the BSP tree)
-         */
-        public BSPTree<Euclidean2D> getNode() {
-            return node;
-        }
-
-        /** Split the edge.
-         * <p>
-         * Once split, this edge is not referenced anymore by the vertices,
-         * it is replaced by the two half-edges and an intermediate splitting
-         * vertex is introduced to connect these two halves.
-         * </p>
-         * @param splitLine line splitting the edge in two halves
-         * @return split vertex (its incoming and outgoing edges are the two halves)
-         */
-        public Vertex split(final Line splitLine) {
-            final Vertex splitVertex = new Vertex(line.intersection(splitLine));
-            splitVertex.bindWith(splitLine);
-            final Edge startHalf = new Edge(start, splitVertex, line);
-            final Edge endHalf   = new Edge(splitVertex, end, line);
-            startHalf.node = node;
-            endHalf.node   = node;
-            return splitVertex;
-        }
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public PolygonsSet buildNew(final BSPTree<Euclidean2D> tree) {
-        return new PolygonsSet(tree, getTolerance());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void computeGeometricalProperties() {
-
-        final Cartesian2D[][] v = getVertices();
-
-        if (v.length == 0) {
-            final BSPTree<Euclidean2D> tree = getTree(false);
-            if (tree.getCut() == null && (Boolean) tree.getAttribute()) {
-                // the instance covers the whole space
-                setSize(Double.POSITIVE_INFINITY);
-                setBarycenter((Point<Euclidean2D>) Cartesian2D.NaN);
-            } else {
-                setSize(0);
-                setBarycenter((Point<Euclidean2D>) Cartesian2D.NaN);
-            }
-        } else if (v[0][0] == null) {
-            // there is at least one open-loop: the polygon is infinite
-            setSize(Double.POSITIVE_INFINITY);
-            setBarycenter((Point<Euclidean2D>) Cartesian2D.NaN);
-        } else {
-            // all loops are closed, we compute some integrals around the shape
-
-            double sum  = 0;
-            double sumX = 0;
-            double sumY = 0;
-
-            for (Cartesian2D[] loop : v) {
-                double x1 = loop[loop.length - 1].getX();
-                double y1 = loop[loop.length - 1].getY();
-                for (final Cartesian2D point : loop) {
-                    final double x0 = x1;
-                    final double y0 = y1;
-                    x1 = point.getX();
-                    y1 = point.getY();
-                    final double factor = x0 * y1 - y0 * x1;
-                    sum  += factor;
-                    sumX += factor * (x0 + x1);
-                    sumY += factor * (y0 + y1);
-                }
-            }
-
-            if (sum < 0) {
-                // the polygon as a finite outside surrounded by an infinite inside
-                setSize(Double.POSITIVE_INFINITY);
-                setBarycenter((Point<Euclidean2D>) Cartesian2D.NaN);
-            } else {
-                setSize(sum / 2);
-                setBarycenter((Point<Euclidean2D>) new Cartesian2D(sumX / (3 * sum), sumY / (3 * sum)));
-            }
-
-        }
-
-    }
-
-    /** Get the vertices of the polygon.
-     * <p>The polygon boundary can be represented as an array of loops,
-     * each loop being itself an array of vertices.</p>
-     * <p>In order to identify open loops which start and end by
-     * infinite edges, the open loops arrays start with a null point. In
-     * this case, the first non null point and the last point of the
-     * array do not represent real vertices, they are dummy points
-     * intended only to get the direction of the first and last edge. An
-     * open loop consisting of a single infinite line will therefore be
-     * represented by a three elements array with one null point
-     * followed by two dummy points. The open loops are always the first
-     * ones in the loops array.</p>
-     * <p>If the polygon has no boundary at all, a zero length loop
-     * array will be returned.</p>
-     * <p>All line segments in the various loops have the inside of the
-     * region on their left side and the outside on their right side
-     * when moving in the underlying line direction. This means that
-     * closed loops surrounding finite areas obey the direct
-     * trigonometric orientation.</p>
-     * @return vertices of the polygon, organized as oriented boundary
-     * loops with the open loops first (the returned value is guaranteed
-     * to be non-null)
-     */
-    public Cartesian2D[][] getVertices() {
-        if (vertices == null) {
-            if (getTree(false).getCut() == null) {
-                vertices = new Cartesian2D[0][];
-            } else {
-
-                // build the unconnected segments
-                final SegmentsBuilder visitor = new SegmentsBuilder(getTolerance());
-                getTree(true).visit(visitor);
-                final List<ConnectableSegment> segments = visitor.getSegments();
-
-                // connect all segments, using topological criteria first
-                // and using Euclidean distance only as a last resort
-                int pending = segments.size();
-                pending -= naturalFollowerConnections(segments);
-                if (pending > 0) {
-                    pending -= splitEdgeConnections(segments);
-                }
-                if (pending > 0) {
-                    pending -= closeVerticesConnections(segments);
-                }
-
-                // create the segment loops
-                final ArrayList<List<Segment>> loops = new ArrayList<>();
-                for (ConnectableSegment s = getUnprocessed(segments); s != null; s = getUnprocessed(segments)) {
-                    final List<Segment> loop = followLoop(s);
-                    if (loop != null) {
-                        // an open loop is one that has fewer than two segments or has a null
-                        // start point; the case where we have two segments in a closed loop
-                        // (ie, an infinitely thin, degenerate loop) will result in null being
-                        // returned from the followLoops method
-                        if (loop.size() < 2 || loop.get(0).getStart() == null) {
-                            // this is an open loop, we put it on the front
-                            loops.add(0, loop);
-                        } else {
-                            // this is a closed loop, we put it on the back
-                            loops.add(loop);
-                        }
-                    }
-                }
-
-                // transform the loops in an array of arrays of points
-                vertices = new Cartesian2D[loops.size()][];
-                int i = 0;
-
-                for (final List<Segment> loop : loops) {
-                    if (loop.size() < 2 ||
-                        (loop.size() == 2 && loop.get(0).getStart() == null && loop.get(1).getEnd() == null)) {
-                        // single infinite line
-                        final Line line = loop.get(0).getLine();
-                        vertices[i++] = new Cartesian2D[] {
-                            null,
-                            line.toSpace(new Cartesian1D(-Float.MAX_VALUE)),
-                            line.toSpace(new Cartesian1D(+Float.MAX_VALUE))
-                        };
-                    } else if (loop.get(0).getStart() == null) {
-                        // open loop with at least one real point
-                        final Cartesian2D[] array = new Cartesian2D[loop.size() + 2];
-                        int j = 0;
-                        for (Segment segment : loop) {
-
-                            if (j == 0) {
-                                // null point and first dummy point
-                                double x = segment.getLine().toSubSpace(segment.getEnd()).getX();
-                                x -= FastMath.max(1.0, FastMath.abs(x / 2));
-                                array[j++] = null;
-                                array[j++] = segment.getLine().toSpace(new Cartesian1D(x));
-                            }
-
-                            if (j < (array.length - 1)) {
-                                // current point
-                                array[j++] = segment.getEnd();
-                            } else if (j == (array.length - 1)) {
-                                // last dummy point
-                                double x = segment.getLine().toSubSpace(segment.getStart()).getX();
-                                x += FastMath.max(1.0, FastMath.abs(x / 2));
-                                array[j++] = segment.getLine().toSpace(new Cartesian1D(x));
-                            }
-
-                        }
-                        vertices[i++] = array;
-                    } else {
-                        final Cartesian2D[] array = new Cartesian2D[loop.size()];
-                        int j = 0;
-                        for (Segment segment : loop) {
-                            array[j++] = segment.getStart();
-                        }
-                        vertices[i++] = array;
-                    }
-                }
-
-            }
-        }
-
-        return vertices.clone();
-
-    }
-
-    /** Connect the segments using only natural follower information.
-     * @param segments segments complete segments list
-     * @return number of connections performed
-     */
-    private int naturalFollowerConnections(final List<ConnectableSegment> segments) {
-        int connected = 0;
-        for (final ConnectableSegment segment : segments) {
-            if (segment.getNext() == null) {
-                final BSPTree<Euclidean2D> node = segment.getNode();
-                final BSPTree<Euclidean2D> end  = segment.getEndNode();
-                for (final ConnectableSegment candidateNext : segments) {
-                    if (candidateNext.getPrevious()  == null &&
-                        candidateNext.getNode()      == end &&
-                        candidateNext.getStartNode() == node) {
-                        // connect the two segments
-                        segment.setNext(candidateNext);
-                        candidateNext.setPrevious(segment);
-                        ++connected;
-                        break;
-                    }
-                }
-            }
-        }
-        return connected;
-    }
-
-    /** Connect the segments resulting from a line splitting a straight edge.
-     * @param segments segments complete segments list
-     * @return number of connections performed
-     */
-    private int splitEdgeConnections(final List<ConnectableSegment> segments) {
-        int connected = 0;
-        for (final ConnectableSegment segment : segments) {
-            if (segment.getNext() == null) {
-                final Hyperplane<Euclidean2D> hyperplane = segment.getNode().getCut().getHyperplane();
-                final BSPTree<Euclidean2D> end  = segment.getEndNode();
-                for (final ConnectableSegment candidateNext : segments) {
-                    if (candidateNext.getPrevious()                      == null &&
-                        candidateNext.getNode().getCut().getHyperplane() == hyperplane &&
-                        candidateNext.getStartNode()                     == end) {
-                        // connect the two segments
-                        segment.setNext(candidateNext);
-                        candidateNext.setPrevious(segment);
-                        ++connected;
-                        break;
-                    }
-                }
-            }
-        }
-        return connected;
-    }
-
-    /** Connect the segments using Euclidean distance.
-     * <p>
-     * This connection heuristic should be used last, as it relies
-     * only on a fuzzy distance criterion.
-     * </p>
-     * @param segments segments complete segments list
-     * @return number of connections performed
-     */
-    private int closeVerticesConnections(final List<ConnectableSegment> segments) {
-        int connected = 0;
-        for (final ConnectableSegment segment : segments) {
-            if (segment.getNext() == null && segment.getEnd() != null) {
-                final Cartesian2D end = segment.getEnd();
-                ConnectableSegment selectedNext = null;
-                double min = Double.POSITIVE_INFINITY;
-                for (final ConnectableSegment candidateNext : segments) {
-                    if (candidateNext.getPrevious() == null && candidateNext.getStart() != null) {
-                        final double distance = Cartesian2D.distance(end, candidateNext.getStart());
-                        if (distance < min) {
-                            selectedNext = candidateNext;
-                            min          = distance;
-                        }
-                    }
-                }
-                if (min <= getTolerance()) {
-                    // connect the two segments
-                    segment.setNext(selectedNext);
-                    selectedNext.setPrevious(segment);
-                    ++connected;
-                }
-            }
-        }
-        return connected;
-    }
-
-    /** Get first unprocessed segment from a list.
-     * @param segments segments list
-     * @return first segment that has not been processed yet
-     * or null if all segments have been processed
-     */
-    private ConnectableSegment getUnprocessed(final List<ConnectableSegment> segments) {
-        for (final ConnectableSegment segment : segments) {
-            if (!segment.isProcessed()) {
-                return segment;
-            }
-        }
-        return null;
-    }
-
-    /** Build the loop containing a segment.
-     * <p>
-     * The segment put in the loop will be marked as processed.
-     * </p>
-     * @param defining segment used to define the loop
-     * @return loop containing the segment (may be null if the loop is a
-     * degenerated infinitely thin 2 points loop
-     */
-    private List<Segment> followLoop(final ConnectableSegment defining) {
-
-        final List<Segment> loop = new ArrayList<>();
-        loop.add(defining);
-        defining.setProcessed(true);
-
-        // add segments in connection order
-        ConnectableSegment next = defining.getNext();
-        while (next != defining && next != null) {
-            loop.add(next);
-            next.setProcessed(true);
-            next = next.getNext();
-        }
-
-        if (next == null) {
-            // the loop is open and we have found its end,
-            // we need to find its start too
-            ConnectableSegment previous = defining.getPrevious();
-            while (previous != null) {
-                loop.add(0, previous);
-                previous.setProcessed(true);
-                previous = previous.getPrevious();
-            }
-        }
-
-        // filter out spurious vertices
-        filterSpuriousVertices(loop);
-
-        if (loop.size() == 2 && loop.get(0).getStart() != null) {
-            // this is a degenerated infinitely thin closed loop, we simply ignore it
-            return null;
-        } else {
-            return loop;
-        }
-
-    }
-
-    /** Filter out spurious vertices on straight lines (at machine precision).
-     * @param loop segments loop to filter (will be modified in-place)
-     */
-    private void filterSpuriousVertices(final List<Segment> loop) {
-        // we need at least 2 segments in order for one of the contained vertices
-        // to be unnecessary
-        if (loop.size() > 1) {
-            // Go through the list and compare each segment with the next
-            // one in line. We can remove the shared vertex if the segments
-            // are not infinite and they lie on the same line.
-            for (int i = 0; i < loop.size(); ++i) {
-                final Segment previous = loop.get(i);
-                int j = (i + 1) % loop.size();
-                final Segment next = loop.get(j);
-                if (next != null &&
-                    previous.getStart() != null && next.getEnd() != null &&
-                    Precision.equals(previous.getLine().getAngle(), next.getLine().getAngle(), Precision.EPSILON)) {
-                    // the vertex between the two edges is a spurious one
-                    // replace the two segments by a single one
-                    loop.set(j, new Segment(previous.getStart(), next.getEnd(), previous.getLine()));
-                    loop.remove(i--);
-                }
-            }
-        }
-    }
-
-    /** Private extension of Segment allowing connection. */
-    private static class ConnectableSegment extends Segment {
-
-        /** Node containing segment. */
-        private final BSPTree<Euclidean2D> node;
-
-        /** Node whose intersection with current node defines start point. */
-        private final BSPTree<Euclidean2D> startNode;
-
-        /** Node whose intersection with current node defines end point. */
-        private final BSPTree<Euclidean2D> endNode;
-
-        /** Previous segment. */
-        private ConnectableSegment previous;
-
-        /** Next segment. */
-        private ConnectableSegment next;
-
-        /** Indicator for completely processed segments. */
-        private boolean processed;
-
-        /** Build a segment.
-         * @param start start point of the segment
-         * @param end end point of the segment
-         * @param line line containing the segment
-         * @param node node containing the segment
-         * @param startNode node whose intersection with current node defines start point
-         * @param endNode node whose intersection with current node defines end point
-         */
-        ConnectableSegment(final Cartesian2D start, final Cartesian2D end, final Line line,
-                           final BSPTree<Euclidean2D> node,
-                           final BSPTree<Euclidean2D> startNode,
-                           final BSPTree<Euclidean2D> endNode) {
-            super(start, end, line);
-            this.node      = node;
-            this.startNode = startNode;
-            this.endNode   = endNode;
-            this.previous  = null;
-            this.next      = null;
-            this.processed = false;
-        }
-
-        /** Get the node containing segment.
-         * @return node containing segment
-         */
-        public BSPTree<Euclidean2D> getNode() {
-            return node;
-        }
-
-        /** Get the node whose intersection with current node defines start point.
-         * @return node whose intersection with current node defines start point
-         */
-        public BSPTree<Euclidean2D> getStartNode() {
-            return startNode;
-        }
-
-        /** Get the node whose intersection with current node defines end point.
-         * @return node whose intersection with current node defines end point
-         */
-        public BSPTree<Euclidean2D> getEndNode() {
-            return endNode;
-        }
-
-        /** Get the previous segment.
-         * @return previous segment
-         */
-        public ConnectableSegment getPrevious() {
-            return previous;
-        }
-
-        /** Set the previous segment.
-         * @param previous previous segment
-         */
-        public void setPrevious(final ConnectableSegment previous) {
-            this.previous = previous;
-        }
-
-        /** Get the next segment.
-         * @return next segment
-         */
-        public ConnectableSegment getNext() {
-            return next;
-        }
-
-        /** Set the next segment.
-         * @param next previous segment
-         */
-        public void setNext(final ConnectableSegment next) {
-            this.next = next;
-        }
-
-        /** Set the processed flag.
-         * @param processed processed flag to set
-         */
-        public void setProcessed(final boolean processed) {
-            this.processed = processed;
-        }
-
-        /** Check if the segment has been processed.
-         * @return true if the segment has been processed
-         */
-        public boolean isProcessed() {
-            return processed;
-        }
-
-    }
-
-    /** Visitor building segments. */
-    private static class SegmentsBuilder implements BSPTreeVisitor<Euclidean2D> {
-
-        /** Tolerance for close nodes connection. */
-        private final double tolerance;
-
-        /** Built segments. */
-        private final List<ConnectableSegment> segments;
-
-        /** Simple constructor.
-         * @param tolerance tolerance for close nodes connection
-         */
-        SegmentsBuilder(final double tolerance) {
-            this.tolerance = tolerance;
-            this.segments  = new ArrayList<>();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Order visitOrder(final BSPTree<Euclidean2D> node) {
-            return Order.MINUS_SUB_PLUS;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void visitInternalNode(final BSPTree<Euclidean2D> node) {
-            @SuppressWarnings("unchecked")
-            final BoundaryAttribute<Euclidean2D> attribute = (BoundaryAttribute<Euclidean2D>) node.getAttribute();
-            final Iterable<BSPTree<Euclidean2D>> splitters = attribute.getSplitters();
-            if (attribute.getPlusOutside() != null) {
-                addContribution(attribute.getPlusOutside(), node, splitters, false);
-            }
-            if (attribute.getPlusInside() != null) {
-                addContribution(attribute.getPlusInside(), node, splitters, true);
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void visitLeafNode(final BSPTree<Euclidean2D> node) {
-        }
-
-        /** Add the contribution of a boundary facet.
-         * @param sub boundary facet
-         * @param node node containing segment
-         * @param splitters splitters for the boundary facet
-         * @param reversed if true, the facet has the inside on its plus side
-         */
-        private void addContribution(final SubHyperplane<Euclidean2D> sub,
-                                     final BSPTree<Euclidean2D> node,
-                                     final Iterable<BSPTree<Euclidean2D>> splitters,
-                                     final boolean reversed) {
-            @SuppressWarnings("unchecked")
-            final AbstractSubHyperplane<Euclidean2D, Euclidean1D> absSub =
-                (AbstractSubHyperplane<Euclidean2D, Euclidean1D>) sub;
-            final Line line      = (Line) sub.getHyperplane();
-            final List<Interval> intervals = ((IntervalsSet) absSub.getRemainingRegion()).asList();
-            for (final Interval i : intervals) {
-
-                // find the 2D points
-                final Cartesian2D startV = Double.isInfinite(i.getInf()) ?
-                                        null : line.toSpace(new Cartesian1D(i.getInf()));
-                final Cartesian2D endV   = Double.isInfinite(i.getSup()) ?
-                                        null : line.toSpace(new Cartesian1D(i.getSup()));
-
-                // recover the connectivity information
-                final BSPTree<Euclidean2D> startN = selectClosest(startV, splitters);
-                final BSPTree<Euclidean2D> endN   = selectClosest(endV, splitters);
-
-                if (reversed) {
-                    segments.add(new ConnectableSegment(endV, startV, line.getReverse(),
-                                                        node, endN, startN));
-                } else {
-                    segments.add(new ConnectableSegment(startV, endV, line,
-                                                        node, startN, endN));
-                }
-
-            }
-        }
-
-        /** Select the node whose cut sub-hyperplane is closest to specified point.
-         * @param point reference point
-         * @param candidates candidate nodes
-         * @return node closest to point, or null if point is null or no node is closer than tolerance
-         */
-        private BSPTree<Euclidean2D> selectClosest(final Cartesian2D point, final Iterable<BSPTree<Euclidean2D>> candidates) {
-            if (point != null) {
-                BSPTree<Euclidean2D> selected = null;
-                double min = Double.POSITIVE_INFINITY;
-
-                for (final BSPTree<Euclidean2D> node : candidates) {
-                    final double distance = FastMath.abs(node.getCut().getHyperplane().getOffset(point));
-                    if (distance < min) {
-                        selected = node;
-                        min      = distance;
-                    }
-                }
-
-                if (min <= tolerance) {
-                    return selected;
-                }
-            }
-            return null;
-        }
-
-        /** Get the segments.
-         * @return built segments
-         */
-        public List<ConnectableSegment> getSegments() {
-            return segments;
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Segment.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Segment.java
deleted file mode 100644
index 70ce579..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Segment.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.twod;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.util.FastMath;
-
-/** Simple container for a two-points segment.
- * @since 3.0
- */
-public class Segment {
-
-    /** Start point of the segment. */
-    private final Cartesian2D start;
-
-    /** End point of the segment. */
-    private final Cartesian2D end;
-
-    /** Line containing the segment. */
-    private final Line     line;
-
-    /** Build a segment.
-     * @param start start point of the segment
-     * @param end end point of the segment
-     * @param line line containing the segment
-     */
-    public Segment(final Cartesian2D start, final Cartesian2D end, final Line line) {
-        this.start  = start;
-        this.end    = end;
-        this.line   = line;
-    }
-
-    /** Get the start point of the segment.
-     * @return start point of the segment
-     */
-    public Cartesian2D getStart() {
-        return start;
-    }
-
-    /** Get the end point of the segment.
-     * @return end point of the segment
-     */
-    public Cartesian2D getEnd() {
-        return end;
-    }
-
-    /** Get the line containing the segment.
-     * @return line containing the segment
-     */
-    public Line getLine() {
-        return line;
-    }
-
-    /** Calculates the shortest distance from a point to this line segment.
-     * <p>
-     * If the perpendicular extension from the point to the line does not
-     * cross in the bounds of the line segment, the shortest distance to
-     * the two end points will be returned.
-     * </p>
-     *
-     * Algorithm adapted from:
-     * <a href="http://www.codeguru.com/forum/printthread.php?s=cc8cf0596231f9a7dba4da6e77c29db3&t=194400&pp=15&page=1">
-     * Thread @ Codeguru</a>
-     *
-     * @param p to check
-     * @return distance between the instance and the point
-     * @since 3.1
-     */
-    public double distance(final Cartesian2D p) {
-        final double deltaX = end.getX() - start.getX();
-        final double deltaY = end.getY() - start.getY();
-
-        final double r = ((p.getX() - start.getX()) * deltaX + (p.getY() - start.getY()) * deltaY) /
-                         (deltaX * deltaX + deltaY * deltaY);
-
-        // r == 0 => P = startPt
-        // r == 1 => P = endPt
-        // r < 0 => P is on the backward extension of the segment
-        // r > 1 => P is on the forward extension of the segment
-        // 0 < r < 1 => P is on the segment
-
-        // if point isn't on the line segment, just return the shortest distance to the end points
-        if (r < 0 || r > 1) {
-            final double dist1 = getStart().distance((Point<Euclidean2D>) p);
-            final double dist2 = getEnd().distance((Point<Euclidean2D>) p);
-
-            return FastMath.min(dist1, dist2);
-        }
-        else {
-            // find point on line and see if it is in the line segment
-            final double px = start.getX() + r * deltaX;
-            final double py = start.getY() + r * deltaY;
-
-            final Cartesian2D interPt = new Cartesian2D(px, py);
-            return interPt.distance((Point<Euclidean2D>) p);
-        }
-    }
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/SubLine.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/SubLine.java
deleted file mode 100644
index ae66659..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/SubLine.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * 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.twod;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.euclidean.oned.Euclidean1D;
-import org.apache.commons.math4.geometry.euclidean.oned.Interval;
-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.Cartesian1D;
-import org.apache.commons.math4.geometry.partitioning.AbstractSubHyperplane;
-import org.apache.commons.math4.geometry.partitioning.BSPTree;
-import org.apache.commons.math4.geometry.partitioning.Hyperplane;
-import org.apache.commons.math4.geometry.partitioning.Region;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-import org.apache.commons.math4.geometry.partitioning.Region.Location;
-import org.apache.commons.math4.util.FastMath;
-
-/** This class represents a sub-hyperplane for {@link Line}.
- * @since 3.0
- */
-public class SubLine extends AbstractSubHyperplane<Euclidean2D, Euclidean1D> {
-
-    /** Simple constructor.
-     * @param hyperplane underlying hyperplane
-     * @param remainingRegion remaining region of the hyperplane
-     */
-    public SubLine(final Hyperplane<Euclidean2D> hyperplane,
-                   final Region<Euclidean1D> remainingRegion) {
-        super(hyperplane, remainingRegion);
-    }
-
-    /** Create a sub-line from two endpoints.
-     * @param start start point
-     * @param end end point
-     * @param tolerance tolerance below which points are considered identical
-     * @since 3.3
-     */
-    public SubLine(final Cartesian2D start, final Cartesian2D end, final double tolerance) {
-        super(new Line(start, end, tolerance), buildIntervalSet(start, end, tolerance));
-    }
-
-    /** Create a sub-line from a segment.
-     * @param segment single segment forming the sub-line
-     */
-    public SubLine(final Segment segment) {
-        super(segment.getLine(),
-              buildIntervalSet(segment.getStart(), segment.getEnd(), segment.getLine().getTolerance()));
-    }
-
-    /** Get the endpoints of the sub-line.
-     * <p>
-     * A subline may be any arbitrary number of disjoints segments, so the endpoints
-     * are provided as a list of endpoint pairs. Each element of the list represents
-     * one segment, and each segment contains a start point at index 0 and an end point
-     * at index 1. If the sub-line is unbounded in the negative infinity direction,
-     * the start point of the first segment will have infinite coordinates. If the
-     * sub-line is unbounded in the positive infinity direction, the end point of the
-     * last segment will have infinite coordinates. So a sub-line covering the whole
-     * line will contain just one row and both elements of this row will have infinite
-     * coordinates. If the sub-line is empty, the returned list will contain 0 segments.
-     * </p>
-     * @return list of segments endpoints
-     */
-    public List<Segment> getSegments() {
-
-        final Line line = (Line) getHyperplane();
-        final List<Interval> list = ((IntervalsSet) getRemainingRegion()).asList();
-        final List<Segment> segments = new ArrayList<>(list.size());
-
-        for (final Interval interval : list) {
-            final Cartesian2D start = line.toSpace(new Cartesian1D(interval.getInf()));
-            final Cartesian2D end   = line.toSpace(new Cartesian1D(interval.getSup()));
-            segments.add(new Segment(start, end, line));
-        }
-
-        return segments;
-
-    }
-
-    /** Get the intersection of the instance and another sub-line.
-     * <p>
-     * This method is related to the {@link Line#intersection(Line)
-     * intersection} method in the {@link Line Line} class, but in addition
-     * to compute the point along infinite lines, it also checks the point
-     * lies on both sub-line ranges.
-     * </p>
-     * @param subLine other sub-line which may intersect instance
-     * @param includeEndPoints if true, endpoints are considered to belong to
-     * instance (i.e. they are closed sets) and may be returned, otherwise endpoints
-     * are considered to not belong to instance (i.e. they are open sets) and intersection
-     * occurring on endpoints lead to null being returned
-     * @return the intersection point if there is one, null if the sub-lines don't intersect
-     */
-    public Cartesian2D intersection(final SubLine subLine, final boolean includeEndPoints) {
-
-        // retrieve the underlying lines
-        Line line1 = (Line) getHyperplane();
-        Line line2 = (Line) subLine.getHyperplane();
-
-        // compute the intersection on infinite line
-        Cartesian2D v2D = line1.intersection(line2);
-        if (v2D == null) {
-            return null;
-        }
-
-        // check location of point with respect to first sub-line
-        Location loc1 = getRemainingRegion().checkPoint(line1.toSubSpace((Point<Euclidean2D>) v2D));
-
-        // check location of point with respect to second sub-line
-        Location loc2 = subLine.getRemainingRegion().checkPoint(line2.toSubSpace((Point<Euclidean2D>) v2D));
-
-        if (includeEndPoints) {
-            return ((loc1 != Location.OUTSIDE) && (loc2 != Location.OUTSIDE)) ? v2D : null;
-        } else {
-            return ((loc1 == Location.INSIDE) && (loc2 == Location.INSIDE)) ? v2D : null;
-        }
-
-    }
-
-    /** Build an interval set from two points.
-     * @param start start point
-     * @param end end point
-     * @param tolerance tolerance below which points are considered identical
-     * @return an interval set
-     */
-    private static IntervalsSet buildIntervalSet(final Cartesian2D start, final Cartesian2D end, final double tolerance) {
-        final Line line = new Line(start, end, tolerance);
-        return new IntervalsSet(line.toSubSpace(start).getX(),
-                                line.toSubSpace(end).getX(),
-                                tolerance);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected AbstractSubHyperplane<Euclidean2D, Euclidean1D> buildNew(final Hyperplane<Euclidean2D> hyperplane,
-                                                                       final Region<Euclidean1D> remainingRegion) {
-        return new SubLine(hyperplane, remainingRegion);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public SplitSubHyperplane<Euclidean2D> split(final Hyperplane<Euclidean2D> hyperplane) {
-
-        final Line    thisLine  = (Line) getHyperplane();
-        final Line    otherLine = (Line) hyperplane;
-        final Cartesian2D crossing = thisLine.intersection(otherLine);
-        final double tolerance  = thisLine.getTolerance();
-
-        if (crossing == null) {
-            // the lines are parallel
-            final double global = otherLine.getOffset(thisLine);
-            if (global < -tolerance) {
-                return new SplitSubHyperplane<>(null, this);
-            } else if (global > tolerance) {
-                return new SplitSubHyperplane<>(this, null);
-            } else {
-                return new SplitSubHyperplane<>(null, null);
-            }
-        }
-
-        // the lines do intersect
-        final boolean direct = FastMath.sin(thisLine.getAngle() - otherLine.getAngle()) < 0;
-        final Cartesian1D x      = thisLine.toSubSpace(crossing);
-        final SubHyperplane<Euclidean1D> subPlus  =
-                new OrientedPoint(x, !direct, tolerance).wholeHyperplane();
-        final SubHyperplane<Euclidean1D> subMinus =
-                new OrientedPoint(x,  direct, tolerance).wholeHyperplane();
-
-        final BSPTree<Euclidean1D> splitTree = getRemainingRegion().getTree(false).split(subMinus);
-        final BSPTree<Euclidean1D> plusTree  = getRemainingRegion().isEmpty(splitTree.getPlus()) ?
-                                               new BSPTree<Euclidean1D>(Boolean.FALSE) :
-                                               new BSPTree<>(subPlus, new BSPTree<Euclidean1D>(Boolean.FALSE),
-                                                                        splitTree.getPlus(), null);
-        final BSPTree<Euclidean1D> minusTree = getRemainingRegion().isEmpty(splitTree.getMinus()) ?
-                                               new BSPTree<Euclidean1D>(Boolean.FALSE) :
-                                               new BSPTree<>(subMinus, new BSPTree<Euclidean1D>(Boolean.FALSE),
-                                                                        splitTree.getMinus(), null);
-        return new SplitSubHyperplane<>(new SubLine(thisLine.copySelf(), new IntervalsSet(plusTree, tolerance)),
-                                                   new SubLine(thisLine.copySelf(), new IntervalsSet(minusTree, tolerance)));
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2D.java
deleted file mode 100644
index dbe98d7..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2D.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.twod;
-
-import org.apache.commons.math4.geometry.Vector;
-
-/** This class represents a 2D vector.
- * @since 3.0
- */
-public abstract class Vector2D implements Vector<Euclidean2D> {
-
-    /** Get the abscissa of the vector.
-     * @return abscissa of the vector
-     * @see Cartesian2D#Cartesian2D(double, double)
-     */
-    public abstract double getX();
-
-    /** Get the ordinate of the vector.
-     * @return ordinate of the vector
-     * @see Cartesian2D#Cartesian2D(double, double)
-     */
-    public abstract double getY();
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2DFormat.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2DFormat.java
deleted file mode 100644
index cb76596..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2DFormat.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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.twod;
-
-import java.text.FieldPosition;
-import java.text.NumberFormat;
-import java.text.ParsePosition;
-import java.util.Locale;
-
-import org.apache.commons.math4.exception.MathParseException;
-import org.apache.commons.math4.geometry.Vector;
-import org.apache.commons.math4.geometry.VectorFormat;
-import org.apache.commons.math4.util.CompositeFormat;
-
-/**
- * Formats a 2D vector in components list format "{x; y}".
- * <p>The prefix and suffix "{" and "}" and the separator "; " can be replaced by
- * any user-defined strings. The number format for components can be configured.</p>
- * <p>White space is ignored at parse time, even if it is in the prefix, suffix
- * or separator specifications. So even if the default separator does include a space
- * character that is used at format time, both input string "{1;1}" and
- * " { 1 ; 1 } " will be parsed without error and the same vector will be
- * returned. In the second case, however, the parse position after parsing will be
- * just after the closing curly brace, i.e. just before the trailing space.</p>
- * <p><b>Note:</b> using "," as a separator may interfere with the grouping separator
- * of the default {@link NumberFormat} for the current locale. Thus it is advised
- * to use a {@link NumberFormat} instance with disabled grouping in such a case.</p>
- *
- * @since 3.0
- */
-public class Vector2DFormat extends VectorFormat<Euclidean2D> {
-
-    /**
-     * Create an instance with default settings.
-     * <p>The instance uses the default prefix, suffix and separator:
-     * "{", "}", and "; " and the default number format for components.</p>
-     */
-    public Vector2DFormat() {
-        super(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR,
-              CompositeFormat.getDefaultNumberFormat());
-    }
-
-    /**
-     * Create an instance with a custom number format for components.
-     * @param format the custom format for components.
-     */
-    public Vector2DFormat(final NumberFormat format) {
-        super(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, format);
-    }
-
-    /**
-     * Create an instance with custom prefix, suffix and separator.
-     * @param prefix prefix to use instead of the default "{"
-     * @param suffix suffix to use instead of the default "}"
-     * @param separator separator to use instead of the default "; "
-     */
-    public Vector2DFormat(final String prefix, final String suffix,
-                         final String separator) {
-        super(prefix, suffix, separator, CompositeFormat.getDefaultNumberFormat());
-    }
-
-    /**
-     * Create an instance with custom prefix, suffix, separator and format
-     * for components.
-     * @param prefix prefix to use instead of the default "{"
-     * @param suffix suffix to use instead of the default "}"
-     * @param separator separator to use instead of the default "; "
-     * @param format the custom format for components.
-     */
-    public Vector2DFormat(final String prefix, final String suffix,
-                         final String separator, final NumberFormat format) {
-        super(prefix, suffix, separator, format);
-    }
-
-    /**
-     * Returns the default 2D vector format for the current locale.
-     * @return the default 2D vector format.
-     */
-    public static Vector2DFormat getInstance() {
-        return getInstance(Locale.getDefault());
-    }
-
-    /**
-     * Returns the default 2D vector format for the given locale.
-     * @param locale the specific locale used by the format.
-     * @return the 2D vector format specific to the given locale.
-     */
-    public static Vector2DFormat getInstance(final Locale locale) {
-        return new Vector2DFormat(CompositeFormat.getDefaultNumberFormat(locale));
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public StringBuffer format(final Vector<Euclidean2D> vector, final StringBuffer toAppendTo,
-                               final FieldPosition pos) {
-        final Vector2D p2 = (Vector2D) vector;
-        return format(toAppendTo, pos, p2.getX(), p2.getY());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Vector2D parse(final String source) throws MathParseException {
-        ParsePosition parsePosition = new ParsePosition(0);
-        Vector2D result = parse(source, parsePosition);
-        if (parsePosition.getIndex() == 0) {
-            throw new MathParseException(source,
-                                         parsePosition.getErrorIndex(),
-                                         Vector2D.class);
-        }
-        return result;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Vector2D parse(final String source, final ParsePosition pos) {
-        final double[] coordinates = parseCoordinates(2, source, pos);
-        if (coordinates == null) {
-            return null;
-        }
-        return new Cartesian2D(coordinates[0], coordinates[1]);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/AbstractConvexHullGenerator2D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/AbstractConvexHullGenerator2D.java
deleted file mode 100644
index d3ecc64..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/AbstractConvexHullGenerator2D.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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.twod.hull;
-
-import java.util.Collection;
-
-import org.apache.commons.math4.exception.ConvergenceException;
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.exception.NullArgumentException;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.math4.util.MathUtils;
-
-/**
- * Abstract base class for convex hull generators in the two-dimensional euclidean space.
- *
- * @since 3.3
- */
-abstract class AbstractConvexHullGenerator2D implements ConvexHullGenerator2D {
-
-    /** Default value for tolerance. */
-    private static final double DEFAULT_TOLERANCE = 1e-10;
-
-    /** Tolerance below which points are considered identical. */
-    private final double tolerance;
-
-    /**
-     * Indicates if collinear points on the hull shall be present in the output.
-     * If {@code false}, only the extreme points are added to the hull.
-     */
-    private final boolean includeCollinearPoints;
-
-    /**
-     * Simple constructor.
-     * <p>
-     * The default tolerance (1e-10) will be used to determine identical points.
-     *
-     * @param includeCollinearPoints indicates if collinear points on the hull shall be
-     * added as hull vertices
-     */
-    protected AbstractConvexHullGenerator2D(final boolean includeCollinearPoints) {
-        this(includeCollinearPoints, DEFAULT_TOLERANCE);
-    }
-
-    /**
-     * Simple constructor.
-     *
-     * @param includeCollinearPoints indicates if collinear points on the hull shall be
-     * added as hull vertices
-     * @param tolerance tolerance below which points are considered identical
-     */
-    protected AbstractConvexHullGenerator2D(final boolean includeCollinearPoints, final double tolerance) {
-        this.includeCollinearPoints = includeCollinearPoints;
-        this.tolerance = tolerance;
-    }
-
-    /**
-     * Get the tolerance below which points are considered identical.
-     * @return the tolerance below which points are considered identical
-     */
-    public double getTolerance() {
-        return tolerance;
-    }
-
-    /**
-     * Returns if collinear points on the hull will be added as hull vertices.
-     * @return {@code true} if collinear points are added as hull vertices, or {@code false}
-     * if only extreme points are present.
-     */
-    public boolean isIncludeCollinearPoints() {
-        return includeCollinearPoints;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public ConvexHull2D generate(final Collection<Cartesian2D> points)
-            throws NullArgumentException, ConvergenceException {
-        // check for null points
-        MathUtils.checkNotNull(points);
-
-        Collection<Cartesian2D> hullVertices = null;
-        if (points.size() < 2) {
-            hullVertices = points;
-        } else {
-            hullVertices = findHullVertices(points);
-        }
-
-        try {
-            return new ConvexHull2D(hullVertices.toArray(new Cartesian2D[hullVertices.size()]),
-                                    tolerance);
-        } catch (MathIllegalArgumentException e) {
-            // the hull vertices may not form a convex hull if the tolerance value is to large
-            throw new ConvergenceException();
-        }
-    }
-
-    /**
-     * Find the convex hull vertices from the set of input points.
-     * @param points the set of input points
-     * @return the convex hull vertices in CCW winding
-     */
-    protected abstract Collection<Cartesian2D> findHullVertices(Collection<Cartesian2D> points);
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/AklToussaintHeuristic.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/AklToussaintHeuristic.java
deleted file mode 100644
index e1d5009..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/AklToussaintHeuristic.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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.twod.hull;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-
-/**
- * A simple heuristic to improve the performance of convex hull algorithms.
- * <p>
- * The heuristic is based on the idea of a convex quadrilateral, which is formed by
- * four points with the lowest and highest x / y coordinates. Any point that lies inside
- * this quadrilateral can not be part of the convex hull and can thus be safely discarded
- * before generating the convex hull itself.
- * <p>
- * The complexity of the operation is O(n), and may greatly improve the time it takes to
- * construct the convex hull afterwards, depending on the point distribution.
- *
- * @see <a href="http://en.wikipedia.org/wiki/Convex_hull_algorithms#Akl-Toussaint_heuristic">
- * Akl-Toussaint heuristic (Wikipedia)</a>
- * @since 3.3
- */
-public final class AklToussaintHeuristic {
-
-    /** Hide utility constructor. */
-    private AklToussaintHeuristic() {
-    }
-
-    /**
-     * Returns a point set that is reduced by all points for which it is safe to assume
-     * that they are not part of the convex hull.
-     *
-     * @param points the original point set
-     * @return a reduced point set, useful as input for convex hull algorithms
-     */
-    public static Collection<Cartesian2D> reducePoints(final Collection<Cartesian2D> points) {
-
-        // find the leftmost point
-        int size = 0;
-        Cartesian2D minX = null;
-        Cartesian2D maxX = null;
-        Cartesian2D minY = null;
-        Cartesian2D maxY = null;
-        for (Cartesian2D p : points) {
-            if (minX == null || p.getX() < minX.getX()) {
-                minX = p;
-            }
-            if (maxX == null || p.getX() > maxX.getX()) {
-                maxX = p;
-            }
-            if (minY == null || p.getY() < minY.getY()) {
-                minY = p;
-            }
-            if (maxY == null || p.getY() > maxY.getY()) {
-                maxY = p;
-            }
-            size++;
-        }
-
-        if (size < 4) {
-            return points;
-        }
-
-        final List<Cartesian2D> quadrilateral = buildQuadrilateral(minY, maxX, maxY, minX);
-        // if the quadrilateral is not well formed, e.g. only 2 points, do not attempt to reduce
-        if (quadrilateral.size() < 3) {
-            return points;
-        }
-
-        final List<Cartesian2D> reducedPoints = new ArrayList<>(quadrilateral);
-        for (final Cartesian2D p : points) {
-            // check all points if they are within the quadrilateral
-            // in which case they can not be part of the convex hull
-            if (!insideQuadrilateral(p, quadrilateral)) {
-                reducedPoints.add(p);
-            }
-        }
-
-        return reducedPoints;
-    }
-
-    /**
-     * Build the convex quadrilateral with the found corner points (with min/max x/y coordinates).
-     *
-     * @param points the respective points with min/max x/y coordinate
-     * @return the quadrilateral
-     */
-    private static List<Cartesian2D> buildQuadrilateral(final Cartesian2D... points) {
-        List<Cartesian2D> quadrilateral = new ArrayList<>();
-        for (Cartesian2D p : points) {
-            if (!quadrilateral.contains(p)) {
-                quadrilateral.add(p);
-            }
-        }
-        return quadrilateral;
-    }
-
-    /**
-     * Checks if the given point is located within the convex quadrilateral.
-     * @param point the point to check
-     * @param quadrilateralPoints the convex quadrilateral, represented by 4 points
-     * @return {@code true} if the point is inside the quadrilateral, {@code false} otherwise
-     */
-    private static boolean insideQuadrilateral(final Cartesian2D point,
-                                               final List<Cartesian2D> quadrilateralPoints) {
-
-        Cartesian2D p1 = quadrilateralPoints.get(0);
-        Cartesian2D p2 = quadrilateralPoints.get(1);
-
-        if (point.equals(p1) || point.equals(p2)) {
-            return true;
-        }
-
-        // get the location of the point relative to the first two vertices
-        final double last = point.crossProduct(p1, p2);
-        final int size = quadrilateralPoints.size();
-        // loop through the rest of the vertices
-        for (int i = 1; i < size; i++) {
-            p1 = p2;
-            p2 = quadrilateralPoints.get((i + 1) == size ? 0 : i + 1);
-
-            if (point.equals(p1) || point.equals(p2)) {
-                return true;
-            }
-
-            // do side of line test: multiply the last location with this location
-            // if they are the same sign then the operation will yield a positive result
-            // -x * -y = +xy, x * y = +xy, -x * y = -xy, x * -y = -xy
-            if (last * point.crossProduct(p1, p2) < 0) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/ConvexHull2D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/ConvexHull2D.java
deleted file mode 100644
index 0ba9fa9..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/ConvexHull2D.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * 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.twod.hull;
-
-import java.io.Serializable;
-
-import org.apache.commons.numbers.arrays.LinearCombination;
-import org.apache.commons.numbers.core.Precision;
-import org.apache.commons.math4.exception.InsufficientDataException;
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-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.Segment;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.math4.geometry.hull.ConvexHull;
-import org.apache.commons.math4.geometry.partitioning.Region;
-import org.apache.commons.math4.geometry.partitioning.RegionFactory;
-
-/**
- * This class represents a convex hull in an two-dimensional euclidean space.
- *
- * @since 3.3
- */
-public class ConvexHull2D implements ConvexHull<Euclidean2D, Cartesian2D>, Serializable {
-
-    /** Serializable UID. */
-    private static final long serialVersionUID = 20140129L;
-
-    /** Vertices of the hull. */
-    private final Cartesian2D[] vertices;
-
-    /** Tolerance threshold used during creation of the hull vertices. */
-    private final double tolerance;
-
-    /**
-     * Line segments of the hull.
-     * The array is not serialized and will be created from the vertices on first access.
-     */
-    private transient Segment[] lineSegments;
-
-    /**
-     * Simple constructor.
-     * @param vertices the vertices of the convex hull, must be ordered
-     * @param tolerance tolerance below which points are considered identical
-     * @throws MathIllegalArgumentException if the vertices do not form a convex hull
-     */
-    public ConvexHull2D(final Cartesian2D[] vertices, final double tolerance)
-        throws MathIllegalArgumentException {
-
-        // assign tolerance as it will be used by the isConvex method
-        this.tolerance = tolerance;
-
-        if (!isConvex(vertices)) {
-            throw new MathIllegalArgumentException(LocalizedFormats.NOT_CONVEX);
-        }
-
-        this.vertices = vertices.clone();
-    }
-
-    /**
-     * Checks whether the given hull vertices form a convex hull.
-     * @param hullVertices the hull vertices
-     * @return {@code true} if the vertices form a convex hull, {@code false} otherwise
-     */
-    private boolean isConvex(final Cartesian2D[] hullVertices) {
-        if (hullVertices.length < 3) {
-            return true;
-        }
-
-        int sign = 0;
-        for (int i = 0; i < hullVertices.length; i++) {
-            final Cartesian2D p1 = hullVertices[i == 0 ? hullVertices.length - 1 : i - 1];
-            final Cartesian2D p2 = hullVertices[i];
-            final Cartesian2D p3 = hullVertices[i == hullVertices.length - 1 ? 0 : i + 1];
-
-            final Cartesian2D d1 = p2.subtract(p1);
-            final Cartesian2D d2 = p3.subtract(p2);
-
-            final double crossProduct = LinearCombination.value(d1.getX(), d2.getY(), -d1.getY(), d2.getX());
-            final int cmp = Precision.compareTo(crossProduct, 0.0, tolerance);
-            // in case of collinear points the cross product will be zero
-            if (cmp != 0.0) {
-                if (sign != 0.0 && cmp != sign) {
-                    return false;
-                }
-                sign = cmp;
-            }
-        }
-
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Cartesian2D[] getVertices() {
-        return vertices.clone();
-    }
-
-    /**
-     * Get the line segments of the convex hull, ordered.
-     * @return the line segments of the convex hull
-     */
-    public Segment[] getLineSegments() {
-        return retrieveLineSegments().clone();
-    }
-
-    /**
-     * Retrieve the line segments from the cached array or create them if needed.
-     *
-     * @return the array of line segments
-     */
-    private Segment[] retrieveLineSegments() {
-        if (lineSegments == null) {
-            // construct the line segments - handle special cases of 1 or 2 points
-            final int size = vertices.length;
-            if (size <= 1) {
-                this.lineSegments = new Segment[0];
-            } else if (size == 2) {
-                this.lineSegments = new Segment[1];
-                final Cartesian2D p1 = vertices[0];
-                final Cartesian2D p2 = vertices[1];
-                this.lineSegments[0] = new Segment(p1, p2, new Line(p1, p2, tolerance));
-            } else {
-                this.lineSegments = new Segment[size];
-                Cartesian2D firstPoint = null;
-                Cartesian2D lastPoint = null;
-                int index = 0;
-                for (Cartesian2D point : vertices) {
-                    if (lastPoint == null) {
-                        firstPoint = point;
-                        lastPoint = point;
-                    } else {
-                        this.lineSegments[index++] =
-                                new Segment(lastPoint, point, new Line(lastPoint, point, tolerance));
-                        lastPoint = point;
-                    }
-                }
-                this.lineSegments[index] =
-                        new Segment(lastPoint, firstPoint, new Line(lastPoint, firstPoint, tolerance));
-            }
-        }
-        return lineSegments;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Region<Euclidean2D> createRegion() throws InsufficientDataException {
-        if (vertices.length < 3) {
-            throw new InsufficientDataException();
-        }
-        final RegionFactory<Euclidean2D> factory = new RegionFactory<>();
-        final Segment[] segments = retrieveLineSegments();
-        final Line[] lineArray = new Line[segments.length];
-        for (int i = 0; i < segments.length; i++) {
-            lineArray[i] = segments[i].getLine();
-        }
-        return factory.buildConvex(lineArray);
-    }
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/ConvexHullGenerator2D.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/ConvexHullGenerator2D.java
deleted file mode 100644
index 0c49b91..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/ConvexHullGenerator2D.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.twod.hull;
-
-import java.util.Collection;
-
-import org.apache.commons.math4.exception.ConvergenceException;
-import org.apache.commons.math4.exception.NullArgumentException;
-import org.apache.commons.math4.geometry.euclidean.twod.Euclidean2D;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.math4.geometry.hull.ConvexHullGenerator;
-
-/**
- * Interface for convex hull generators in the two-dimensional euclidean space.
- *
- * @since 3.3
- */
-public interface ConvexHullGenerator2D extends ConvexHullGenerator<Euclidean2D, Cartesian2D> {
-
-    /** {@inheritDoc} */
-    @Override
-    ConvexHull2D generate(Collection<Cartesian2D> points) throws NullArgumentException, ConvergenceException;
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/MonotoneChain.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/MonotoneChain.java
deleted file mode 100644
index cbc98da..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/MonotoneChain.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * 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.twod.hull;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import org.apache.commons.math4.geometry.euclidean.twod.Line;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.numbers.core.Precision;
-
-/**
- * Implements Andrew's monotone chain method to generate the convex hull of a finite set of
- * points in the two-dimensional euclidean space.
- * <p>
- * The runtime complexity is O(n log n), with n being the number of input points. If the
- * point set is already sorted (by x-coordinate), the runtime complexity is O(n).
- * <p>
- * The implementation is not sensitive to collinear points on the hull. The parameter
- * {@code includeCollinearPoints} allows to control the behavior with regard to collinear points.
- * If {@code true}, all points on the boundary of the hull will be added to the hull vertices,
- * otherwise only the extreme points will be present. By default, collinear points are not added
- * as hull vertices.
- * <p>
- * The {@code tolerance} parameter (default: 1e-10) is used as epsilon criteria to determine
- * identical and collinear points.
- *
- * @see <a href="http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain">
- * Andrew's monotone chain algorithm (Wikibooks)</a>
- * @since 3.3
- */
-public class MonotoneChain extends AbstractConvexHullGenerator2D {
-
-    /**
-     * Create a new MonotoneChain instance.
-     */
-    public MonotoneChain() {
-        this(false);
-    }
-
-    /**
-     * Create a new MonotoneChain instance.
-     * @param includeCollinearPoints whether collinear points shall be added as hull vertices
-     */
-    public MonotoneChain(final boolean includeCollinearPoints) {
-        super(includeCollinearPoints);
-    }
-
-    /**
-     * Create a new MonotoneChain instance.
-     * @param includeCollinearPoints whether collinear points shall be added as hull vertices
-     * @param tolerance tolerance below which points are considered identical
-     */
-    public MonotoneChain(final boolean includeCollinearPoints, final double tolerance) {
-        super(includeCollinearPoints, tolerance);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Collection<Cartesian2D> findHullVertices(final Collection<Cartesian2D> points) {
-
-        final List<Cartesian2D> pointsSortedByXAxis = new ArrayList<>(points);
-
-        // sort the points in increasing order on the x-axis
-        Collections.sort(pointsSortedByXAxis, new Comparator<Cartesian2D>() {
-            /** {@inheritDoc} */
-            @Override
-            public int compare(final Cartesian2D o1, final Cartesian2D o2) {
-                final double tolerance = getTolerance();
-                // need to take the tolerance value into account, otherwise collinear points
-                // will not be handled correctly when building the upper/lower hull
-                final int diff = Precision.compareTo(o1.getX(), o2.getX(), tolerance);
-                if (diff == 0) {
-                    return Precision.compareTo(o1.getY(), o2.getY(), tolerance);
-                } else {
-                    return diff;
-                }
-            }
-        });
-
-        // build lower hull
-        final List<Cartesian2D> lowerHull = new ArrayList<>();
-        for (Cartesian2D p : pointsSortedByXAxis) {
-            updateHull(p, lowerHull);
-        }
-
-        // build upper hull
-        final List<Cartesian2D> upperHull = new ArrayList<>();
-        for (int idx = pointsSortedByXAxis.size() - 1; idx >= 0; idx--) {
-            final Cartesian2D p = pointsSortedByXAxis.get(idx);
-            updateHull(p, upperHull);
-        }
-
-        // concatenate the lower and upper hulls
-        // the last point of each list is omitted as it is repeated at the beginning of the other list
-        final List<Cartesian2D> hullVertices = new ArrayList<>(lowerHull.size() + upperHull.size() - 2);
-        for (int idx = 0; idx < lowerHull.size() - 1; idx++) {
-            hullVertices.add(lowerHull.get(idx));
-        }
-        for (int idx = 0; idx < upperHull.size() - 1; idx++) {
-            hullVertices.add(upperHull.get(idx));
-        }
-
-        // special case: if the lower and upper hull may contain only 1 point if all are identical
-        if (hullVertices.isEmpty() && ! lowerHull.isEmpty()) {
-            hullVertices.add(lowerHull.get(0));
-        }
-
-        return hullVertices;
-    }
-
-    /**
-     * Update the partial hull with the current point.
-     *
-     * @param point the current point
-     * @param hull the partial hull
-     */
-    private void updateHull(final Cartesian2D point, final List<Cartesian2D> hull) {
-        final double tolerance = getTolerance();
-
-        if (hull.size() == 1) {
-            // ensure that we do not add an identical point
-            final Cartesian2D p1 = hull.get(0);
-            if (p1.distance(point) < tolerance) {
-                return;
-            }
-        }
-
-        while (hull.size() >= 2) {
-            final int size = hull.size();
-            final Cartesian2D p1 = hull.get(size - 2);
-            final Cartesian2D p2 = hull.get(size - 1);
-
-            final double offset = new Line(p1, p2, tolerance).getOffset(point);
-            if (FastMath.abs(offset) < tolerance) {
-                // the point is collinear to the line (p1, p2)
-
-                final double distanceToCurrent = p1.distance(point);
-                if (distanceToCurrent < tolerance || p2.distance(point) < tolerance) {
-                    // the point is assumed to be identical to either p1 or p2
-                    return;
-                }
-
-                final double distanceToLast = p1.distance(p2);
-                if (isIncludeCollinearPoints()) {
-                    final int index = distanceToCurrent < distanceToLast ? size - 1 : size;
-                    hull.add(index, point);
-                } else {
-                    if (distanceToCurrent > distanceToLast) {
-                        hull.remove(size - 1);
-                        hull.add(point);
-                    }
-                }
-                return;
-            } else if (offset > 0) {
-                hull.remove(size - 1);
-            } else {
-                break;
-            }
-        }
-        hull.add(point);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/package-info.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/package-info.java
deleted file mode 100644
index 120f5c7..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/hull/package-info.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- *
- * <p>
- * This package provides algorithms to generate the convex hull
- * for a set of points in an two-dimensional euclidean space.
- * </p>
- *
- */
-package org.apache.commons.math4.geometry.euclidean.twod.hull;
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/package-info.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/package-info.java
deleted file mode 100644
index 7872044..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/twod/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- *
- * <p>
- * This package provides basic 2D geometry components.
- * </p>
- *
- */
-package org.apache.commons.math4.geometry.euclidean.twod;
diff --git a/src/main/java/org/apache/commons/math4/geometry/hull/ConvexHull.java b/src/main/java/org/apache/commons/math4/geometry/hull/ConvexHull.java
deleted file mode 100644
index b78d229..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/hull/ConvexHull.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.hull;
-
-import java.io.Serializable;
-
-import org.apache.commons.math4.exception.InsufficientDataException;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.partitioning.Region;
-
-/**
- * This class represents a convex hull.
- *
- * @param <S> Space type.
- * @param <P> Point type.
- * @since 3.3
- */
-public interface ConvexHull<S extends Space, P extends Point<S>> extends Serializable {
-
-    /**
-     * Get the vertices of the convex hull.
-     * @return vertices of the convex hull
-     */
-    P[] getVertices();
-
-    /**
-     * Returns a new region that is enclosed by the convex hull.
-     * @return the region enclosed by the convex hull
-     * @throws InsufficientDataException if the number of vertices is not enough to
-     * build a region in the respective space
-     */
-    Region<S> createRegion() throws InsufficientDataException;
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/hull/ConvexHullGenerator.java b/src/main/java/org/apache/commons/math4/geometry/hull/ConvexHullGenerator.java
deleted file mode 100644
index eadc0af..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/hull/ConvexHullGenerator.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.hull;
-
-import java.util.Collection;
-
-import org.apache.commons.math4.exception.ConvergenceException;
-import org.apache.commons.math4.exception.NullArgumentException;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-
-/**
- * Interface for convex hull generators.
- *
- * @param <S> Type of the {@link Space}
- * @param <P> Type of the {@link Point}
- *
- * @see <a href="http://en.wikipedia.org/wiki/Convex_hull">Convex Hull (Wikipedia)</a>
- * @see <a href="http://mathworld.wolfram.com/ConvexHull.html">Convex Hull (MathWorld)</a>
- *
- * @since 3.3
- */
-public interface ConvexHullGenerator<S extends Space, P extends Point<S>> {
-
-    /**
-     * Builds the convex hull from the set of input points.
-     *
-     * @param points the set of input points
-     * @return the convex hull
-     * @throws NullArgumentException if the input collection is {@code null}
-     * @throws ConvergenceException if generator fails to generate a convex hull for
-     * the given set of input points
-     */
-    ConvexHull<S, P> generate(Collection<P> points) throws NullArgumentException, ConvergenceException;
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/hull/package-info.java b/src/main/java/org/apache/commons/math4/geometry/hull/package-info.java
deleted file mode 100644
index 70468bf..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/hull/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- *
- * <p>
- * This package provides interfaces and classes related to the convex hull problem.
- * </p>
- *
- */
-package org.apache.commons.math4.geometry.hull;
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/AbstractRegion.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/AbstractRegion.java
deleted file mode 100644
index a52c38f..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/AbstractRegion.java
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
- * 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.partitioning;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.TreeSet;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.Vector;
-
-/** Abstract class for all regions, independently of geometry type or dimension.
-
- * @param <S> Type of the space.
- * @param <T> Type of the sub-space.
-
- * @since 3.0
- */
-public abstract class AbstractRegion<S extends Space, T extends Space> implements Region<S> {
-
-    /** Inside/Outside BSP tree. */
-    private BSPTree<S> tree;
-
-    /** Tolerance below which points are considered to belong to hyperplanes. */
-    private final double tolerance;
-
-    /** Size of the instance. */
-    private double size;
-
-    /** Barycenter. */
-    private Point<S> barycenter;
-
-    /** Build a region representing the whole space.
-     * @param tolerance tolerance below which points are considered identical.
-     */
-    protected AbstractRegion(final double tolerance) {
-        this.tree      = new BSPTree<>(Boolean.TRUE);
-        this.tolerance = tolerance;
-    }
-
-    /** Build a region from an inside/outside BSP tree.
-     * <p>The leaf nodes of the BSP tree <em>must</em> have a
-     * {@code Boolean} attribute representing the inside status of
-     * the corresponding cell (true for inside cells, false for outside
-     * cells). In order to avoid building too many small objects, it is
-     * recommended to use the predefined constants
-     * {@code Boolean.TRUE} and {@code Boolean.FALSE}. The
-     * tree also <em>must</em> have either null internal nodes or
-     * internal nodes representing the boundary as specified in the
-     * {@link #getTree getTree} method).</p>
-     * @param tree inside/outside BSP tree representing the region
-     * @param tolerance tolerance below which points are considered identical.
-     */
-    protected AbstractRegion(final BSPTree<S> tree, final double tolerance) {
-        this.tree      = tree;
-        this.tolerance = tolerance;
-    }
-
-    /** Build a Region from a Boundary REPresentation (B-rep).
-     * <p>The boundary is provided as a collection of {@link
-     * SubHyperplane sub-hyperplanes}. Each sub-hyperplane has the
-     * interior part of the region on its minus side and the exterior on
-     * its plus side.</p>
-     * <p>The boundary elements can be in any order, and can form
-     * several non-connected sets (like for example polygons with holes
-     * or a set of disjoints polyhedrons considered as a whole). In
-     * fact, the elements do not even need to be connected together
-     * (their topological connections are not used here). However, if the
-     * boundary does not really separate an inside open from an outside
-     * open (open having here its topological meaning), then subsequent
-     * calls to the {@link #checkPoint(Point) checkPoint} method will not be
-     * meaningful anymore.</p>
-     * <p>If the boundary is empty, the region will represent the whole
-     * space.</p>
-     * @param boundary collection of boundary elements, as a
-     * collection of {@link SubHyperplane SubHyperplane} objects
-     * @param tolerance tolerance below which points are considered identical.
-     */
-    protected AbstractRegion(final Collection<SubHyperplane<S>> boundary, final double tolerance) {
-
-        this.tolerance = tolerance;
-
-        if (boundary.size() == 0) {
-
-            // the tree represents the whole space
-            tree = new BSPTree<>(Boolean.TRUE);
-
-        } else {
-
-            // sort the boundary elements in decreasing size order
-            // (we don't want equal size elements to be removed, so
-            // we use a trick to fool the TreeSet)
-            final TreeSet<SubHyperplane<S>> ordered = new TreeSet<>(new Comparator<SubHyperplane<S>>() {
-                /** {@inheritDoc} */
-                @Override
-                public int compare(final SubHyperplane<S> o1, final SubHyperplane<S> o2) {
-                    final double size1 = o1.getSize();
-                    final double size2 = o2.getSize();
-                    return (size2 < size1) ? -1 : ((o1 == o2) ? 0 : +1);
-                }
-            });
-            ordered.addAll(boundary);
-
-            // build the tree top-down
-            tree = new BSPTree<>();
-            insertCuts(tree, ordered);
-
-            // set up the inside/outside flags
-            tree.visit(new BSPTreeVisitor<S>() {
-
-                /** {@inheritDoc} */
-                @Override
-                public Order visitOrder(final BSPTree<S> node) {
-                    return Order.PLUS_SUB_MINUS;
-                }
-
-                /** {@inheritDoc} */
-                @Override
-                public void visitInternalNode(final BSPTree<S> node) {
-                }
-
-                /** {@inheritDoc} */
-                @Override
-                public void visitLeafNode(final BSPTree<S> node) {
-                    if (node.getParent() == null || node == node.getParent().getMinus()) {
-                        node.setAttribute(Boolean.TRUE);
-                    } else {
-                        node.setAttribute(Boolean.FALSE);
-                    }
-                }
-            });
-
-        }
-
-    }
-
-    /** Build a convex region from an array of bounding hyperplanes.
-     * @param hyperplanes array of bounding hyperplanes (if null, an
-     * empty region will be built)
-     * @param tolerance tolerance below which points are considered identical.
-     */
-    public AbstractRegion(final Hyperplane<S>[] hyperplanes, final double tolerance) {
-        this.tolerance = tolerance;
-        if ((hyperplanes == null) || (hyperplanes.length == 0)) {
-            tree = new BSPTree<>(Boolean.FALSE);
-        } else {
-
-            // use the first hyperplane to build the right class
-            tree = hyperplanes[0].wholeSpace().getTree(false);
-
-            // chop off parts of the space
-            BSPTree<S> node = tree;
-            node.setAttribute(Boolean.TRUE);
-            for (final Hyperplane<S> hyperplane : hyperplanes) {
-                if (node.insertCut(hyperplane)) {
-                    node.setAttribute(null);
-                    node.getPlus().setAttribute(Boolean.FALSE);
-                    node = node.getMinus();
-                    node.setAttribute(Boolean.TRUE);
-                }
-            }
-
-        }
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public abstract AbstractRegion<S, T> buildNew(BSPTree<S> newTree);
-
-    /** Get the tolerance below which points are considered to belong to hyperplanes.
-     * @return tolerance below which points are considered to belong to hyperplanes
-     */
-    public double getTolerance() {
-        return tolerance;
-    }
-
-    /** Recursively build a tree by inserting cut sub-hyperplanes.
-     * @param node current tree node (it is a leaf node at the beginning
-     * of the call)
-     * @param boundary collection of edges belonging to the cell defined
-     * by the node
-     */
-    private void insertCuts(final BSPTree<S> node, final Collection<SubHyperplane<S>> boundary) {
-
-        final Iterator<SubHyperplane<S>> iterator = boundary.iterator();
-
-        // build the current level
-        Hyperplane<S> inserted = null;
-        while ((inserted == null) && iterator.hasNext()) {
-            inserted = iterator.next().getHyperplane();
-            if (!node.insertCut(inserted.copySelf())) {
-                inserted = null;
-            }
-        }
-
-        if (!iterator.hasNext()) {
-            return;
-        }
-
-        // distribute the remaining edges in the two sub-trees
-        final ArrayList<SubHyperplane<S>> plusList  = new ArrayList<>();
-        final ArrayList<SubHyperplane<S>> minusList = new ArrayList<>();
-        while (iterator.hasNext()) {
-            final SubHyperplane<S> other = iterator.next();
-            final SubHyperplane.SplitSubHyperplane<S> split = other.split(inserted);
-            switch (split.getSide()) {
-            case PLUS:
-                plusList.add(other);
-                break;
-            case MINUS:
-                minusList.add(other);
-                break;
-            case BOTH:
-                plusList.add(split.getPlus());
-                minusList.add(split.getMinus());
-                break;
-            default:
-                // ignore the sub-hyperplanes belonging to the cut hyperplane
-            }
-        }
-
-        // recurse through lower levels
-        insertCuts(node.getPlus(),  plusList);
-        insertCuts(node.getMinus(), minusList);
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public AbstractRegion<S, T> copySelf() {
-        return buildNew(tree.copySelf());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isEmpty() {
-        return isEmpty(tree);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isEmpty(final BSPTree<S> node) {
-
-        // we use a recursive function rather than the BSPTreeVisitor
-        // interface because we can stop visiting the tree as soon as we
-        // have found an inside cell
-
-        if (node.getCut() == null) {
-            // if we find an inside node, the region is not empty
-            return !((Boolean) node.getAttribute());
-        }
-
-        // check both sides of the sub-tree
-        return isEmpty(node.getMinus()) && isEmpty(node.getPlus());
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isFull() {
-        return isFull(tree);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isFull(final BSPTree<S> node) {
-
-        // we use a recursive function rather than the BSPTreeVisitor
-        // interface because we can stop visiting the tree as soon as we
-        // have found an outside cell
-
-        if (node.getCut() == null) {
-            // if we find an outside node, the region does not cover full space
-            return (Boolean) node.getAttribute();
-        }
-
-        // check both sides of the sub-tree
-        return isFull(node.getMinus()) && isFull(node.getPlus());
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean contains(final Region<S> region) {
-        return new RegionFactory<S>().difference(region, this).isEmpty();
-    }
-
-    /** {@inheritDoc}
-     * @since 3.3
-     */
-    @Override
-    public BoundaryProjection<S> projectToBoundary(final Point<S> point) {
-        final BoundaryProjector<S, T> projector = new BoundaryProjector<>(point);
-        getTree(true).visit(projector);
-        return projector.getProjection();
-    }
-
-    /** Check a point with respect to the region.
-     * @param point point to check
-     * @return a code representing the point status: either {@link
-     * Region.Location#INSIDE}, {@link Region.Location#OUTSIDE} or
-     * {@link Region.Location#BOUNDARY}
-     */
-//    public Location checkPoint(final Vector<S> point) {
-//        return checkPoint((Point<S>) point);
-//    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Location checkPoint(final Point<S> point) {
-        return checkPoint(tree, point);
-    }
-
-    /** Check a point with respect to the region starting at a given node.
-     * @param node root node of the region
-     * @param point point to check
-     * @return a code representing the point status: either {@link
-     * Region.Location#INSIDE INSIDE}, {@link Region.Location#OUTSIDE
-     * OUTSIDE} or {@link Region.Location#BOUNDARY BOUNDARY}
-     */
-    protected Location checkPoint(final BSPTree<S> node, final Vector<S> point) {
-        return checkPoint(node, (Point<S>) point);
-    }
-
-    /** Check a point with respect to the region starting at a given node.
-     * @param node root node of the region
-     * @param point point to check
-     * @return a code representing the point status: either {@link
-     * Region.Location#INSIDE INSIDE}, {@link Region.Location#OUTSIDE
-     * OUTSIDE} or {@link Region.Location#BOUNDARY BOUNDARY}
-     */
-    protected Location checkPoint(final BSPTree<S> node, final Point<S> point) {
-        final BSPTree<S> cell = node.getCell(point, tolerance);
-        if (cell.getCut() == null) {
-            // the point is in the interior of a cell, just check the attribute
-            return ((Boolean) cell.getAttribute()) ? Location.INSIDE : Location.OUTSIDE;
-        }
-
-        // the point is on a cut-sub-hyperplane, is it on a boundary ?
-        final Location minusCode = checkPoint(cell.getMinus(), point);
-        final Location plusCode  = checkPoint(cell.getPlus(),  point);
-        return (minusCode == plusCode) ? minusCode : Location.BOUNDARY;
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public BSPTree<S> getTree(final boolean includeBoundaryAttributes) {
-        if (includeBoundaryAttributes && (tree.getCut() != null) && (tree.getAttribute() == null)) {
-            // compute the boundary attributes
-            tree.visit(new BoundaryBuilder<S>());
-        }
-        return tree;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getBoundarySize() {
-        final BoundarySizeVisitor<S> visitor = new BoundarySizeVisitor<>();
-        getTree(true).visit(visitor);
-        return visitor.getSize();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getSize() {
-        if (barycenter == null) {
-            computeGeometricalProperties();
-        }
-        return size;
-    }
-
-    /** Set the size of the instance.
-     * @param size size of the instance
-     */
-    protected void setSize(final double size) {
-        this.size = size;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Point<S> getBarycenter() {
-        if (barycenter == null) {
-            computeGeometricalProperties();
-        }
-        return barycenter;
-    }
-
-    /** Set the barycenter of the instance.
-     * @param barycenter barycenter of the instance
-     */
-    protected void setBarycenter(final Vector<S> barycenter) {
-        setBarycenter((Point<S>) barycenter);
-    }
-
-    /** Set the barycenter of the instance.
-     * @param barycenter barycenter of the instance
-     */
-    protected void setBarycenter(final Point<S> barycenter) {
-        this.barycenter = barycenter;
-    }
-
-    /** Compute some geometrical properties.
-     * <p>The properties to compute are the barycenter and the size.</p>
-     */
-    protected abstract void computeGeometricalProperties();
-
-    /** {@inheritDoc} */
-    @Override
-    public SubHyperplane<S> intersection(final SubHyperplane<S> sub) {
-        return recurseIntersection(tree, sub);
-    }
-
-    /** Recursively compute the parts of a sub-hyperplane that are
-     * contained in the region.
-     * @param node current BSP tree node
-     * @param sub sub-hyperplane traversing the region
-     * @return filtered sub-hyperplane
-     */
-    private SubHyperplane<S> recurseIntersection(final BSPTree<S> node, final SubHyperplane<S> sub) {
-
-        if (node.getCut() == null) {
-            return (Boolean) node.getAttribute() ? sub.copySelf() : null;
-        }
-
-        final Hyperplane<S> hyperplane = node.getCut().getHyperplane();
-        final SubHyperplane.SplitSubHyperplane<S> split = sub.split(hyperplane);
-        if (split.getPlus() != null) {
-            if (split.getMinus() != null) {
-                // both sides
-                final SubHyperplane<S> plus  = recurseIntersection(node.getPlus(),  split.getPlus());
-                final SubHyperplane<S> minus = recurseIntersection(node.getMinus(), split.getMinus());
-                if (plus == null) {
-                    return minus;
-                } else if (minus == null) {
-                    return plus;
-                } else {
-                    return plus.reunite(minus);
-                }
-            } else {
-                // only on plus side
-                return recurseIntersection(node.getPlus(), sub);
-            }
-        } else if (split.getMinus() != null) {
-            // only on minus side
-            return recurseIntersection(node.getMinus(), sub);
-        } else {
-            // on hyperplane
-            return recurseIntersection(node.getPlus(),
-                                       recurseIntersection(node.getMinus(), sub));
-        }
-
-    }
-
-    /** Transform a region.
-     * <p>Applying a transform to a region consist in applying the
-     * transform to all the hyperplanes of the underlying BSP tree and
-     * of the boundary (and also to the sub-hyperplanes embedded in
-     * these hyperplanes) and to the barycenter. The instance is not
-     * modified, a new instance is built.</p>
-     * @param transform transform to apply
-     * @return a new region, resulting from the application of the
-     * transform to the instance
-     */
-    public AbstractRegion<S, T> applyTransform(final Transform<S, T> transform) {
-
-        // transform the tree, except for boundary attribute splitters
-        final Map<BSPTree<S>, BSPTree<S>> map = new HashMap<>();
-        final BSPTree<S> transformedTree = recurseTransform(getTree(false), transform, map);
-
-        // set up the boundary attributes splitters
-        for (final Map.Entry<BSPTree<S>, BSPTree<S>> entry : map.entrySet()) {
-            if (entry.getKey().getCut() != null) {
-                @SuppressWarnings("unchecked")
-                BoundaryAttribute<S> original = (BoundaryAttribute<S>) entry.getKey().getAttribute();
-                if (original != null) {
-                    @SuppressWarnings("unchecked")
-                    BoundaryAttribute<S> transformed = (BoundaryAttribute<S>) entry.getValue().getAttribute();
-                    for (final BSPTree<S> splitter : original.getSplitters()) {
-                        transformed.getSplitters().add(map.get(splitter));
-                    }
-                }
-            }
-        }
-
-        return buildNew(transformedTree);
-
-    }
-
-    /** Recursively transform an inside/outside BSP-tree.
-     * @param node current BSP tree node
-     * @param transform transform to apply
-     * @param map transformed nodes map
-     * @return a new tree
-     */
-    @SuppressWarnings("unchecked")
-    private BSPTree<S> recurseTransform(final BSPTree<S> node, final Transform<S, T> transform,
-                                        final Map<BSPTree<S>, BSPTree<S>> map) {
-
-        final BSPTree<S> transformedNode;
-        if (node.getCut() == null) {
-            transformedNode = new BSPTree<>(node.getAttribute());
-        } else {
-
-            final SubHyperplane<S>  sub = node.getCut();
-            final SubHyperplane<S> tSub = ((AbstractSubHyperplane<S, T>) sub).applyTransform(transform);
-            BoundaryAttribute<S> attribute = (BoundaryAttribute<S>) node.getAttribute();
-            if (attribute != null) {
-                final SubHyperplane<S> tPO = (attribute.getPlusOutside() == null) ?
-                    null : ((AbstractSubHyperplane<S, T>) attribute.getPlusOutside()).applyTransform(transform);
-                final SubHyperplane<S> tPI = (attribute.getPlusInside()  == null) ?
-                    null  : ((AbstractSubHyperplane<S, T>) attribute.getPlusInside()).applyTransform(transform);
-                // we start with an empty list of splitters, it will be filled in out of recursion
-                attribute = new BoundaryAttribute<>(tPO, tPI, new NodesSet<S>());
-            }
-
-            transformedNode = new BSPTree<>(tSub,
-                                             recurseTransform(node.getPlus(),  transform, map),
-                                             recurseTransform(node.getMinus(), transform, map),
-                                             attribute);
-        }
-
-        map.put(node, transformedNode);
-        return transformedNode;
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/AbstractSubHyperplane.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/AbstractSubHyperplane.java
deleted file mode 100644
index 275269e..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/AbstractSubHyperplane.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * 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.partitioning;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.math4.geometry.Space;
-
-/** This class implements the dimension-independent parts of {@link SubHyperplane}.
-
- * <p>sub-hyperplanes are obtained when parts of an {@link
- * Hyperplane hyperplane} are chopped off by other hyperplanes that
- * intersect it. The remaining part is a convex region. Such objects
- * appear in {@link BSPTree BSP trees} as the intersection of a cut
- * hyperplane with the convex region which it splits, the chopping
- * hyperplanes are the cut hyperplanes closer to the tree root.</p>
-
- * @param <S> Type of the embedding space.
- * @param <T> Type of the embedded sub-space.
-
- * @since 3.0
- */
-public abstract class AbstractSubHyperplane<S extends Space, T extends Space>
-    implements SubHyperplane<S> {
-
-    /** Underlying hyperplane. */
-    private final Hyperplane<S> hyperplane;
-
-    /** Remaining region of the hyperplane. */
-    private final Region<T> remainingRegion;
-
-    /** Build a sub-hyperplane from an hyperplane and a region.
-     * @param hyperplane underlying hyperplane
-     * @param remainingRegion remaining region of the hyperplane
-     */
-    protected AbstractSubHyperplane(final Hyperplane<S> hyperplane,
-                                    final Region<T> remainingRegion) {
-        this.hyperplane      = hyperplane;
-        this.remainingRegion = remainingRegion;
-    }
-
-    /** Build a sub-hyperplane from an hyperplane and a region.
-     * @param hyper underlying hyperplane
-     * @param remaining remaining region of the hyperplane
-     * @return a new sub-hyperplane
-     */
-    protected abstract AbstractSubHyperplane<S, T> buildNew(final Hyperplane<S> hyper,
-                                                            final Region<T> remaining);
-
-    /** {@inheritDoc} */
-    @Override
-    public AbstractSubHyperplane<S, T> copySelf() {
-        return buildNew(hyperplane.copySelf(), remainingRegion);
-    }
-
-    /** Get the underlying hyperplane.
-     * @return underlying hyperplane
-     */
-    @Override
-    public Hyperplane<S> getHyperplane() {
-        return hyperplane;
-    }
-
-    /** Get the remaining region of the hyperplane.
-     * <p>The returned region is expressed in the canonical hyperplane
-     * frame and has the hyperplane dimension. For example a chopped
-     * hyperplane in the 3D euclidean is a 2D plane and the
-     * corresponding region is a convex 2D polygon.</p>
-     * @return remaining region of the hyperplane
-     */
-    public Region<T> getRemainingRegion() {
-        return remainingRegion;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getSize() {
-        return remainingRegion.getSize();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public AbstractSubHyperplane<S, T> reunite(final SubHyperplane<S> other) {
-        @SuppressWarnings("unchecked")
-        AbstractSubHyperplane<S, T> o = (AbstractSubHyperplane<S, T>) other;
-        return buildNew(hyperplane,
-                        new RegionFactory<T>().union(remainingRegion, o.remainingRegion));
-    }
-
-    /** Apply a transform to the instance.
-     * <p>The instance must be a (D-1)-dimension sub-hyperplane with
-     * respect to the transform <em>not</em> a (D-2)-dimension
-     * sub-hyperplane the transform knows how to transform by
-     * itself. The transform will consist in transforming first the
-     * hyperplane and then the all region using the various methods
-     * provided by the transform.</p>
-     * @param transform D-dimension transform to apply
-     * @return the transformed instance
-     */
-    public AbstractSubHyperplane<S, T> applyTransform(final Transform<S, T> transform) {
-        final Hyperplane<S> tHyperplane = transform.apply(hyperplane);
-
-        // transform the tree, except for boundary attribute splitters
-        final Map<BSPTree<T>, BSPTree<T>> map = new HashMap<>();
-        final BSPTree<T> tTree =
-            recurseTransform(remainingRegion.getTree(false), tHyperplane, transform, map);
-
-        // set up the boundary attributes splitters
-        for (final Map.Entry<BSPTree<T>, BSPTree<T>> entry : map.entrySet()) {
-            if (entry.getKey().getCut() != null) {
-                @SuppressWarnings("unchecked")
-                BoundaryAttribute<T> original = (BoundaryAttribute<T>) entry.getKey().getAttribute();
-                if (original != null) {
-                    @SuppressWarnings("unchecked")
-                    BoundaryAttribute<T> transformed = (BoundaryAttribute<T>) entry.getValue().getAttribute();
-                    for (final BSPTree<T> splitter : original.getSplitters()) {
-                        transformed.getSplitters().add(map.get(splitter));
-                    }
-                }
-            }
-        }
-
-        return buildNew(tHyperplane, remainingRegion.buildNew(tTree));
-
-    }
-
-    /** Recursively transform a BSP-tree from a sub-hyperplane.
-     * @param node current BSP tree node
-     * @param transformed image of the instance hyperplane by the transform
-     * @param transform transform to apply
-     * @param map transformed nodes map
-     * @return a new tree
-     */
-    private BSPTree<T> recurseTransform(final BSPTree<T> node,
-                                        final Hyperplane<S> transformed,
-                                        final Transform<S, T> transform,
-                                        final Map<BSPTree<T>, BSPTree<T>> map) {
-
-        final BSPTree<T> transformedNode;
-        if (node.getCut() == null) {
-            transformedNode = new BSPTree<>(node.getAttribute());
-        } else {
-
-            @SuppressWarnings("unchecked")
-            BoundaryAttribute<T> attribute = (BoundaryAttribute<T>) node.getAttribute();
-            if (attribute != null) {
-                final SubHyperplane<T> tPO = (attribute.getPlusOutside() == null) ?
-                    null : transform.apply(attribute.getPlusOutside(), hyperplane, transformed);
-                final SubHyperplane<T> tPI = (attribute.getPlusInside() == null) ?
-                    null : transform.apply(attribute.getPlusInside(), hyperplane, transformed);
-                // we start with an empty list of splitters, it will be filled in out of recursion
-                attribute = new BoundaryAttribute<>(tPO, tPI, new NodesSet<T>());
-            }
-
-            transformedNode = new BSPTree<>(transform.apply(node.getCut(), hyperplane, transformed),
-                    recurseTransform(node.getPlus(),  transformed, transform, map),
-                    recurseTransform(node.getMinus(), transformed, transform, map),
-                    attribute);
-        }
-
-        map.put(node, transformedNode);
-        return transformedNode;
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public abstract SplitSubHyperplane<S> split(Hyperplane<S> hyper);
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isEmpty() {
-        return remainingRegion.isEmpty();
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/BSPTree.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/BSPTree.java
deleted file mode 100644
index 0599d89..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/BSPTree.java
+++ /dev/null
@@ -1,784 +0,0 @@
-/*
- * 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.partitioning;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.math4.exception.MathInternalError;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.util.FastMath;
-
-/** This class represent a Binary Space Partition tree.
-
- * <p>BSP trees are an efficient way to represent space partitions and
- * to associate attributes with each cell. Each node in a BSP tree
- * represents a convex region which is partitioned in two convex
- * sub-regions at each side of a cut hyperplane. The root tree
- * contains the complete space.</p>
-
- * <p>The main use of such partitions is to use a boolean attribute to
- * define an inside/outside property, hence representing arbitrary
- * polytopes (line segments in 1D, polygons in 2D and polyhedrons in
- * 3D) and to operate on them.</p>
-
- * <p>Another example would be to represent Voronoi tesselations, the
- * attribute of each cell holding the defining point of the cell.</p>
-
- * <p>The application-defined attributes are shared among copied
- * instances and propagated to split parts. These attributes are not
- * used by the BSP-tree algorithms themselves, so the application can
- * use them for any purpose. Since the tree visiting method holds
- * internal and leaf nodes differently, it is possible to use
- * different classes for internal nodes attributes and leaf nodes
- * attributes. This should be used with care, though, because if the
- * tree is modified in any way after attributes have been set, some
- * internal nodes may become leaf nodes and some leaf nodes may become
- * internal nodes.</p>
-
- * <p>One of the main sources for the development of this package was
- * Bruce Naylor, John Amanatides and William Thibault paper <a
- * href="http://www.cs.yorku.ca/~amana/research/bsptSetOp.pdf">Merging
- * BSP Trees Yields Polyhedral Set Operations</a> Proc. Siggraph '90,
- * Computer Graphics 24(4), August 1990, pp 115-124, published by the
- * Association for Computing Machinery (ACM).</p>
-
- * @param <S> Type of the space.
-
- * @since 3.0
- */
-public class BSPTree<S extends Space> {
-
-    /** Cut sub-hyperplane. */
-    private SubHyperplane<S> cut;
-
-    /** Tree at the plus side of the cut hyperplane. */
-    private BSPTree<S> plus;
-
-    /** Tree at the minus side of the cut hyperplane. */
-    private BSPTree<S> minus;
-
-    /** Parent tree. */
-    private BSPTree<S> parent;
-
-    /** Application-defined attribute. */
-    private Object attribute;
-
-    /** Build a tree having only one root cell representing the whole space.
-     */
-    public BSPTree() {
-        cut       = null;
-        plus      = null;
-        minus     = null;
-        parent    = null;
-        attribute = null;
-    }
-
-    /** Build a tree having only one root cell representing the whole space.
-     * @param attribute attribute of the tree (may be null)
-     */
-    public BSPTree(final Object attribute) {
-        cut    = null;
-        plus   = null;
-        minus  = null;
-        parent = null;
-        this.attribute = attribute;
-    }
-
-    /** Build a BSPTree from its underlying elements.
-     * <p>This method does <em>not</em> perform any verification on
-     * consistency of its arguments, it should therefore be used only
-     * when then caller knows what it is doing.</p>
-     * <p>This method is mainly useful to build trees
-     * bottom-up. Building trees top-down is realized with the help of
-     * method {@link #insertCut insertCut}.</p>
-     * @param cut cut sub-hyperplane for the tree
-     * @param plus plus side sub-tree
-     * @param minus minus side sub-tree
-     * @param attribute attribute associated with the node (may be null)
-     * @see #insertCut
-     */
-    public BSPTree(final SubHyperplane<S> cut, final BSPTree<S> plus, final BSPTree<S> minus,
-                   final Object attribute) {
-        this.cut       = cut;
-        this.plus      = plus;
-        this.minus     = minus;
-        this.parent    = null;
-        this.attribute = attribute;
-        plus.parent    = this;
-        minus.parent   = this;
-    }
-
-    /** Insert a cut sub-hyperplane in a node.
-     * <p>The sub-tree starting at this node will be completely
-     * overwritten. The new cut sub-hyperplane will be built from the
-     * intersection of the provided hyperplane with the cell. If the
-     * hyperplane does intersect the cell, the cell will have two
-     * children cells with {@code null} attributes on each side of
-     * the inserted cut sub-hyperplane. If the hyperplane does not
-     * intersect the cell then <em>no</em> cut hyperplane will be
-     * inserted and the cell will be changed to a leaf cell. The
-     * attribute of the node is never changed.</p>
-     * <p>This method is mainly useful when called on leaf nodes
-     * (i.e. nodes for which {@link #getCut getCut} returns
-     * {@code null}), in this case it provides a way to build a
-     * tree top-down (whereas the {@link #BSPTree(SubHyperplane,
-     * BSPTree, BSPTree, Object) 4 arguments constructor} is devoted to
-     * build trees bottom-up).</p>
-     * @param hyperplane hyperplane to insert, it will be chopped in
-     * order to fit in the cell defined by the parent nodes of the
-     * instance
-     * @return true if a cut sub-hyperplane has been inserted (i.e. if
-     * the cell now has two leaf child nodes)
-     * @see #BSPTree(SubHyperplane, BSPTree, BSPTree, Object)
-     */
-    public boolean insertCut(final Hyperplane<S> hyperplane) {
-
-        if (cut != null) {
-            plus.parent  = null;
-            minus.parent = null;
-        }
-
-        final SubHyperplane<S> chopped = fitToCell(hyperplane.wholeHyperplane());
-        if (chopped == null || chopped.isEmpty()) {
-            cut          = null;
-            plus         = null;
-            minus        = null;
-            return false;
-        }
-
-        cut          = chopped;
-        plus         = new BSPTree<>();
-        plus.parent  = this;
-        minus        = new BSPTree<>();
-        minus.parent = this;
-        return true;
-
-    }
-
-    /** Copy the instance.
-     * <p>The instance created is completely independent of the original
-     * one. A deep copy is used, none of the underlying objects are
-     * shared (except for the nodes attributes and immutable
-     * objects).</p>
-     * @return a new tree, copy of the instance
-     */
-    public BSPTree<S> copySelf() {
-
-        if (cut == null) {
-            return new BSPTree<>(attribute);
-        }
-
-        return new BSPTree<>(cut.copySelf(), plus.copySelf(), minus.copySelf(),
-                           attribute);
-
-    }
-
-    /** Get the cut sub-hyperplane.
-     * @return cut sub-hyperplane, null if this is a leaf tree
-     */
-    public SubHyperplane<S> getCut() {
-        return cut;
-    }
-
-    /** Get the tree on the plus side of the cut hyperplane.
-     * @return tree on the plus side of the cut hyperplane, null if this
-     * is a leaf tree
-     */
-    public BSPTree<S> getPlus() {
-        return plus;
-    }
-
-    /** Get the tree on the minus side of the cut hyperplane.
-     * @return tree on the minus side of the cut hyperplane, null if this
-     * is a leaf tree
-     */
-    public BSPTree<S> getMinus() {
-        return minus;
-    }
-
-    /** Get the parent node.
-     * @return parent node, null if the node has no parents
-     */
-    public BSPTree<S> getParent() {
-        return parent;
-    }
-
-    /** Associate an attribute with the instance.
-     * @param attribute attribute to associate with the node
-     * @see #getAttribute
-     */
-    public void setAttribute(final Object attribute) {
-        this.attribute = attribute;
-    }
-
-    /** Get the attribute associated with the instance.
-     * @return attribute associated with the node or null if no
-     * attribute has been explicitly set using the {@link #setAttribute
-     * setAttribute} method
-     * @see #setAttribute
-     */
-    public Object getAttribute() {
-        return attribute;
-    }
-
-    /** Visit the BSP tree nodes.
-     * @param visitor object visiting the tree nodes
-     */
-    public void visit(final BSPTreeVisitor<S> visitor) {
-        if (cut == null) {
-            visitor.visitLeafNode(this);
-        } else {
-            switch (visitor.visitOrder(this)) {
-            case PLUS_MINUS_SUB:
-                plus.visit(visitor);
-                minus.visit(visitor);
-                visitor.visitInternalNode(this);
-                break;
-            case PLUS_SUB_MINUS:
-                plus.visit(visitor);
-                visitor.visitInternalNode(this);
-                minus.visit(visitor);
-                break;
-            case MINUS_PLUS_SUB:
-                minus.visit(visitor);
-                plus.visit(visitor);
-                visitor.visitInternalNode(this);
-                break;
-            case MINUS_SUB_PLUS:
-                minus.visit(visitor);
-                visitor.visitInternalNode(this);
-                plus.visit(visitor);
-                break;
-            case SUB_PLUS_MINUS:
-                visitor.visitInternalNode(this);
-                plus.visit(visitor);
-                minus.visit(visitor);
-                break;
-            case SUB_MINUS_PLUS:
-                visitor.visitInternalNode(this);
-                minus.visit(visitor);
-                plus.visit(visitor);
-                break;
-            default:
-                throw new MathInternalError();
-            }
-
-        }
-    }
-
-    /** Fit a sub-hyperplane inside the cell defined by the instance.
-     * <p>Fitting is done by chopping off the parts of the
-     * sub-hyperplane that lie outside of the cell using the
-     * cut-hyperplanes of the parent nodes of the instance.</p>
-     * @param sub sub-hyperplane to fit
-     * @return a new sub-hyperplane, guaranteed to have no part outside
-     * of the instance cell
-     */
-    private SubHyperplane<S> fitToCell(final SubHyperplane<S> sub) {
-        SubHyperplane<S> s = sub;
-        for (BSPTree<S> tree = this; tree.parent != null && s != null; tree = tree.parent) {
-            if (tree == tree.parent.plus) {
-                s = s.split(tree.parent.cut.getHyperplane()).getPlus();
-            } else {
-                s = s.split(tree.parent.cut.getHyperplane()).getMinus();
-            }
-        }
-        return s;
-    }
-
-    /** Get the cell to which a point belongs.
-     * <p>If the returned cell is a leaf node the points belongs to the
-     * interior of the node, if the cell is an internal node the points
-     * belongs to the node cut sub-hyperplane.</p>
-     * @param point point to check
-     * @param tolerance tolerance below which points close to a cut hyperplane
-     * are considered to belong to the hyperplane itself
-     * @return the tree cell to which the point belongs
-     */
-    public BSPTree<S> getCell(final Point<S> point, final double tolerance) {
-
-        if (cut == null) {
-            return this;
-        }
-
-        // position of the point with respect to the cut hyperplane
-        final double offset = cut.getHyperplane().getOffset(point);
-
-        if (FastMath.abs(offset) < tolerance) {
-            return this;
-        } else if (offset <= 0) {
-            // point is on the minus side of the cut hyperplane
-            return minus.getCell(point, tolerance);
-        } else {
-            // point is on the plus side of the cut hyperplane
-            return plus.getCell(point, tolerance);
-        }
-
-    }
-
-    /** Get the cells whose cut sub-hyperplanes are close to the point.
-     * @param point point to check
-     * @param maxOffset offset below which a cut sub-hyperplane is considered
-     * close to the point (in absolute value)
-     * @return close cells (may be empty if all cut sub-hyperplanes are farther
-     * than maxOffset from the point)
-     */
-    public List<BSPTree<S>> getCloseCuts(final Point<S> point, final double maxOffset) {
-        final List<BSPTree<S>> close = new ArrayList<>();
-        recurseCloseCuts(point, maxOffset, close);
-        return close;
-    }
-
-    /** Get the cells whose cut sub-hyperplanes are close to the point.
-     * @param point point to check
-     * @param maxOffset offset below which a cut sub-hyperplane is considered
-     * close to the point (in absolute value)
-     * @param close list to fill
-     */
-    private void recurseCloseCuts(final Point<S> point, final double maxOffset,
-                                  final List<BSPTree<S>> close) {
-        if (cut != null) {
-
-            // position of the point with respect to the cut hyperplane
-            final double offset = cut.getHyperplane().getOffset(point);
-
-            if (offset < -maxOffset) {
-                // point is on the minus side of the cut hyperplane
-                minus.recurseCloseCuts(point, maxOffset, close);
-            } else if (offset > maxOffset) {
-                // point is on the plus side of the cut hyperplane
-                plus.recurseCloseCuts(point, maxOffset, close);
-            } else {
-                // point is close to the cut hyperplane
-                close.add(this);
-                minus.recurseCloseCuts(point, maxOffset, close);
-                plus.recurseCloseCuts(point, maxOffset, close);
-            }
-
-        }
-    }
-
-    /** Perform condensation on a tree.
-     * <p>The condensation operation is not recursive, it must be called
-     * explicitly from leaves to root.</p>
-     */
-    private void condense() {
-        if ((cut != null) && (plus.cut == null) && (minus.cut == null) &&
-            (((plus.attribute == null) && (minus.attribute == null)) ||
-             ((plus.attribute != null) && plus.attribute.equals(minus.attribute)))) {
-            attribute = (plus.attribute == null) ? minus.attribute : plus.attribute;
-            cut       = null;
-            plus      = null;
-            minus     = null;
-        }
-    }
-
-    /** Merge a BSP tree with the instance.
-     * <p>All trees are modified (parts of them are reused in the new
-     * tree), it is the responsibility of the caller to ensure a copy
-     * has been done before if any of the former tree should be
-     * preserved, <em>no</em> such copy is done here!</p>
-     * <p>The algorithm used here is directly derived from the one
-     * described in the Naylor, Amanatides and Thibault paper (section
-     * III, Binary Partitioning of a BSP Tree).</p>
-     * @param tree other tree to merge with the instance (will be
-     * <em>unusable</em> after the operation, as well as the
-     * instance itself)
-     * @param leafMerger object implementing the final merging phase
-     * (this is where the semantic of the operation occurs, generally
-     * depending on the attribute of the leaf node)
-     * @return a new tree, result of <code>instance &lt;op&gt;
-     * tree</code>, this value can be ignored if parentTree is not null
-     * since all connections have already been established
-     */
-    public BSPTree<S> merge(final BSPTree<S> tree, final LeafMerger<S> leafMerger) {
-        return merge(tree, leafMerger, null, false);
-    }
-
-    /** Merge a BSP tree with the instance.
-     * @param tree other tree to merge with the instance (will be
-     * <em>unusable</em> after the operation, as well as the
-     * instance itself)
-     * @param leafMerger object implementing the final merging phase
-     * (this is where the semantic of the operation occurs, generally
-     * depending on the attribute of the leaf node)
-     * @param parentTree parent tree to connect to (may be null)
-     * @param isPlusChild if true and if parentTree is not null, the
-     * resulting tree should be the plus child of its parent, ignored if
-     * parentTree is null
-     * @return a new tree, result of <code>instance &lt;op&gt;
-     * tree</code>, this value can be ignored if parentTree is not null
-     * since all connections have already been established
-     */
-    private BSPTree<S> merge(final BSPTree<S> tree, final LeafMerger<S> leafMerger,
-                             final BSPTree<S> parentTree, final boolean isPlusChild) {
-        if (cut == null) {
-            // cell/tree operation
-            return leafMerger.merge(this, tree, parentTree, isPlusChild, true);
-        } else if (tree.cut == null) {
-            // tree/cell operation
-            return leafMerger.merge(tree, this, parentTree, isPlusChild, false);
-        } else {
-            // tree/tree operation
-            final BSPTree<S> merged = tree.split(cut);
-            if (parentTree != null) {
-                merged.parent = parentTree;
-                if (isPlusChild) {
-                    parentTree.plus = merged;
-                } else {
-                    parentTree.minus = merged;
-                }
-            }
-
-            // merging phase
-            plus.merge(merged.plus, leafMerger, merged, true);
-            minus.merge(merged.minus, leafMerger, merged, false);
-            merged.condense();
-            if (merged.cut != null) {
-                merged.cut = merged.fitToCell(merged.cut.getHyperplane().wholeHyperplane());
-            }
-
-            return merged;
-
-        }
-    }
-
-    /** This interface gather the merging operations between a BSP tree
-     * leaf and another BSP tree.
-     * <p>As explained in Bruce Naylor, John Amanatides and William
-     * Thibault paper <a
-     * href="http://www.cs.yorku.ca/~amana/research/bsptSetOp.pdf">Merging
-     * BSP Trees Yields Polyhedral Set Operations</a>,
-     * the operations on {@link BSPTree BSP trees} can be expressed as a
-     * generic recursive merging operation where only the final part,
-     * when one of the operand is a leaf, is specific to the real
-     * operation semantics. For example, a tree representing a region
-     * using a boolean attribute to identify inside cells and outside
-     * cells would use four different objects to implement the final
-     * merging phase of the four set operations union, intersection,
-     * difference and symmetric difference (exclusive or).</p>
-     * @param <S> Type of the space.
-     */
-    public interface LeafMerger<S extends Space> {
-
-        /** Merge a leaf node and a tree node.
-         * <p>This method is called at the end of a recursive merging
-         * resulting from a {@code tree1.merge(tree2, leafMerger)}
-         * call, when one of the sub-trees involved is a leaf (i.e. when
-         * its cut-hyperplane is null). This is the only place where the
-         * precise semantics of the operation are required. For all upper
-         * level nodes in the tree, the merging operation is only a
-         * generic partitioning algorithm.</p>
-         * <p>Since the final operation may be non-commutative, it is
-         * important to know if the leaf node comes from the instance tree
-         * ({@code tree1}) or the argument tree
-         * ({@code tree2}). The third argument of the method is
-         * devoted to this. It can be ignored for commutative
-         * operations.</p>
-         * <p>The {@link BSPTree#insertInTree BSPTree.insertInTree} method
-         * may be useful to implement this method.</p>
-         * @param leaf leaf node (its cut hyperplane is guaranteed to be
-         * null)
-         * @param tree tree node (its cut hyperplane may be null or not)
-         * @param parentTree parent tree to connect to (may be null)
-         * @param isPlusChild if true and if parentTree is not null, the
-         * resulting tree should be the plus child of its parent, ignored if
-         * parentTree is null
-         * @param leafFromInstance if true, the leaf node comes from the
-         * instance tree ({@code tree1}) and the tree node comes from
-         * the argument tree ({@code tree2})
-         * @return the BSP tree resulting from the merging (may be one of
-         * the arguments)
-         */
-        BSPTree<S> merge(BSPTree<S> leaf, BSPTree<S> tree, BSPTree<S> parentTree,
-                         boolean isPlusChild, boolean leafFromInstance);
-
-    }
-
-    /** This interface handles the corner cases when an internal node cut sub-hyperplane vanishes.
-     * <p>
-     * Such cases happens for example when a cut sub-hyperplane is inserted into
-     * another tree (during a merge operation), and is split in several parts,
-     * some of which becomes smaller than the tolerance. The corresponding node
-     * as then no cut sub-hyperplane anymore, but does have children. This interface
-     * specifies how to handle this situation.
-     * setting
-     * </p>
-     * @param <S> Type of the space.
-     * @since 3.4
-     */
-    public interface VanishingCutHandler<S extends Space> {
-
-        /** Fix a node with both vanished cut and children.
-         * @param node node to fix
-         * @return fixed node
-         */
-        BSPTree<S> fixNode(BSPTree<S> node);
-
-    }
-
-    /** Split a BSP tree by an external sub-hyperplane.
-     * <p>Split a tree in two halves, on each side of the
-     * sub-hyperplane. The instance is not modified.</p>
-     * <p>The tree returned is not upward-consistent: despite all of its
-     * sub-trees cut sub-hyperplanes (including its own cut
-     * sub-hyperplane) are bounded to the current cell, it is <em>not</em>
-     * attached to any parent tree yet. This tree is intended to be
-     * later inserted into an higher level tree.</p>
-     * <p>The algorithm used here is the one given in Naylor, Amanatides
-     * and Thibault paper (section III, Binary Partitioning of a BSP
-     * Tree).</p>
-     * @param sub partitioning sub-hyperplane, must be already clipped
-     * to the convex region represented by the instance, will be used as
-     * the cut sub-hyperplane of the returned tree
-     * @return a tree having the specified sub-hyperplane as its cut
-     * sub-hyperplane, the two parts of the split instance as its two
-     * sub-trees and a null parent
-     */
-    public BSPTree<S> split(final SubHyperplane<S> sub) {
-
-        if (cut == null) {
-            return new BSPTree<>(sub, copySelf(), new BSPTree<S>(attribute), null);
-        }
-
-        final Hyperplane<S> cHyperplane = cut.getHyperplane();
-        final Hyperplane<S> sHyperplane = sub.getHyperplane();
-        final SubHyperplane.SplitSubHyperplane<S> subParts = sub.split(cHyperplane);
-        switch (subParts.getSide()) {
-        case PLUS :
-        { // the partitioning sub-hyperplane is entirely in the plus sub-tree
-            final BSPTree<S> split = plus.split(sub);
-            if (cut.split(sHyperplane).getSide() == Side.PLUS) {
-                split.plus =
-                    new BSPTree<>(cut.copySelf(), split.plus, minus.copySelf(), attribute);
-                split.plus.condense();
-                split.plus.parent = split;
-            } else {
-                split.minus =
-                    new BSPTree<>(cut.copySelf(), split.minus, minus.copySelf(), attribute);
-                split.minus.condense();
-                split.minus.parent = split;
-            }
-            return split;
-        }
-        case MINUS :
-        { // the partitioning sub-hyperplane is entirely in the minus sub-tree
-            final BSPTree<S> split = minus.split(sub);
-            if (cut.split(sHyperplane).getSide() == Side.PLUS) {
-                split.plus =
-                    new BSPTree<>(cut.copySelf(), plus.copySelf(), split.plus, attribute);
-                split.plus.condense();
-                split.plus.parent = split;
-            } else {
-                split.minus =
-                    new BSPTree<>(cut.copySelf(), plus.copySelf(), split.minus, attribute);
-                split.minus.condense();
-                split.minus.parent = split;
-            }
-            return split;
-        }
-        case BOTH :
-        {
-            final SubHyperplane.SplitSubHyperplane<S> cutParts = cut.split(sHyperplane);
-            final BSPTree<S> split =
-                new BSPTree<>(sub, plus.split(subParts.getPlus()), minus.split(subParts.getMinus()),
-                               null);
-            split.plus.cut          = cutParts.getPlus();
-            split.minus.cut         = cutParts.getMinus();
-            final BSPTree<S> tmp    = split.plus.minus;
-            split.plus.minus        = split.minus.plus;
-            split.plus.minus.parent = split.plus;
-            split.minus.plus        = tmp;
-            split.minus.plus.parent = split.minus;
-            split.plus.condense();
-            split.minus.condense();
-            return split;
-        }
-        default :
-            return cHyperplane.sameOrientationAs(sHyperplane) ?
-                   new BSPTree<>(sub, plus.copySelf(),  minus.copySelf(), attribute) :
-                   new BSPTree<>(sub, minus.copySelf(), plus.copySelf(),  attribute);
-        }
-
-    }
-
-    /** Insert the instance into another tree.
-     * <p>The instance itself is modified so its former parent should
-     * not be used anymore.</p>
-     * @param parentTree parent tree to connect to (may be null)
-     * @param isPlusChild if true and if parentTree is not null, the
-     * resulting tree should be the plus child of its parent, ignored if
-     * parentTree is null
-     * @param vanishingHandler handler to use for handling very rare corner
-     * cases of vanishing cut sub-hyperplanes in internal nodes during merging
-     * @see LeafMerger
-     * @since 3.4
-     */
-    public void insertInTree(final BSPTree<S> parentTree, final boolean isPlusChild,
-                             final VanishingCutHandler<S> vanishingHandler) {
-
-        // set up parent/child links
-        parent = parentTree;
-        if (parentTree != null) {
-            if (isPlusChild) {
-                parentTree.plus = this;
-            } else {
-                parentTree.minus = this;
-            }
-        }
-
-        // make sure the inserted tree lies in the cell defined by its parent nodes
-        if (cut != null) {
-
-            // explore the parent nodes from here towards tree root
-            for (BSPTree<S> tree = this; tree.parent != null; tree = tree.parent) {
-
-                // this is an hyperplane of some parent node
-                final Hyperplane<S> hyperplane = tree.parent.cut.getHyperplane();
-
-                // chop off the parts of the inserted tree that extend
-                // on the wrong side of this parent hyperplane
-                if (tree == tree.parent.plus) {
-                    cut = cut.split(hyperplane).getPlus();
-                    plus.chopOffMinus(hyperplane, vanishingHandler);
-                    minus.chopOffMinus(hyperplane, vanishingHandler);
-                } else {
-                    cut = cut.split(hyperplane).getMinus();
-                    plus.chopOffPlus(hyperplane, vanishingHandler);
-                    minus.chopOffPlus(hyperplane, vanishingHandler);
-                }
-
-                if (cut == null) {
-                    // the cut sub-hyperplane has vanished
-                    final BSPTree<S> fixed = vanishingHandler.fixNode(this);
-                    cut       = fixed.cut;
-                    plus      = fixed.plus;
-                    minus     = fixed.minus;
-                    attribute = fixed.attribute;
-                    if (cut == null) {
-                        break;
-                    }
-                }
-
-            }
-
-            // since we may have drop some parts of the inserted tree,
-            // perform a condensation pass to keep the tree structure simple
-            condense();
-
-        }
-
-    }
-
-    /** Prune a tree around a cell.
-     * <p>
-     * This method can be used to extract a convex cell from a tree.
-     * The original cell may either be a leaf node or an internal node.
-     * If it is an internal node, it's subtree will be ignored (i.e. the
-     * extracted cell will be a leaf node in all cases). The original
-     * tree to which the original cell belongs is not touched at all,
-     * a new independent tree will be built.
-     * </p>
-     * @param cellAttribute attribute to set for the leaf node
-     * corresponding to the initial instance cell
-     * @param otherLeafsAttributes attribute to set for the other leaf
-     * nodes
-     * @param internalAttributes attribute to set for the internal nodes
-     * @return a new tree (the original tree is left untouched) containing
-     * a single branch with the cell as a leaf node, and other leaf nodes
-     * as the remnants of the pruned branches
-     * @since 3.3
-     */
-    public BSPTree<S> pruneAroundConvexCell(final Object cellAttribute,
-                                            final Object otherLeafsAttributes,
-                                            final Object internalAttributes) {
-
-        // build the current cell leaf
-        BSPTree<S> tree = new BSPTree<>(cellAttribute);
-
-        // build the pruned tree bottom-up
-        for (BSPTree<S> current = this; current.parent != null; current = current.parent) {
-            final SubHyperplane<S> parentCut = current.parent.cut.copySelf();
-            final BSPTree<S>       sibling   = new BSPTree<>(otherLeafsAttributes);
-            if (current == current.parent.plus) {
-                tree = new BSPTree<>(parentCut, tree, sibling, internalAttributes);
-            } else {
-                tree = new BSPTree<>(parentCut, sibling, tree, internalAttributes);
-            }
-        }
-
-        return tree;
-
-    }
-
-    /** Chop off parts of the tree.
-     * <p>The instance is modified in place, all the parts that are on
-     * the minus side of the chopping hyperplane are discarded, only the
-     * parts on the plus side remain.</p>
-     * @param hyperplane chopping hyperplane
-     * @param vanishingHandler handler to use for handling very rare corner
-     * cases of vanishing cut sub-hyperplanes in internal nodes during merging
-     */
-    private void chopOffMinus(final Hyperplane<S> hyperplane, final VanishingCutHandler<S> vanishingHandler) {
-        if (cut != null) {
-
-            cut = cut.split(hyperplane).getPlus();
-            plus.chopOffMinus(hyperplane, vanishingHandler);
-            minus.chopOffMinus(hyperplane, vanishingHandler);
-
-            if (cut == null) {
-                // the cut sub-hyperplane has vanished
-                final BSPTree<S> fixed = vanishingHandler.fixNode(this);
-                cut       = fixed.cut;
-                plus      = fixed.plus;
-                minus     = fixed.minus;
-                attribute = fixed.attribute;
-            }
-
-        }
-    }
-
-    /** Chop off parts of the tree.
-     * <p>The instance is modified in place, all the parts that are on
-     * the plus side of the chopping hyperplane are discarded, only the
-     * parts on the minus side remain.</p>
-     * @param hyperplane chopping hyperplane
-     * @param vanishingHandler handler to use for handling very rare corner
-     * cases of vanishing cut sub-hyperplanes in internal nodes during merging
-     */
-    private void chopOffPlus(final Hyperplane<S> hyperplane, final VanishingCutHandler<S> vanishingHandler) {
-        if (cut != null) {
-
-            cut = cut.split(hyperplane).getMinus();
-            plus.chopOffPlus(hyperplane, vanishingHandler);
-            minus.chopOffPlus(hyperplane, vanishingHandler);
-
-            if (cut == null) {
-                // the cut sub-hyperplane has vanished
-                final BSPTree<S> fixed = vanishingHandler.fixNode(this);
-                cut       = fixed.cut;
-                plus      = fixed.plus;
-                minus     = fixed.minus;
-                attribute = fixed.attribute;
-            }
-
-        }
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/BSPTreeVisitor.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/BSPTreeVisitor.java
deleted file mode 100644
index 836f287..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/BSPTreeVisitor.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.partitioning;
-
-import org.apache.commons.math4.geometry.Space;
-
-/** This interface is used to visit {@link BSPTree BSP tree} nodes.
-
- * <p>Navigation through {@link BSPTree BSP trees} can be done using
- * two different point of views:</p>
- * <ul>
- *   <li>
- *     the first one is in a node-oriented way using the {@link
- *     BSPTree#getPlus}, {@link BSPTree#getMinus} and {@link
- *     BSPTree#getParent} methods. Terminal nodes without associated
- *     {@link SubHyperplane sub-hyperplanes} can be visited this way,
- *     there is no constraint in the visit order, and it is possible
- *     to visit either all nodes or only a subset of the nodes
- *   </li>
- *   <li>
- *     the second one is in a sub-hyperplane-oriented way using
- *     classes implementing this interface which obeys the visitor
- *     design pattern. The visit order is provided by the visitor as
- *     each node is first encountered. Each node is visited exactly
- *     once.
- *   </li>
- * </ul>
-
- * @param <S> Type of the space.
-
- * @see BSPTree
- * @see SubHyperplane
-
- * @since 3.0
- */
-public interface BSPTreeVisitor<S extends Space> {
-
-    /** Enumerate for visit order with respect to plus sub-tree, minus sub-tree and cut sub-hyperplane. */
-    enum Order {
-        /** Indicator for visit order plus sub-tree, then minus sub-tree,
-         * and last cut sub-hyperplane.
-         */
-        PLUS_MINUS_SUB,
-
-        /** Indicator for visit order plus sub-tree, then cut sub-hyperplane,
-         * and last minus sub-tree.
-         */
-        PLUS_SUB_MINUS,
-
-        /** Indicator for visit order minus sub-tree, then plus sub-tree,
-         * and last cut sub-hyperplane.
-         */
-        MINUS_PLUS_SUB,
-
-        /** Indicator for visit order minus sub-tree, then cut sub-hyperplane,
-         * and last plus sub-tree.
-         */
-        MINUS_SUB_PLUS,
-
-        /** Indicator for visit order cut sub-hyperplane, then plus sub-tree,
-         * and last minus sub-tree.
-         */
-        SUB_PLUS_MINUS,
-
-        /** Indicator for visit order cut sub-hyperplane, then minus sub-tree,
-         * and last plus sub-tree.
-         */
-        SUB_MINUS_PLUS;
-    }
-
-    /** Determine the visit order for this node.
-     * <p>Before attempting to visit an internal node, this method is
-     * called to determine the desired ordering of the visit. It is
-     * guaranteed that this method will be called before {@link
-     * #visitInternalNode visitInternalNode} for a given node, it will be
-     * called exactly once for each internal node.</p>
-     * @param node BSP node guaranteed to have a non null cut sub-hyperplane
-     * @return desired visit order, must be one of
-     * {@link Order#PLUS_MINUS_SUB}, {@link Order#PLUS_SUB_MINUS},
-     * {@link Order#MINUS_PLUS_SUB}, {@link Order#MINUS_SUB_PLUS},
-     * {@link Order#SUB_PLUS_MINUS}, {@link Order#SUB_MINUS_PLUS}
-     */
-    Order visitOrder(BSPTree<S> node);
-
-    /** Visit a BSP tree node node having a non-null sub-hyperplane.
-     * <p>It is guaranteed that this method will be called after {@link
-     * #visitOrder visitOrder} has been called for a given node,
-     * it wil be called exactly once for each internal node.</p>
-     * @param node BSP node guaranteed to have a non null cut sub-hyperplane
-     * @see #visitLeafNode
-     */
-    void visitInternalNode(BSPTree<S> node);
-
-    /** Visit a leaf BSP tree node node having a null sub-hyperplane.
-     * @param node leaf BSP node having a null sub-hyperplane
-     * @see #visitInternalNode
-     */
-    void visitLeafNode(BSPTree<S> node);
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryAttribute.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryAttribute.java
deleted file mode 100644
index c3ce13f..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryAttribute.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.partitioning;
-
-import org.apache.commons.math4.geometry.Space;
-
-/** Class holding boundary attributes.
- * <p>This class is used for the attributes associated with the
- * nodes of region boundary shell trees returned by the {@link
- * Region#getTree(boolean) Region.getTree(includeBoundaryAttributes)}
- * when the boolean {@code includeBoundaryAttributes} parameter is
- * set to {@code true}. It contains the parts of the node cut
- * sub-hyperplane that belong to the boundary.</p>
- * <p>This class is a simple placeholder, it does not provide any
- * processing methods.</p>
- * @param <S> Type of the space.
- * @see Region#getTree
- * @since 3.0
- */
-public class BoundaryAttribute<S extends Space> {
-
-    /** Part of the node cut sub-hyperplane that belongs to the
-     * boundary and has the outside of the region on the plus side of
-     * its underlying hyperplane (may be null).
-     */
-    private final SubHyperplane<S> plusOutside;
-
-    /** Part of the node cut sub-hyperplane that belongs to the
-     * boundary and has the inside of the region on the plus side of
-     * its underlying hyperplane (may be null).
-     */
-    private final SubHyperplane<S> plusInside;
-
-    /** Sub-hyperplanes that were used to split the boundary part. */
-    private final NodesSet<S> splitters;
-
-    /** Simple constructor.
-     * @param plusOutside part of the node cut sub-hyperplane that
-     * belongs to the boundary and has the outside of the region on
-     * the plus side of its underlying hyperplane (may be null)
-     * @param plusInside part of the node cut sub-hyperplane that
-     * belongs to the boundary and has the inside of the region on the
-     * plus side of its underlying hyperplane (may be null)
-     * @param splitters sub-hyperplanes that were used to
-     * split the boundary part (may be null)
-     * @since 3.4
-     */
-    BoundaryAttribute(final SubHyperplane<S> plusOutside,
-                      final SubHyperplane<S> plusInside,
-                      final NodesSet<S> splitters) {
-        this.plusOutside = plusOutside;
-        this.plusInside  = plusInside;
-        this.splitters   = splitters;
-    }
-
-    /** Get the part of the node cut sub-hyperplane that belongs to the
-     * boundary and has the outside of the region on the plus side of
-     * its underlying hyperplane.
-     * @return part of the node cut sub-hyperplane that belongs to the
-     * boundary and has the outside of the region on the plus side of
-     * its underlying hyperplane
-     */
-    public SubHyperplane<S> getPlusOutside() {
-        return plusOutside;
-    }
-
-    /** Get the part of the node cut sub-hyperplane that belongs to the
-     * boundary and has the inside of the region on the plus side of
-     * its underlying hyperplane.
-     * @return part of the node cut sub-hyperplane that belongs to the
-     * boundary and has the inside of the region on the plus side of
-     * its underlying hyperplane
-     */
-    public SubHyperplane<S> getPlusInside() {
-        return plusInside;
-    }
-
-    /** Get the sub-hyperplanes that were used to split the boundary part.
-     * @return sub-hyperplanes that were used to split the boundary part
-     */
-    public NodesSet<S> getSplitters() {
-        return splitters;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryBuilder.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryBuilder.java
deleted file mode 100644
index a286235..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryBuilder.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.partitioning;
-
-import org.apache.commons.math4.geometry.Space;
-
-/** Visitor building boundary shell tree.
- * <p>
- * The boundary shell is represented as {@link BoundaryAttribute boundary attributes}
- * at each internal node.
- * </p>
- * @param <S> Type of the space.
- * @since 3.4
- */
-class BoundaryBuilder<S extends Space> implements BSPTreeVisitor<S> {
-
-    /** {@inheritDoc} */
-    @Override
-    public Order visitOrder(BSPTree<S> node) {
-        return Order.PLUS_MINUS_SUB;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void visitInternalNode(BSPTree<S> node) {
-
-        SubHyperplane<S> plusOutside = null;
-        SubHyperplane<S> plusInside  = null;
-        NodesSet<S>      splitters   = null;
-
-        // characterize the cut sub-hyperplane,
-        // first with respect to the plus sub-tree
-        final Characterization<S> plusChar = new Characterization<>(node.getPlus(), node.getCut().copySelf());
-
-        if (plusChar.touchOutside()) {
-            // plusChar.outsideTouching() corresponds to a subset of the cut sub-hyperplane
-            // known to have outside cells on its plus side, we want to check if parts
-            // of this subset do have inside cells on their minus side
-            final Characterization<S> minusChar = new Characterization<>(node.getMinus(), plusChar.outsideTouching());
-            if (minusChar.touchInside()) {
-                // this part belongs to the boundary,
-                // it has the outside on its plus side and the inside on its minus side
-                plusOutside = minusChar.insideTouching();
-                splitters = new NodesSet<>();
-                splitters.addAll(minusChar.getInsideSplitters());
-                splitters.addAll(plusChar.getOutsideSplitters());
-            }
-        }
-
-        if (plusChar.touchInside()) {
-            // plusChar.insideTouching() corresponds to a subset of the cut sub-hyperplane
-            // known to have inside cells on its plus side, we want to check if parts
-            // of this subset do have outside cells on their minus side
-            final Characterization<S> minusChar = new Characterization<>(node.getMinus(), plusChar.insideTouching());
-            if (minusChar.touchOutside()) {
-                // this part belongs to the boundary,
-                // it has the inside on its plus side and the outside on its minus side
-                plusInside = minusChar.outsideTouching();
-                if (splitters == null) {
-                    splitters = new NodesSet<>();
-                }
-                splitters.addAll(minusChar.getOutsideSplitters());
-                splitters.addAll(plusChar.getInsideSplitters());
-            }
-        }
-
-        if (splitters != null) {
-            // the parent nodes are natural splitters for boundary sub-hyperplanes
-            for (BSPTree<S> up = node.getParent(); up != null; up = up.getParent()) {
-                splitters.add(up);
-            }
-        }
-
-        // set the boundary attribute at non-leaf nodes
-        node.setAttribute(new BoundaryAttribute<>(plusOutside, plusInside, splitters));
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void visitLeafNode(BSPTree<S> node) {
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryProjection.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryProjection.java
deleted file mode 100644
index 97d4ca4..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryProjection.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.partitioning;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-
-/** Class holding the result of point projection on region boundary.
- * <p>This class is a simple placeholder, it does not provide any
- * processing methods.</p>
- * <p>Instances of this class are guaranteed to be immutable</p>
- * @param <S> Type of the space.
- * @since 3.3
- * @see AbstractRegion#projectToBoundary(Point)
- */
-public class BoundaryProjection<S extends Space> {
-
-    /** Original point. */
-    private final Point<S> original;
-
-    /** Projected point. */
-    private final Point<S> projected;
-
-    /** Offset of the point with respect to the boundary it is projected on. */
-    private final double offset;
-
-    /** Constructor from raw elements.
-     * @param original original point
-     * @param projected projected point
-     * @param offset offset of the point with respect to the boundary it is projected on
-     */
-    public BoundaryProjection(final Point<S> original, final Point<S> projected, final double offset) {
-        this.original  = original;
-        this.projected = projected;
-        this.offset    = offset;
-    }
-
-    /** Get the original point.
-     * @return original point
-     */
-    public Point<S> getOriginal() {
-        return original;
-    }
-
-    /** Projected point.
-     * @return projected point, or null if there are no boundary
-     */
-    public Point<S> getProjected() {
-        return projected;
-    }
-
-    /** Offset of the point with respect to the boundary it is projected on.
-     * <p>
-     * The offset with respect to the boundary is negative if the {@link
-     * #getOriginal() original point} is inside the region, and positive otherwise.
-     * </p>
-     * <p>
-     * If there are no boundary, the value is set to either {@code
-     * Double.POSITIVE_INFINITY} if the region is empty (i.e. all points are
-     * outside of the region) or {@code Double.NEGATIVE_INFINITY} if the region
-     * covers the whole space (i.e. all points are inside of the region).
-     * </p>
-     * @return offset of the point with respect to the boundary it is projected on
-     */
-    public double getOffset() {
-        return offset;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryProjector.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryProjector.java
deleted file mode 100644
index 212f624..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundaryProjector.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * 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.partitioning;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.partitioning.Region.Location;
-import org.apache.commons.math4.util.FastMath;
-
-/** Local tree visitor to compute projection on boundary.
- * @param <S> Type of the space.
- * @param <T> Type of the sub-space.
- * @since 3.3
- */
-class BoundaryProjector<S extends Space, T extends Space> implements BSPTreeVisitor<S> {
-
-    /** Original point. */
-    private final Point<S> original;
-
-    /** Current best projected point. */
-    private Point<S> projected;
-
-    /** Leaf node closest to the test point. */
-    private BSPTree<S> leaf;
-
-    /** Current offset. */
-    private double offset;
-
-    /** Simple constructor.
-     * @param original original point
-     */
-    BoundaryProjector(final Point<S> original) {
-        this.original  = original;
-        this.projected = null;
-        this.leaf      = null;
-        this.offset    = Double.POSITIVE_INFINITY;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Order visitOrder(final BSPTree<S> node) {
-        // we want to visit the tree so that the first encountered
-        // leaf is the one closest to the test point
-        if (node.getCut().getHyperplane().getOffset(original) <= 0) {
-            return Order.MINUS_SUB_PLUS;
-        } else {
-            return Order.PLUS_SUB_MINUS;
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void visitInternalNode(final BSPTree<S> node) {
-
-        // project the point on the cut sub-hyperplane
-        final Hyperplane<S> hyperplane = node.getCut().getHyperplane();
-        final double signedOffset = hyperplane.getOffset(original);
-        if (FastMath.abs(signedOffset) < offset) {
-
-            // project point
-            final Point<S> regular = hyperplane.project(original);
-
-            // get boundary parts
-            final List<Region<T>> boundaryParts = boundaryRegions(node);
-
-            // check if regular projection really belongs to the boundary
-            boolean regularFound = false;
-            for (final Region<T> part : boundaryParts) {
-                if (!regularFound && belongsToPart(regular, hyperplane, part)) {
-                    // the projected point lies in the boundary
-                    projected    = regular;
-                    offset       = FastMath.abs(signedOffset);
-                    regularFound = true;
-                }
-            }
-
-            if (!regularFound) {
-                // the regular projected point is not on boundary,
-                // so we have to check further if a singular point
-                // (i.e. a vertex in 2D case) is a possible projection
-                for (final Region<T> part : boundaryParts) {
-                    final Point<S> spI = singularProjection(regular, hyperplane, part);
-                    if (spI != null) {
-                        final double distance = original.distance(spI);
-                        if (distance < offset) {
-                            projected = spI;
-                            offset    = distance;
-                        }
-                    }
-                }
-
-            }
-
-        }
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void visitLeafNode(final BSPTree<S> node) {
-        if (leaf == null) {
-            // this is the first leaf we visit,
-            // it is the closest one to the original point
-            leaf = node;
-        }
-    }
-
-    /** Get the projection.
-     * @return projection
-     */
-    public BoundaryProjection<S> getProjection() {
-
-        // fix offset sign
-        offset = FastMath.copySign(offset, (Boolean) leaf.getAttribute() ? -1 : +1);
-
-        return new BoundaryProjection<>(original, projected, offset);
-
-    }
-
-    /** Extract the regions of the boundary on an internal node.
-     * @param node internal node
-     * @return regions in the node sub-hyperplane
-     */
-    private List<Region<T>> boundaryRegions(final BSPTree<S> node) {
-
-        final List<Region<T>> regions = new ArrayList<>(2);
-
-        @SuppressWarnings("unchecked")
-        final BoundaryAttribute<S> ba = (BoundaryAttribute<S>) node.getAttribute();
-        addRegion(ba.getPlusInside(),  regions);
-        addRegion(ba.getPlusOutside(), regions);
-
-        return regions;
-
-    }
-
-    /** Add a boundary region to a list.
-     * @param sub sub-hyperplane defining the region
-     * @param list to fill up
-     */
-    private void addRegion(final SubHyperplane<S> sub, final List<Region<T>> list) {
-        if (sub != null) {
-            @SuppressWarnings("unchecked")
-            final Region<T> region = ((AbstractSubHyperplane<S, T>) sub).getRemainingRegion();
-            if (region != null) {
-                list.add(region);
-            }
-        }
-    }
-
-    /** Check if a projected point lies on a boundary part.
-     * @param point projected point to check
-     * @param hyperplane hyperplane into which the point was projected
-     * @param part boundary part
-     * @return true if point lies on the boundary part
-     */
-    private boolean belongsToPart(final Point<S> point, final Hyperplane<S> hyperplane,
-                                  final Region<T> part) {
-
-        // there is a non-null sub-space, we can dive into smaller dimensions
-        @SuppressWarnings("unchecked")
-        final Embedding<S, T> embedding = (Embedding<S, T>) hyperplane;
-        return part.checkPoint(embedding.toSubSpace(point)) != Location.OUTSIDE;
-
-    }
-
-    /** Get the projection to the closest boundary singular point.
-     * @param point projected point to check
-     * @param hyperplane hyperplane into which the point was projected
-     * @param part boundary part
-     * @return projection to a singular point of boundary part (may be null)
-     */
-    private Point<S> singularProjection(final Point<S> point, final Hyperplane<S> hyperplane,
-                                        final Region<T> part) {
-
-        // there is a non-null sub-space, we can dive into smaller dimensions
-        @SuppressWarnings("unchecked")
-        final Embedding<S, T> embedding = (Embedding<S, T>) hyperplane;
-        final BoundaryProjection<T> bp = part.projectToBoundary(embedding.toSubSpace(point));
-
-        // back to initial dimension
-        return (bp.getProjected() == null) ? null : embedding.toSpace(bp.getProjected());
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundarySizeVisitor.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundarySizeVisitor.java
deleted file mode 100644
index c5b2895..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/BoundarySizeVisitor.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.partitioning;
-
-import org.apache.commons.math4.geometry.Space;
-
-/** Visitor computing the boundary size.
- * @param <S> Type of the space.
- * @since 3.0
- */
-class BoundarySizeVisitor<S extends Space> implements BSPTreeVisitor<S> {
-
-    /** Size of the boundary. */
-    private double boundarySize;
-
-    /** Simple constructor.
-     */
-    BoundarySizeVisitor() {
-        boundarySize = 0;
-    }
-
-    /** {@inheritDoc}*/
-    @Override
-    public Order visitOrder(final BSPTree<S> node) {
-        return Order.MINUS_SUB_PLUS;
-    }
-
-    /** {@inheritDoc}*/
-    @Override
-    public void visitInternalNode(final BSPTree<S> node) {
-        @SuppressWarnings("unchecked")
-        final BoundaryAttribute<S> attribute =
-            (BoundaryAttribute<S>) node.getAttribute();
-        if (attribute.getPlusOutside() != null) {
-            boundarySize += attribute.getPlusOutside().getSize();
-        }
-        if (attribute.getPlusInside() != null) {
-            boundarySize += attribute.getPlusInside().getSize();
-        }
-    }
-
-    /** {@inheritDoc}*/
-    @Override
-    public void visitLeafNode(final BSPTree<S> node) {
-    }
-
-    /** Get the size of the boundary.
-     * @return size of the boundary
-     */
-    public double getSize() {
-        return boundarySize;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/Characterization.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/Characterization.java
deleted file mode 100644
index 93fd171..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/Characterization.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * 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.partitioning;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.math4.geometry.Space;
-
-/** Cut sub-hyperplanes characterization with respect to inside/outside cells.
- * @see BoundaryBuilder
- * @param <S> Type of the space.
- * @since 3.4
- */
-class Characterization<S extends Space> {
-
-    /** Part of the cut sub-hyperplane that touch outside cells. */
-    private SubHyperplane<S> outsideTouching;
-
-    /** Part of the cut sub-hyperplane that touch inside cells. */
-    private SubHyperplane<S> insideTouching;
-
-    /** Nodes that were used to split the outside touching part. */
-    private final NodesSet<S> outsideSplitters;
-
-    /** Nodes that were used to split the outside touching part. */
-    private final NodesSet<S> insideSplitters;
-
-    /** Simple constructor.
-     * <p>Characterization consists in splitting the specified
-     * sub-hyperplane into several parts lying in inside and outside
-     * cells of the tree. The principle is to compute characterization
-     * twice for each cut sub-hyperplane in the tree, once on the plus
-     * node and once on the minus node. The parts that have the same flag
-     * (inside/inside or outside/outside) do not belong to the boundary
-     * while parts that have different flags (inside/outside or
-     * outside/inside) do belong to the boundary.</p>
-     * @param node current BSP tree node
-     * @param sub sub-hyperplane to characterize
-     */
-    Characterization(final BSPTree<S> node, final SubHyperplane<S> sub) {
-        outsideTouching  = null;
-        insideTouching   = null;
-        outsideSplitters = new NodesSet<>();
-        insideSplitters  = new NodesSet<>();
-        characterize(node, sub, new ArrayList<BSPTree<S>>());
-    }
-
-    /** Filter the parts of an hyperplane belonging to the boundary.
-     * <p>The filtering consist in splitting the specified
-     * sub-hyperplane into several parts lying in inside and outside
-     * cells of the tree. The principle is to call this method twice for
-     * each cut sub-hyperplane in the tree, once on the plus node and
-     * once on the minus node. The parts that have the same flag
-     * (inside/inside or outside/outside) do not belong to the boundary
-     * while parts that have different flags (inside/outside or
-     * outside/inside) do belong to the boundary.</p>
-     * @param node current BSP tree node
-     * @param sub sub-hyperplane to characterize
-     * @param splitters nodes that did split the current one
-     */
-    private void characterize(final BSPTree<S> node, final SubHyperplane<S> sub,
-                              final List<BSPTree<S>> splitters) {
-        if (node.getCut() == null) {
-            // we have reached a leaf node
-            final boolean inside = (Boolean) node.getAttribute();
-            if (inside) {
-                addInsideTouching(sub, splitters);
-            } else {
-                addOutsideTouching(sub, splitters);
-            }
-        } else {
-            final Hyperplane<S> hyperplane = node.getCut().getHyperplane();
-            final SubHyperplane.SplitSubHyperplane<S> split = sub.split(hyperplane);
-            switch (split.getSide()) {
-            case PLUS:
-                characterize(node.getPlus(),  sub, splitters);
-                break;
-            case MINUS:
-                characterize(node.getMinus(), sub, splitters);
-                break;
-            case BOTH:
-                splitters.add(node);
-                characterize(node.getPlus(),  split.getPlus(),  splitters);
-                characterize(node.getMinus(), split.getMinus(), splitters);
-                splitters.remove(splitters.size() - 1);
-                break;
-            default:
-                // If we reach this point, then the sub-hyperplane we're
-                // testing lies directly on this node's hyperplane. In theory,
-                // this shouldn't ever happen with correctly-formed trees. However,
-                // this does actually occur in practice, especially with manually
-                // built trees or very complex models. Rather than throwing an
-                // exception, we'll attempt to handle this situation gracefully
-                // by treating these sub-hyperplanes as if they lie on the minus
-                // side of the cut hyperplane.
-                characterize(node.getMinus(), sub, splitters);
-                break;
-            }
-        }
-    }
-
-    /** Add a part of the cut sub-hyperplane known to touch an outside cell.
-     * @param sub part of the cut sub-hyperplane known to touch an outside cell
-     * @param splitters sub-hyperplanes that did split the current one
-     */
-    private void addOutsideTouching(final SubHyperplane<S> sub,
-                                    final List<BSPTree<S>> splitters) {
-        if (outsideTouching == null) {
-            outsideTouching = sub;
-        } else {
-            outsideTouching = outsideTouching.reunite(sub);
-        }
-        outsideSplitters.addAll(splitters);
-    }
-
-    /** Add a part of the cut sub-hyperplane known to touch an inside cell.
-     * @param sub part of the cut sub-hyperplane known to touch an inside cell
-     * @param splitters sub-hyperplanes that did split the current one
-     */
-    private void addInsideTouching(final SubHyperplane<S> sub,
-                                   final List<BSPTree<S>> splitters) {
-        if (insideTouching == null) {
-            insideTouching = sub;
-        } else {
-            insideTouching = insideTouching.reunite(sub);
-        }
-        insideSplitters.addAll(splitters);
-    }
-
-    /** Check if the cut sub-hyperplane touches outside cells.
-     * @return true if the cut sub-hyperplane touches outside cells
-     */
-    public boolean touchOutside() {
-        return outsideTouching != null && !outsideTouching.isEmpty();
-    }
-
-    /** Get all the parts of the cut sub-hyperplane known to touch outside cells.
-     * @return parts of the cut sub-hyperplane known to touch outside cells
-     * (may be null or empty)
-     */
-    public SubHyperplane<S> outsideTouching() {
-        return outsideTouching;
-    }
-
-    /** Get the nodes that were used to split the outside touching part.
-     * <p>
-     * Splitting nodes are internal nodes (i.e. they have a non-null
-     * cut sub-hyperplane).
-     * </p>
-     * @return nodes that were used to split the outside touching part
-     */
-    public NodesSet<S> getOutsideSplitters() {
-        return outsideSplitters;
-    }
-
-    /** Check if the cut sub-hyperplane touches inside cells.
-     * @return true if the cut sub-hyperplane touches inside cells
-     */
-    public boolean touchInside() {
-        return insideTouching != null && !insideTouching.isEmpty();
-    }
-
-    /** Get all the parts of the cut sub-hyperplane known to touch inside cells.
-     * @return parts of the cut sub-hyperplane known to touch inside cells
-     * (may be null or empty)
-     */
-    public SubHyperplane<S> insideTouching() {
-        return insideTouching;
-    }
-
-    /** Get the nodes that were used to split the inside touching part.
-     * <p>
-     * Splitting nodes are internal nodes (i.e. they have a non-null
-     * cut sub-hyperplane).
-     * </p>
-     * @return nodes that were used to split the inside touching part
-     */
-    public NodesSet<S> getInsideSplitters() {
-        return insideSplitters;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/Embedding.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/Embedding.java
deleted file mode 100644
index ef3cadf..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/Embedding.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.partitioning;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-
-/** This interface defines mappers between a space and one of its sub-spaces.
-
- * <p>Sub-spaces are the lower dimensions subsets of a n-dimensions
- * space. The (n-1)-dimension sub-spaces are specific sub-spaces known
- * as {@link Hyperplane hyperplanes}. This interface can be used regardless
- * of the dimensions differences. As an example, {@link
- * org.apache.commons.math4.geometry.euclidean.threed.Line Line} in 3D
- * implements Embedding&lt;{@link
- * org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D Cartesian3D}, {@link
- * org.apache.commons.math4.geometry.euclidean.oned.Cartesian1D Cartesian1D}&gt;, i.e. it
- * maps directly dimensions 3 and 1.</p>
-
- * <p>In the 3D euclidean space, hyperplanes are 2D planes, and the 1D
- * sub-spaces are lines.</p>
-
- * <p>
- * Note that this interface is <em>not</em> intended to be implemented
- * by Apache Commons Math users, it is only intended to be implemented
- * within the library itself. New methods may be added even for minor
- * versions, which breaks compatibility for external implementations.
- * </p>
-
- * @param <S> Type of the embedding space.
- * @param <T> Type of the embedded sub-space.
-
- * @see Hyperplane
- * @since 3.0
- */
-public interface Embedding<S extends Space, T extends Space> {
-
-    /** Transform a space point into a sub-space point.
-     * @param point n-dimension point of the space
-     * @return (n-1)-dimension point of the sub-space corresponding to
-     * the specified space point
-     * @see #toSpace
-     */
-    Point<T> toSubSpace(Point<S> point);
-
-    /** Transform a sub-space point into a space point.
-     * @param point (n-1)-dimension point of the sub-space
-     * @return n-dimension point of the space corresponding to the
-     * specified sub-space point
-     * @see #toSubSpace
-     */
-    Point<S> toSpace(Point<T> point);
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/Hyperplane.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/Hyperplane.java
deleted file mode 100644
index b9948f5..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/Hyperplane.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.partitioning;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-
-/** This interface represents an hyperplane of a space.
-
- * <p>The most prominent place where hyperplane appears in space
- * partitioning is as cutters. Each partitioning node in a {@link
- * BSPTree BSP tree} has a cut {@link SubHyperplane sub-hyperplane}
- * which is either an hyperplane or a part of an hyperplane. In an
- * n-dimensions euclidean space, an hyperplane is an (n-1)-dimensions
- * hyperplane (for example a traditional plane in the 3D euclidean
- * space). They can be more exotic objects in specific fields, for
- * example a circle on the surface of the unit sphere.</p>
-
- * <p>
- * Note that this interface is <em>not</em> intended to be implemented
- * by Apache Commons Math users, it is only intended to be implemented
- * within the library itself. New methods may be added even for minor
- * versions, which breaks compatibility for external implementations.
- * </p>
-
- * @param <S> Type of the space.
-
- * @since 3.0
- */
-public interface Hyperplane<S extends Space> {
-
-    /** Copy the instance.
-     * <p>The instance created is completely independant of the original
-     * one. A deep copy is used, none of the underlying objects are
-     * shared (except for immutable objects).</p>
-     * @return a new hyperplane, copy of the instance
-     */
-    Hyperplane<S> copySelf();
-
-    /** Get the offset (oriented distance) of a point.
-     * <p>The offset is 0 if the point is on the underlying hyperplane,
-     * it is positive if the point is on one particular side of the
-     * hyperplane, and it is negative if the point is on the other side,
-     * according to the hyperplane natural orientation.</p>
-     * @param point point to check
-     * @return offset of the point
-     */
-    double getOffset(Point<S> point);
-
-    /** Project a point to the hyperplane.
-     * @param point point to project
-     * @return projected point
-     * @since 3.3
-     */
-    Point<S> project(Point<S> point);
-
-    /** Get the tolerance below which points are considered to belong to the hyperplane.
-     * @return tolerance below which points are considered to belong to the hyperplane
-     * @since 3.3
-     */
-    double getTolerance();
-
-    /** Check if the instance has the same orientation as another hyperplane.
-     * <p>This method is expected to be called on parallel hyperplanes. The
-     * method should <em>not</em> re-check for parallelism, only for
-     * orientation, typically by testing something like the sign of the
-     * dot-products of normals.</p>
-     * @param other other hyperplane to check against the instance
-     * @return true if the instance and the other hyperplane have
-     * the same orientation
-     */
-    boolean sameOrientationAs(Hyperplane<S> other);
-
-    /** Build a sub-hyperplane covering the whole hyperplane.
-     * @return a sub-hyperplane covering the whole hyperplane
-     */
-    SubHyperplane<S> wholeHyperplane();
-
-    /** Build a region covering the whole space.
-     * @return a region containing the instance
-     */
-    Region<S> wholeSpace();
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/InsideFinder.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/InsideFinder.java
deleted file mode 100644
index 3429d3a..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/InsideFinder.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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.partitioning;
-
-import org.apache.commons.math4.geometry.Space;
-
-/** Utility class checking if inside nodes can be found
- * on the plus and minus sides of an hyperplane.
- * @param <S> Type of the space.
- * @since 3.4
- */
-class InsideFinder<S extends Space> {
-
-    /** Region on which to operate. */
-    private final Region<S> region;
-
-    /** Indicator of inside leaf nodes found on the plus side. */
-    private boolean plusFound;
-
-    /** Indicator of inside leaf nodes found on the plus side. */
-    private boolean minusFound;
-
-    /** Simple constructor.
-     * @param region region on which to operate
-     */
-    InsideFinder(final Region<S> region) {
-        this.region = region;
-        plusFound  = false;
-        minusFound = false;
-    }
-
-    /** Search recursively for inside leaf nodes on each side of the given hyperplane.
-
-     * <p>The algorithm used here is directly derived from the one
-     * described in section III (<i>Binary Partitioning of a BSP
-     * Tree</i>) of the Bruce Naylor, John Amanatides and William
-     * Thibault paper <a
-     * href="http://www.cs.yorku.ca/~amana/research/bsptSetOp.pdf">Merging
-     * BSP Trees Yields Polyhedral Set Operations</a> Proc. Siggraph
-     * '90, Computer Graphics 24(4), August 1990, pp 115-124, published
-     * by the Association for Computing Machinery (ACM)..</p>
-
-     * @param node current BSP tree node
-     * @param sub sub-hyperplane
-     */
-    public void recurseSides(final BSPTree<S> node, final SubHyperplane<S> sub) {
-
-        if (node.getCut() == null) {
-            if ((Boolean) node.getAttribute()) {
-                // this is an inside cell expanding across the hyperplane
-                plusFound  = true;
-                minusFound = true;
-            }
-            return;
-        }
-
-        final Hyperplane<S> hyperplane = node.getCut().getHyperplane();
-        final SubHyperplane.SplitSubHyperplane<S> split = sub.split(hyperplane);
-        switch (split.getSide()) {
-        case PLUS :
-            // the sub-hyperplane is entirely in the plus sub-tree
-            if (node.getCut().split(sub.getHyperplane()).getSide() == Side.PLUS) {
-                if (!region.isEmpty(node.getMinus())) {
-                    plusFound  = true;
-                }
-            } else {
-                if (!region.isEmpty(node.getMinus())) {
-                    minusFound = true;
-                }
-            }
-            if (!(plusFound && minusFound)) {
-                recurseSides(node.getPlus(), sub);
-            }
-            break;
-        case MINUS :
-            // the sub-hyperplane is entirely in the minus sub-tree
-            if (node.getCut().split(sub.getHyperplane()).getSide() == Side.PLUS) {
-                if (!region.isEmpty(node.getPlus())) {
-                    plusFound  = true;
-                }
-            } else {
-                if (!region.isEmpty(node.getPlus())) {
-                    minusFound = true;
-                }
-            }
-            if (!(plusFound && minusFound)) {
-                recurseSides(node.getMinus(), sub);
-            }
-            break;
-        case BOTH :
-            // the sub-hyperplane extends in both sub-trees
-
-            // explore first the plus sub-tree
-            recurseSides(node.getPlus(), split.getPlus());
-
-            // if needed, explore the minus sub-tree
-            if (!(plusFound && minusFound)) {
-                recurseSides(node.getMinus(), split.getMinus());
-            }
-            break;
-        default :
-            // the sub-hyperplane and the cut sub-hyperplane share the same hyperplane
-            if (node.getCut().getHyperplane().sameOrientationAs(sub.getHyperplane())) {
-                if ((node.getPlus().getCut() != null) || ((Boolean) node.getPlus().getAttribute())) {
-                    plusFound  = true;
-                }
-                if ((node.getMinus().getCut() != null) || ((Boolean) node.getMinus().getAttribute())) {
-                    minusFound = true;
-                }
-            } else {
-                if ((node.getPlus().getCut() != null) || ((Boolean) node.getPlus().getAttribute())) {
-                    minusFound = true;
-                }
-                if ((node.getMinus().getCut() != null) || ((Boolean) node.getMinus().getAttribute())) {
-                    plusFound  = true;
-                }
-            }
-        }
-
-    }
-
-    /** Check if inside leaf nodes have been found on the plus side.
-     * @return true if inside leaf nodes have been found on the plus side
-     */
-    public boolean plusFound() {
-        return plusFound;
-    }
-
-    /** Check if inside leaf nodes have been found on the minus side.
-     * @return true if inside leaf nodes have been found on the minus side
-     */
-    public boolean minusFound() {
-        return minusFound;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/NodesSet.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/NodesSet.java
deleted file mode 100644
index 1d55c5b..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/NodesSet.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.partitioning;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.commons.math4.geometry.Space;
-
-/** Set of {@link BSPTree BSP tree} nodes.
- * @see BoundaryAttribute
- * @param <S> Type of the space.
- * @since 3.4
- */
-public class NodesSet<S extends Space> implements Iterable<BSPTree<S>> {
-
-    /** List of sub-hyperplanes. */
-    private final List<BSPTree<S>> list;
-
-    /** Simple constructor.
-     */
-    public NodesSet() {
-        list = new ArrayList<>();
-    }
-
-    /** Add a node if not already known.
-     * @param node node to add
-     */
-    public void add(final BSPTree<S> node) {
-
-        for (final BSPTree<S> existing : list) {
-            if (node == existing) {
-                // the node is already known, don't add it
-                return;
-            }
-        }
-
-        // the node was not known, add it
-        list.add(node);
-
-    }
-
-    /** Add nodes if they are not already known.
-     * @param iterator nodes iterator
-     */
-    public void addAll(final Iterable<BSPTree<S>> iterator) {
-        for (final BSPTree<S> node : iterator) {
-            add(node);
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Iterator<BSPTree<S>> iterator() {
-        return list.iterator();
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/Region.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/Region.java
deleted file mode 100644
index 40314a5..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/Region.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * 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.partitioning;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-
-/** This interface represents a region of a space as a partition.
-
- * <p>Region are subsets of a space, they can be infinite (whole
- * space, half space, infinite stripe ...) or finite (polygons in 2D,
- * polyhedrons in 3D ...). Their main characteristic is to separate
- * points that are considered to be <em>inside</em> the region from
- * points considered to be <em>outside</em> of it. In between, there
- * may be points on the <em>boundary</em> of the region.</p>
-
- * <p>This implementation is limited to regions for which the boundary
- * is composed of several {@link SubHyperplane sub-hyperplanes},
- * including regions with no boundary at all: the whole space and the
- * empty region. They are not necessarily finite and not necessarily
- * path-connected. They can contain holes.</p>
-
- * <p>Regions can be combined using the traditional sets operations :
- * union, intersection, difference and symetric difference (exclusive
- * or) for the binary operations, complement for the unary
- * operation.</p>
-
- * <p>
- * Note that this interface is <em>not</em> intended to be implemented
- * by Apache Commons Math users, it is only intended to be implemented
- * within the library itself. New methods may be added even for minor
- * versions, which breaks compatibility for external implementations.
- * </p>
-
- * @param <S> Type of the space.
-
- * @since 3.0
- */
-public interface Region<S extends Space> {
-
-    /** Enumerate for the location of a point with respect to the region. */
-    enum Location {
-        /** Code for points inside the partition. */
-        INSIDE,
-
-        /** Code for points outside of the partition. */
-        OUTSIDE,
-
-        /** Code for points on the partition boundary. */
-        BOUNDARY;
-    }
-
-    /** Build a region using the instance as a prototype.
-     * <p>This method allow to create new instances without knowing
-     * exactly the type of the region. It is an application of the
-     * prototype design pattern.</p>
-     * <p>The leaf nodes of the BSP tree <em>must</em> have a
-     * {@code Boolean} attribute representing the inside status of
-     * the corresponding cell (true for inside cells, false for outside
-     * cells). In order to avoid building too many small objects, it is
-     * recommended to use the predefined constants
-     * {@code Boolean.TRUE} and {@code Boolean.FALSE}. The
-     * tree also <em>must</em> have either null internal nodes or
-     * internal nodes representing the boundary as specified in the
-     * {@link #getTree getTree} method).</p>
-     * @param newTree inside/outside BSP tree representing the new region
-     * @return the built region
-     */
-    Region<S> buildNew(BSPTree<S> newTree);
-
-    /** Copy the instance.
-     * <p>The instance created is completely independant of the original
-     * one. A deep copy is used, none of the underlying objects are
-     * shared (except for the underlying tree {@code Boolean}
-     * attributes and immutable objects).</p>
-     * @return a new region, copy of the instance
-     */
-    Region<S> copySelf();
-
-    /** Check if the instance is empty.
-     * @return true if the instance is empty
-     */
-    boolean isEmpty();
-
-    /** Check if the sub-tree starting at a given node is empty.
-     * @param node root node of the sub-tree (<em>must</em> have {@link
-     * Region Region} tree semantics, i.e. the leaf nodes must have
-     * {@code Boolean} attributes representing an inside/outside
-     * property)
-     * @return true if the sub-tree starting at the given node is empty
-     */
-    boolean isEmpty(final BSPTree<S> node);
-
-    /** Check if the instance covers the full space.
-     * @return true if the instance covers the full space
-     */
-    boolean isFull();
-
-    /** Check if the sub-tree starting at a given node covers the full space.
-     * @param node root node of the sub-tree (<em>must</em> have {@link
-     * Region Region} tree semantics, i.e. the leaf nodes must have
-     * {@code Boolean} attributes representing an inside/outside
-     * property)
-     * @return true if the sub-tree starting at the given node covers the full space
-     */
-    boolean isFull(final BSPTree<S> node);
-
-    /** Check if the instance entirely contains another region.
-     * @param region region to check against the instance
-     * @return true if the instance contains the specified tree
-     */
-    boolean contains(final Region<S> region);
-
-    /** Check a point with respect to the region.
-     * @param point point to check
-     * @return a code representing the point status: either {@link
-     * Location#INSIDE}, {@link Location#OUTSIDE} or {@link Location#BOUNDARY}
-     */
-    Location checkPoint(final Point<S> point);
-
-    /** Project a point on the boundary of the region.
-     * @param point point to check
-     * @return projection of the point on the boundary
-     * @since 3.3
-     */
-    BoundaryProjection<S> projectToBoundary(final Point<S> point);
-
-    /** Get the underlying BSP tree.
-
-     * <p>Regions are represented by an underlying inside/outside BSP
-     * tree whose leaf attributes are {@code Boolean} instances
-     * representing inside leaf cells if the attribute value is
-     * {@code true} and outside leaf cells if the attribute is
-     * {@code false}. These leaf attributes are always present and
-     * guaranteed to be non null.</p>
-
-     * <p>In addition to the leaf attributes, the internal nodes which
-     * correspond to cells split by cut sub-hyperplanes may contain
-     * {@link BoundaryAttribute BoundaryAttribute} objects representing
-     * the parts of the corresponding cut sub-hyperplane that belong to
-     * the boundary. When the boundary attributes have been computed,
-     * all internal nodes are guaranteed to have non-null
-     * attributes, however some {@link BoundaryAttribute
-     * BoundaryAttribute} instances may have their {@link
-     * BoundaryAttribute#getPlusInside() getPlusInside} and {@link
-     * BoundaryAttribute#getPlusOutside() getPlusOutside} methods both
-     * returning null if the corresponding cut sub-hyperplane does not
-     * have any parts belonging to the boundary.</p>
-
-     * <p>Since computing the boundary is not always required and can be
-     * time-consuming for large trees, these internal nodes attributes
-     * are computed using lazy evaluation only when required by setting
-     * the {@code includeBoundaryAttributes} argument to
-     * {@code true}. Once computed, these attributes remain in the
-     * tree, which implies that in this case, further calls to the
-     * method for the same region will always include these attributes
-     * regardless of the value of the
-     * {@code includeBoundaryAttributes} argument.</p>
-
-     * @param includeBoundaryAttributes if true, the boundary attributes
-     * at internal nodes are guaranteed to be included (they may be
-     * included even if the argument is false, if they have already been
-     * computed due to a previous call)
-     * @return underlying BSP tree
-     * @see BoundaryAttribute
-     */
-    BSPTree<S> getTree(final boolean includeBoundaryAttributes);
-
-    /** Get the size of the boundary.
-     * @return the size of the boundary (this is 0 in 1D, a length in
-     * 2D, an area in 3D ...)
-     */
-    double getBoundarySize();
-
-    /** Get the size of the instance.
-     * @return the size of the instance (this is a length in 1D, an area
-     * in 2D, a volume in 3D ...)
-     */
-    double getSize();
-
-    /** Get the barycenter of the instance.
-     * @return an object representing the barycenter
-     */
-    Point<S> getBarycenter();
-
-    /** Get the parts of a sub-hyperplane that are contained in the region.
-     * <p>The parts of the sub-hyperplane that belong to the boundary are
-     * <em>not</em> included in the resulting parts.</p>
-     * @param sub sub-hyperplane traversing the region
-     * @return filtered sub-hyperplane
-     */
-    SubHyperplane<S> intersection(final SubHyperplane<S> sub);
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/RegionFactory.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/RegionFactory.java
deleted file mode 100644
index 3b0e795..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/RegionFactory.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * 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.partitioning;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.partitioning.BSPTree.VanishingCutHandler;
-import org.apache.commons.math4.geometry.partitioning.Region.Location;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane.SplitSubHyperplane;
-
-/** This class is a factory for {@link Region}.
-
- * @param <S> Type of the space.
-
- * @since 3.0
- */
-public class RegionFactory<S extends Space> {
-
-    /** Visitor removing internal nodes attributes. */
-    private final NodesCleaner nodeCleaner;
-
-    /** Simple constructor.
-     */
-    public RegionFactory() {
-        nodeCleaner = new NodesCleaner();
-    }
-
-    /** Build a convex region from a collection of bounding hyperplanes.
-     * @param hyperplanes collection of bounding hyperplanes
-     * @return a new convex region, or null if the collection is empty
-     */
-    @SafeVarargs
-    public final Region<S> buildConvex(final Hyperplane<S> ... hyperplanes) {
-        if ((hyperplanes == null) || (hyperplanes.length == 0)) {
-            return null;
-        }
-
-        // use the first hyperplane to build the right class
-        final Region<S> region = hyperplanes[0].wholeSpace();
-
-        // chop off parts of the space
-        BSPTree<S> node = region.getTree(false);
-        node.setAttribute(Boolean.TRUE);
-        for (final Hyperplane<S> hyperplane : hyperplanes) {
-            if (node.insertCut(hyperplane)) {
-                node.setAttribute(null);
-                node.getPlus().setAttribute(Boolean.FALSE);
-                node = node.getMinus();
-                node.setAttribute(Boolean.TRUE);
-            } else {
-                // the hyperplane could not be inserted in the current leaf node
-                // either it is completely outside (which means the input hyperplanes
-                // are wrong), or it is parallel to a previous hyperplane
-                SubHyperplane<S> s = hyperplane.wholeHyperplane();
-                for (BSPTree<S> tree = node; tree.getParent() != null && s != null; tree = tree.getParent()) {
-                    final Hyperplane<S>         other = tree.getParent().getCut().getHyperplane();
-                    final SplitSubHyperplane<S> split = s.split(other);
-                    switch (split.getSide()) {
-                        case HYPER :
-                            // the hyperplane is parallel to a previous hyperplane
-                            if (!hyperplane.sameOrientationAs(other)) {
-                                // this hyperplane is opposite to the other one,
-                                // the region is thinner than the tolerance, we consider it empty
-                                return getComplement(hyperplanes[0].wholeSpace());
-                            }
-                            // the hyperplane is an extension of an already known hyperplane, we just ignore it
-                            break;
-                        case PLUS :
-                        // the hyperplane is outside of the current convex zone,
-                        // the input hyperplanes are inconsistent
-                        throw new MathIllegalArgumentException(LocalizedFormats.NOT_CONVEX_HYPERPLANES);
-                        default :
-                            s = split.getMinus();
-                    }
-                }
-            }
-        }
-
-        return region;
-
-    }
-
-    /** Compute the union of two regions.
-     * @param region1 first region (will be unusable after the operation as
-     * parts of it will be reused in the new region)
-     * @param region2 second region (will be unusable after the operation as
-     * parts of it will be reused in the new region)
-     * @return a new region, result of {@code region1 union region2}
-     */
-    public Region<S> union(final Region<S> region1, final Region<S> region2) {
-        final BSPTree<S> tree =
-            region1.getTree(false).merge(region2.getTree(false), new UnionMerger());
-        tree.visit(nodeCleaner);
-        return region1.buildNew(tree);
-    }
-
-    /** Compute the intersection of two regions.
-     * @param region1 first region (will be unusable after the operation as
-     * parts of it will be reused in the new region)
-     * @param region2 second region (will be unusable after the operation as
-     * parts of it will be reused in the new region)
-     * @return a new region, result of {@code region1 intersection region2}
-     */
-    public Region<S> intersection(final Region<S> region1, final Region<S> region2) {
-        final BSPTree<S> tree =
-            region1.getTree(false).merge(region2.getTree(false), new IntersectionMerger());
-        tree.visit(nodeCleaner);
-        return region1.buildNew(tree);
-    }
-
-    /** Compute the symmetric difference (exclusive or) of two regions.
-     * @param region1 first region (will be unusable after the operation as
-     * parts of it will be reused in the new region)
-     * @param region2 second region (will be unusable after the operation as
-     * parts of it will be reused in the new region)
-     * @return a new region, result of {@code region1 xor region2}
-     */
-    public Region<S> xor(final Region<S> region1, final Region<S> region2) {
-        final BSPTree<S> tree =
-            region1.getTree(false).merge(region2.getTree(false), new XorMerger());
-        tree.visit(nodeCleaner);
-        return region1.buildNew(tree);
-    }
-
-    /** Compute the difference of two regions.
-     * @param region1 first region (will be unusable after the operation as
-     * parts of it will be reused in the new region)
-     * @param region2 second region (will be unusable after the operation as
-     * parts of it will be reused in the new region)
-     * @return a new region, result of {@code region1 minus region2}
-     */
-    public Region<S> difference(final Region<S> region1, final Region<S> region2) {
-        final BSPTree<S> tree =
-            region1.getTree(false).merge(region2.getTree(false), new DifferenceMerger(region1, region2));
-        tree.visit(nodeCleaner);
-        return region1.buildNew(tree);
-    }
-
-    /** Get the complement of the region (exchanged interior/exterior).
-     * @param region region to complement, it will not modified, a new
-     * region independent region will be built
-     * @return a new region, complement of the specified one
-     */
-    /** Get the complement of the region (exchanged interior/exterior).
-     * @param region region to complement, it will not modified, a new
-     * region independent region will be built
-     * @return a new region, complement of the specified one
-     */
-    public Region<S> getComplement(final Region<S> region) {
-        return region.buildNew(recurseComplement(region.getTree(false)));
-    }
-
-    /** Recursively build the complement of a BSP tree.
-     * @param node current node of the original tree
-     * @return new tree, complement of the node
-     */
-    private BSPTree<S> recurseComplement(final BSPTree<S> node) {
-
-        // transform the tree, except for boundary attribute splitters
-        final Map<BSPTree<S>, BSPTree<S>> map = new HashMap<>();
-        final BSPTree<S> transformedTree = recurseComplement(node, map);
-
-        // set up the boundary attributes splitters
-        for (final Map.Entry<BSPTree<S>, BSPTree<S>> entry : map.entrySet()) {
-            if (entry.getKey().getCut() != null) {
-                @SuppressWarnings("unchecked")
-                BoundaryAttribute<S> original = (BoundaryAttribute<S>) entry.getKey().getAttribute();
-                if (original != null) {
-                    @SuppressWarnings("unchecked")
-                    BoundaryAttribute<S> transformed = (BoundaryAttribute<S>) entry.getValue().getAttribute();
-                    for (final BSPTree<S> splitter : original.getSplitters()) {
-                        transformed.getSplitters().add(map.get(splitter));
-                    }
-                }
-            }
-        }
-
-        return transformedTree;
-
-    }
-
-    /** Recursively build the complement of a BSP tree.
-     * @param node current node of the original tree
-     * @param map transformed nodes map
-     * @return new tree, complement of the node
-     */
-    private BSPTree<S> recurseComplement(final BSPTree<S> node,
-                                         final Map<BSPTree<S>, BSPTree<S>> map) {
-
-        final BSPTree<S> transformedNode;
-        if (node.getCut() == null) {
-            transformedNode = new BSPTree<>(((Boolean) node.getAttribute()) ? Boolean.FALSE : Boolean.TRUE);
-        } else {
-
-            @SuppressWarnings("unchecked")
-            BoundaryAttribute<S> attribute = (BoundaryAttribute<S>) node.getAttribute();
-            if (attribute != null) {
-                final SubHyperplane<S> plusOutside =
-                        (attribute.getPlusInside() == null) ? null : attribute.getPlusInside().copySelf();
-                final SubHyperplane<S> plusInside  =
-                        (attribute.getPlusOutside() == null) ? null : attribute.getPlusOutside().copySelf();
-                // we start with an empty list of splitters, it will be filled in out of recursion
-                attribute = new BoundaryAttribute<>(plusOutside, plusInside, new NodesSet<S>());
-            }
-
-            transformedNode = new BSPTree<>(node.getCut().copySelf(),
-                                             recurseComplement(node.getPlus(),  map),
-                                             recurseComplement(node.getMinus(), map),
-                                             attribute);
-        }
-
-        map.put(node, transformedNode);
-        return transformedNode;
-
-    }
-
-    /** BSP tree leaf merger computing union of two regions. */
-    private class UnionMerger implements BSPTree.LeafMerger<S> {
-        /** {@inheritDoc} */
-        @Override
-        public BSPTree<S> merge(final BSPTree<S> leaf, final BSPTree<S> tree,
-                                final BSPTree<S> parentTree,
-                                final boolean isPlusChild, final boolean leafFromInstance) {
-            if ((Boolean) leaf.getAttribute()) {
-                // the leaf node represents an inside cell
-                leaf.insertInTree(parentTree, isPlusChild, new VanishingToLeaf(true));
-                return leaf;
-            }
-            // the leaf node represents an outside cell
-            tree.insertInTree(parentTree, isPlusChild, new VanishingToLeaf(false));
-            return tree;
-        }
-    }
-
-    /** BSP tree leaf merger computing intersection of two regions. */
-    private class IntersectionMerger implements BSPTree.LeafMerger<S> {
-        /** {@inheritDoc} */
-        @Override
-        public BSPTree<S> merge(final BSPTree<S> leaf, final BSPTree<S> tree,
-                                final BSPTree<S> parentTree,
-                                final boolean isPlusChild, final boolean leafFromInstance) {
-            if ((Boolean) leaf.getAttribute()) {
-                // the leaf node represents an inside cell
-                tree.insertInTree(parentTree, isPlusChild, new VanishingToLeaf(true));
-                return tree;
-            }
-            // the leaf node represents an outside cell
-            leaf.insertInTree(parentTree, isPlusChild, new VanishingToLeaf(false));
-            return leaf;
-        }
-    }
-
-    /** BSP tree leaf merger computing symmetric difference (exclusive or) of two regions. */
-    private class XorMerger implements BSPTree.LeafMerger<S> {
-        /** {@inheritDoc} */
-        @Override
-        public BSPTree<S> merge(final BSPTree<S> leaf, final BSPTree<S> tree,
-                                final BSPTree<S> parentTree, final boolean isPlusChild,
-                                final boolean leafFromInstance) {
-            BSPTree<S> t = tree;
-            if ((Boolean) leaf.getAttribute()) {
-                // the leaf node represents an inside cell
-                t = recurseComplement(t);
-            }
-            t.insertInTree(parentTree, isPlusChild, new VanishingToLeaf(true));
-            return t;
-        }
-    }
-
-    /** BSP tree leaf merger computing difference of two regions. */
-    private class DifferenceMerger implements BSPTree.LeafMerger<S>, VanishingCutHandler<S> {
-
-        /** Region to subtract from. */
-        private final Region<S> region1;
-
-        /** Region to subtract. */
-        private final Region<S> region2;
-
-        /** Simple constructor.
-         * @param region1 region to subtract from
-         * @param region2 region to subtract
-         */
-        DifferenceMerger(final Region<S> region1, final Region<S> region2) {
-            this.region1 = region1.copySelf();
-            this.region2 = region2.copySelf();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public BSPTree<S> merge(final BSPTree<S> leaf, final BSPTree<S> tree,
-                                final BSPTree<S> parentTree, final boolean isPlusChild,
-                                final boolean leafFromInstance) {
-            if ((Boolean) leaf.getAttribute()) {
-                // the leaf node represents an inside cell
-                final BSPTree<S> argTree =
-                    recurseComplement(leafFromInstance ? tree : leaf);
-                argTree.insertInTree(parentTree, isPlusChild, this);
-                return argTree;
-            }
-            // the leaf node represents an outside cell
-            final BSPTree<S> instanceTree =
-                leafFromInstance ? leaf : tree;
-            instanceTree.insertInTree(parentTree, isPlusChild, this);
-            return instanceTree;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public BSPTree<S> fixNode(final BSPTree<S> node) {
-            // get a representative point in the degenerate cell
-            final BSPTree<S> cell = node.pruneAroundConvexCell(Boolean.TRUE, Boolean.FALSE, null);
-            final Region<S> r = region1.buildNew(cell);
-            final Point<S> p = r.getBarycenter();
-            return new BSPTree<>(region1.checkPoint(p) == Location.INSIDE &&
-                                  region2.checkPoint(p) == Location.OUTSIDE);
-        }
-
-    }
-
-    /** Visitor removing internal nodes attributes. */
-    private class NodesCleaner implements  BSPTreeVisitor<S> {
-
-        /** {@inheritDoc} */
-        @Override
-        public Order visitOrder(final BSPTree<S> node) {
-            return Order.PLUS_SUB_MINUS;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void visitInternalNode(final BSPTree<S> node) {
-            node.setAttribute(null);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void visitLeafNode(final BSPTree<S> node) {
-        }
-
-    }
-
-    /** Handler replacing nodes with vanishing cuts with leaf nodes. */
-    private class VanishingToLeaf implements VanishingCutHandler<S> {
-
-        /** Inside/outside indocator to use for ambiguous nodes. */
-        private final boolean inside;
-
-        /** Simple constructor.
-         * @param inside inside/outside indicator to use for ambiguous nodes
-         */
-        VanishingToLeaf(final boolean inside) {
-            this.inside = inside;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public BSPTree<S> fixNode(final BSPTree<S> node) {
-            if (node.getPlus().getAttribute().equals(node.getMinus().getAttribute())) {
-                // no ambiguity
-                return new BSPTree<>(node.getPlus().getAttribute());
-            } else {
-                // ambiguous node
-                return new BSPTree<>(inside);
-            }
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/Side.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/Side.java
deleted file mode 100644
index 4851230..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/Side.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.partitioning;
-
-/** Enumerate representing the location of an element with respect to an
- * {@link Hyperplane hyperplane} of a space.
- * @since 3.0
- */
-public enum Side {
-
-    /** Code for the plus side of the hyperplane. */
-    PLUS,
-
-    /** Code for the minus side of the hyperplane. */
-    MINUS,
-
-    /** Code for elements crossing the hyperplane from plus to minus side. */
-    BOTH,
-
-    /** Code for the hyperplane itself. */
-    HYPER;
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/SubHyperplane.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/SubHyperplane.java
deleted file mode 100644
index 9e8461a..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/SubHyperplane.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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.partitioning;
-
-import org.apache.commons.math4.geometry.Space;
-
-/** This interface represents the remaining parts of an hyperplane after
- * other parts have been chopped off.
-
- * <p>sub-hyperplanes are obtained when parts of an {@link
- * Hyperplane hyperplane} are chopped off by other hyperplanes that
- * intersect it. The remaining part is a convex region. Such objects
- * appear in {@link BSPTree BSP trees} as the intersection of a cut
- * hyperplane with the convex region which it splits, the chopping
- * hyperplanes are the cut hyperplanes closer to the tree root.</p>
-
- * <p>
- * Note that this interface is <em>not</em> intended to be implemented
- * by Apache Commons Math users, it is only intended to be implemented
- * within the library itself. New methods may be added even for minor
- * versions, which breaks compatibility for external implementations.
- * </p>
-
- * @param <S> Type of the embedding space.
-
- * @since 3.0
- */
-public interface SubHyperplane<S extends Space> {
-
-    /** Copy the instance.
-     * <p>The instance created is completely independent of the original
-     * one. A deep copy is used, none of the underlying objects are
-     * shared (except for the nodes attributes and immutable
-     * objects).</p>
-     * @return a new sub-hyperplane, copy of the instance
-     */
-    SubHyperplane<S> copySelf();
-
-    /** Get the underlying hyperplane.
-     * @return underlying hyperplane
-     */
-    Hyperplane<S> getHyperplane();
-
-    /** Check if the instance is empty.
-     * @return true if the instance is empty
-     */
-    boolean isEmpty();
-
-    /** Get the size of the instance.
-     * @return the size of the instance (this is a length in 1D, an area
-     * in 2D, a volume in 3D ...)
-     */
-    double getSize();
-
-    /** Split the instance in two parts by an hyperplane.
-     * @param hyperplane splitting hyperplane
-     * @return an object containing both the part of the instance
-     * on the plus side of the hyperplane and the part of the
-     * instance on the minus side of the hyperplane
-     */
-    SplitSubHyperplane<S> split(Hyperplane<S> hyperplane);
-
-    /** Compute the union of the instance and another sub-hyperplane.
-     * @param other other sub-hyperplane to union (<em>must</em> be in the
-     * same hyperplane as the instance)
-     * @return a new sub-hyperplane, union of the instance and other
-     */
-    SubHyperplane<S> reunite(SubHyperplane<S> other);
-
-    /** Class holding the results of the {@link #split split} method.
-     * @param <U> Type of the embedding space.
-     */
-    class SplitSubHyperplane<U extends Space> {
-
-        /** Part of the sub-hyperplane on the plus side of the splitting hyperplane. */
-        private final SubHyperplane<U> plus;
-
-        /** Part of the sub-hyperplane on the minus side of the splitting hyperplane. */
-        private final SubHyperplane<U> minus;
-
-        /** Build a SplitSubHyperplane from its parts.
-         * @param plus part of the sub-hyperplane on the plus side of the
-         * splitting hyperplane
-         * @param minus part of the sub-hyperplane on the minus side of the
-         * splitting hyperplane
-         */
-        public SplitSubHyperplane(final SubHyperplane<U> plus,
-                                  final SubHyperplane<U> minus) {
-            this.plus  = plus;
-            this.minus = minus;
-        }
-
-        /** Get the part of the sub-hyperplane on the plus side of the splitting hyperplane.
-         * @return part of the sub-hyperplane on the plus side of the splitting hyperplane
-         */
-        public SubHyperplane<U> getPlus() {
-            return plus;
-        }
-
-        /** Get the part of the sub-hyperplane on the minus side of the splitting hyperplane.
-         * @return part of the sub-hyperplane on the minus side of the splitting hyperplane
-         */
-        public SubHyperplane<U> getMinus() {
-            return minus;
-        }
-
-        /** Get the side of the split sub-hyperplane with respect to its splitter.
-         * @return {@link Side#PLUS} if only {@link #getPlus()} is neither null nor empty,
-         * {@link Side#MINUS} if only {@link #getMinus()} is neither null nor empty,
-         * {@link Side#BOTH} if both {@link #getPlus()} and {@link #getMinus()}
-         * are neither null nor empty or {@link Side#HYPER} if both {@link #getPlus()} and
-         * {@link #getMinus()} are either null or empty
-         * @since 3.6
-         */
-        public Side getSide() {
-            if (plus != null && !plus.isEmpty()) {
-                if (minus != null && !minus.isEmpty()) {
-                    return Side.BOTH;
-                } else {
-                    return Side.PLUS;
-                }
-            } else if (minus != null && !minus.isEmpty()) {
-                return Side.MINUS;
-            } else {
-                return Side.HYPER;
-            }
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/Transform.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/Transform.java
deleted file mode 100644
index 3fd3c08..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/Transform.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.partitioning;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-
-
-/** This interface represents an inversible affine transform in a space.
- * <p>Inversible affine transform include for example scalings,
- * translations, rotations.</p>
-
- * <p>Transforms are dimension-specific. The consistency rules between
- * the three {@code apply} methods are the following ones for a
- * transformed defined for dimension D:</p>
- * <ul>
- *   <li>
- *     the transform can be applied to a point in the
- *     D-dimension space using its {@link #apply(Point)}
- *     method
- *   </li>
- *   <li>
- *     the transform can be applied to a (D-1)-dimension
- *     hyperplane in the D-dimension space using its
- *     {@link #apply(Hyperplane)} method
- *   </li>
- *   <li>
- *     the transform can be applied to a (D-2)-dimension
- *     sub-hyperplane in a (D-1)-dimension hyperplane using
- *     its {@link #apply(SubHyperplane, Hyperplane, Hyperplane)}
- *     method
- *   </li>
- * </ul>
-
- * @param <S> Type of the embedding space.
- * @param <T> Type of the embedded sub-space.
-
- * @since 3.0
- */
-public interface Transform<S extends Space, T extends Space> {
-
-    /** Transform a point of a space.
-     * @param point point to transform
-     * @return a new object representing the transformed point
-     */
-    Point<S> apply(Point<S> point);
-
-    /** Transform an hyperplane of a space.
-     * @param hyperplane hyperplane to transform
-     * @return a new object representing the transformed hyperplane
-     */
-    Hyperplane<S> apply(Hyperplane<S> hyperplane);
-
-    /** Transform a sub-hyperplane embedded in an hyperplane.
-     * @param sub sub-hyperplane to transform
-     * @param original hyperplane in which the sub-hyperplane is
-     * defined (this is the original hyperplane, the transform has
-     * <em>not</em> been applied to it)
-     * @param transformed hyperplane in which the sub-hyperplane is
-     * defined (this is the transformed hyperplane, the transform
-     * <em>has</em> been applied to it)
-     * @return a new object representing the transformed sub-hyperplane
-     */
-    SubHyperplane<T> apply(SubHyperplane<T> sub, Hyperplane<S> original, Hyperplane<S> transformed);
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/partitioning/package-info.java b/src/main/java/org/apache/commons/math4/geometry/partitioning/package-info.java
deleted file mode 100644
index e427483..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/partitioning/package-info.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.
- */
-/**
- *
- * This package provides classes to implement Binary Space Partition trees.
- *
- * <p>
- * {@link org.apache.commons.math4.geometry.partitioning.BSPTree BSP trees}
- * are an efficient way to represent parts of space and in particular
- * polytopes (line segments in 1D, polygons in 2D and polyhedrons in 3D)
- * and to operate on them. The main principle is to recursively subdivide
- * the space using simple hyperplanes (points in 1D, lines in 2D, planes
- * in 3D).
- * </p>
- *
- * <p>
- * We start with a tree composed of a single node without any cut
- * hyperplane: it represents the complete space, which is a convex
- * part. If we add a cut hyperplane to this node, this represents a
- * partition with the hyperplane at the node level and two half spaces at
- * each side of the cut hyperplane. These half-spaces are represented by
- * two child nodes without any cut hyperplanes associated, the plus child
- * which represents the half space on the plus side of the cut hyperplane
- * and the minus child on the other side. Continuing the subdivisions, we
- * end up with a tree having internal nodes that are associated with a
- * cut hyperplane and leaf nodes without any hyperplane which correspond
- * to convex parts.
- * </p>
- *
- * <p>
- * When BSP trees are used to represent polytopes, the convex parts are
- * known to be completely inside or outside the polytope as long as there
- * is no facet in the part (which is obviously the case if the cut
- * hyperplanes have been chosen as the underlying hyperplanes of the
- * facets (this is called an autopartition) and if the subdivision
- * process has been continued until all facets have been processed. It is
- * important to note that the polytope is <em>not</em> defined by a
- * single part, but by several convex ones. This is the property that
- * allows BSP-trees to represent non-convex polytopes despites all parts
- * are convex. The {@link
- * org.apache.commons.math4.geometry.partitioning.Region Region} class is
- * devoted to this representation, it is build on top of the {@link
- * org.apache.commons.math4.geometry.partitioning.BSPTree BSPTree} class using
- * boolean objects as the leaf nodes attributes to represent the
- * inside/outside property of each leaf part, and also adds various
- * methods dealing with boundaries (i.e. the separation between the
- * inside and the outside parts).
- * </p>
- *
- * <p>
- * Rather than simply associating the internal nodes with an hyperplane,
- * we consider <em>sub-hyperplanes</em> which correspond to the part of
- * the hyperplane that is inside the convex part defined by all the
- * parent nodes (this implies that the sub-hyperplane at root node is in
- * fact a complete hyperplane, because there is no parent to bound
- * it). Since the parts are convex, the sub-hyperplanes are convex, in
- * 3D the convex parts are convex polyhedrons, and the sub-hyperplanes
- * are convex polygons that cut these polyhedrons in two
- * sub-polyhedrons. Using this definition, a BSP tree completely
- * partitions the space. Each point either belongs to one of the
- * sub-hyperplanes in an internal node or belongs to one of the leaf
- * convex parts.
- * </p>
- *
- * <p>
- * In order to determine where a point is, it is sufficient to check its
- * position with respect to the root cut hyperplane, to select the
- * corresponding child tree and to repeat the procedure recursively,
- * until either the point appears to be exactly on one of the hyperplanes
- * in the middle of the tree or to be in one of the leaf parts. For
- * this operation, it is sufficient to consider the complete hyperplanes,
- * there is no need to check the points with the boundary of the
- * sub-hyperplanes, because this check has in fact already been realized
- * by the recursive descent in the tree. This is very easy to do and very
- * efficient, especially if the tree is well balanced (the cost is
- * <code>O(log(n))</code> where <code>n</code> is the number of facets)
- * or if the first tree levels close to the root discriminate large parts
- * of the total space.
- * </p>
- *
- * <p>
- * One of the main sources for the development of this package was Bruce
- * Naylor, John Amanatides and William Thibault paper <a
- * href="http://www.cs.yorku.ca/~amana/research/bsptSetOp.pdf">Merging
- * BSP Trees Yields Polyhedral Set Operations</a> Proc. Siggraph '90,
- * Computer Graphics 24(4), August 1990, pp 115-124, published by the
- * Association for Computing Machinery (ACM). The same paper can also be
- * found <a
- * href="http://www.cs.utexas.edu/users/fussell/courses/cs384g/bsp_treemerge.pdf">here</a>.
- * </p>
- *
- * <p>
- * Note that the interfaces defined in this package are <em>not</em> intended to
- * be implemented by Apache Commons Math users, they are only intended to be
- * implemented within the library itself. New methods may be added even for
- * minor versions, which breaks compatibility for external implementations.
- * </p>
- *
- */
-package org.apache.commons.math4.geometry.partitioning;
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/Arc.java b/src/main/java/org/apache/commons/math4/geometry/spherical/oned/Arc.java
deleted file mode 100644
index ae1f3bd..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/Arc.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.spherical.oned;
-
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
-import org.apache.commons.math4.exception.NumberIsTooLargeException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.partitioning.Region.Location;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-import org.apache.commons.numbers.core.Precision;
-
-
-/** This class represents an arc on a circle.
- * @see ArcsSet
- * @since 3.3
- */
-public class Arc {
-
-    /** The lower angular bound of the arc. */
-    private final double lower;
-
-    /** The upper angular bound of the arc. */
-    private final double upper;
-
-    /** Middle point of the arc. */
-    private final double middle;
-
-    /** Tolerance below which angles are considered identical. */
-    private final double tolerance;
-
-    /** Simple constructor.
-     * <p>
-     * If either {@code lower} is equals to {@code upper} or
-     * the interval exceeds \( 2 \pi \), the arc is considered
-     * to be the full circle and its initial defining boundaries
-     * will be forgotten. {@code lower} is not allowed to be
-     * greater than {@code upper} (an exception is thrown in this case).
-     * {@code lower} will be canonicalized between 0 and \( 2 \pi \), and
-     * upper shifted accordingly, so the {@link #getInf()} and {@link #getSup()}
-     * may not return the value used at instance construction.
-     * </p>
-     * @param lower lower angular bound of the arc
-     * @param upper upper angular bound of the arc
-     * @param tolerance tolerance below which angles are considered identical
-     * @exception NumberIsTooLargeException if lower is greater than upper
-     */
-    public Arc(final double lower, final double upper, final double tolerance)
-        throws NumberIsTooLargeException {
-        this.tolerance = tolerance;
-        if (Precision.equals(lower, upper, 0) || (upper - lower) >= MathUtils.TWO_PI) {
-            // the arc must cover the whole circle
-            this.lower  = 0;
-            this.upper  = MathUtils.TWO_PI;
-            this.middle = FastMath.PI;
-        } else  if (lower <= upper) {
-            this.lower  = PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(lower);
-            this.upper  = this.lower + (upper - lower);
-            this.middle = 0.5 * (this.lower + this.upper);
-        } else {
-            throw new NumberIsTooLargeException(LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
-                                                lower, upper, true);
-        }
-    }
-
-    /** Get the lower angular bound of the arc.
-     * @return lower angular bound of the arc,
-     * always between 0 and \( 2 \pi \)
-     */
-    public double getInf() {
-        return lower;
-    }
-
-    /** Get the upper angular bound of the arc.
-     * @return upper angular bound of the arc,
-     * always between {@link #getInf()} and {@link #getInf()} \( + 2 \pi \)
-     */
-    public double getSup() {
-        return upper;
-    }
-
-    /** Get the angular size of the arc.
-     * @return angular size of the arc
-     */
-    public double getSize() {
-        return upper - lower;
-    }
-
-    /** Get the barycenter of the arc.
-     * @return barycenter of the arc
-     */
-    public double getBarycenter() {
-        return middle;
-    }
-
-    /** Get the tolerance below which angles are considered identical.
-     * @return tolerance below which angles are considered identical
-     */
-    public double getTolerance() {
-        return tolerance;
-    }
-
-    /** Check a point with respect to the arc.
-     * @param point point to check
-     * @return a code representing the point status: either {@link
-     * Location#INSIDE}, {@link Location#OUTSIDE} or {@link Location#BOUNDARY}
-     */
-    public Location checkPoint(final double point) {
-        final double normalizedPoint = PlaneAngleRadians.normalize(point, middle);
-        if (normalizedPoint < lower - tolerance || normalizedPoint > upper + tolerance) {
-            return Location.OUTSIDE;
-        } else if (normalizedPoint > lower + tolerance && normalizedPoint < upper - tolerance) {
-            return Location.INSIDE;
-        } else {
-            return (getSize() >= MathUtils.TWO_PI - tolerance) ? Location.INSIDE : Location.BOUNDARY;
-        }
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/ArcsSet.java b/src/main/java/org/apache/commons/math4/geometry/spherical/oned/ArcsSet.java
deleted file mode 100644
index 2955090..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/ArcsSet.java
+++ /dev/null
@@ -1,960 +0,0 @@
-/*
- * 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.spherical.oned;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.exception.MathInternalError;
-import org.apache.commons.math4.exception.NumberIsTooLargeException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.partitioning.AbstractRegion;
-import org.apache.commons.math4.geometry.partitioning.BSPTree;
-import org.apache.commons.math4.geometry.partitioning.BoundaryProjection;
-import org.apache.commons.math4.geometry.partitioning.Side;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-import org.apache.commons.numbers.core.Precision;
-
-/** This class represents a region of a circle: a set of arcs.
- * <p>
- * Note that due to the wrapping around \(2 \pi\), barycenter is
- * ill-defined here. It was defined only in order to fulfill
- * the requirements of the {@link
- * org.apache.commons.math4.geometry.partitioning.Region Region}
- * interface, but its use is discouraged.
- * </p>
- * @since 3.3
- */
-public class ArcsSet extends AbstractRegion<Sphere1D, Sphere1D> implements Iterable<double[]> {
-
-    /** Build an arcs set representing the whole circle.
-     * @param tolerance tolerance below which close sub-arcs are merged together
-     */
-    public ArcsSet(final double tolerance) {
-        super(tolerance);
-    }
-
-    /** Build an arcs set corresponding to a single arc.
-     * <p>
-     * If either {@code lower} is equals to {@code upper} or
-     * the interval exceeds \( 2 \pi \), the arc is considered
-     * to be the full circle and its initial defining boundaries
-     * will be forgotten. {@code lower} is not allowed to be greater
-     * than {@code upper} (an exception is thrown in this case).
-     * </p>
-     * @param lower lower bound of the arc
-     * @param upper upper bound of the arc
-     * @param tolerance tolerance below which close sub-arcs are merged together
-     * @exception NumberIsTooLargeException if lower is greater than upper
-     */
-    public ArcsSet(final double lower, final double upper, final double tolerance)
-        throws NumberIsTooLargeException {
-        super(buildTree(lower, upper, tolerance), tolerance);
-    }
-
-    /** Build an arcs set from an inside/outside BSP tree.
-     * <p>The leaf nodes of the BSP tree <em>must</em> have a
-     * {@code Boolean} attribute representing the inside status of
-     * the corresponding cell (true for inside cells, false for outside
-     * cells). In order to avoid building too many small objects, it is
-     * recommended to use the predefined constants
-     * {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
-     * @param tree inside/outside BSP tree representing the arcs set
-     * @param tolerance tolerance below which close sub-arcs are merged together
-     * @exception InconsistentStateAt2PiWrapping if the tree leaf nodes are not
-     * consistent across the \( 0, 2 \pi \) crossing
-     */
-    public ArcsSet(final BSPTree<Sphere1D> tree, final double tolerance)
-        throws InconsistentStateAt2PiWrapping {
-        super(tree, tolerance);
-        check2PiConsistency();
-    }
-
-    /** Build an arcs set from a Boundary REPresentation (B-rep).
-     * <p>The boundary is provided as a collection of {@link
-     * SubHyperplane sub-hyperplanes}. Each sub-hyperplane has the
-     * interior part of the region on its minus side and the exterior on
-     * its plus side.</p>
-     * <p>The boundary elements can be in any order, and can form
-     * several non-connected sets (like for example polygons with holes
-     * or a set of disjoints polyhedrons considered as a whole). In
-     * fact, the elements do not even need to be connected together
-     * (their topological connections are not used here). However, if the
-     * boundary does not really separate an inside open from an outside
-     * open (open having here its topological meaning), then subsequent
-     * calls to the {@link
-     * org.apache.commons.math4.geometry.partitioning.Region#checkPoint(org.apache.commons.math4.geometry.Point)
-     * checkPoint} method will not be meaningful anymore.</p>
-     * <p>If the boundary is empty, the region will represent the whole
-     * space.</p>
-     * @param boundary collection of boundary elements
-     * @param tolerance tolerance below which close sub-arcs are merged together
-     * @exception InconsistentStateAt2PiWrapping if the tree leaf nodes are not
-     * consistent across the \( 0, 2 \pi \) crossing
-     */
-    public ArcsSet(final Collection<SubHyperplane<Sphere1D>> boundary, final double tolerance)
-        throws InconsistentStateAt2PiWrapping {
-        super(boundary, tolerance);
-        check2PiConsistency();
-    }
-
-    /** Build an inside/outside tree representing a single arc.
-     * @param lower lower angular bound of the arc
-     * @param upper upper angular bound of the arc
-     * @param tolerance tolerance below which close sub-arcs are merged together
-     * @return the built tree
-     * @exception NumberIsTooLargeException if lower is greater than upper
-     */
-    private static BSPTree<Sphere1D> buildTree(final double lower, final double upper,
-                                               final double tolerance)
-        throws NumberIsTooLargeException {
-
-        if (Precision.equals(lower, upper, 0) || (upper - lower) >= MathUtils.TWO_PI) {
-            // the tree must cover the whole circle
-            return new BSPTree<>(Boolean.TRUE);
-        } else  if (lower > upper) {
-            throw new NumberIsTooLargeException(LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
-                                                lower, upper, true);
-        }
-
-        // this is a regular arc, covering only part of the circle
-        final double normalizedLower = PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(lower);
-        final double normalizedUpper = normalizedLower + (upper - lower);
-        final SubHyperplane<Sphere1D> lowerCut =
-                new LimitAngle(new S1Point(normalizedLower), false, tolerance).wholeHyperplane();
-
-        if (normalizedUpper <= MathUtils.TWO_PI) {
-            // simple arc starting after 0 and ending before 2 \pi
-            final SubHyperplane<Sphere1D> upperCut =
-                    new LimitAngle(new S1Point(normalizedUpper), true, tolerance).wholeHyperplane();
-            return new BSPTree<>(lowerCut,
-                                         new BSPTree<Sphere1D>(Boolean.FALSE),
-                                         new BSPTree<>(upperCut,
-                                                               new BSPTree<Sphere1D>(Boolean.FALSE),
-                                                               new BSPTree<Sphere1D>(Boolean.TRUE),
-                                                               null),
-                                         null);
-        } else {
-            // arc wrapping around 2 \pi
-            final SubHyperplane<Sphere1D> upperCut =
-                    new LimitAngle(new S1Point(normalizedUpper - MathUtils.TWO_PI), true, tolerance).wholeHyperplane();
-            return new BSPTree<>(lowerCut,
-                                         new BSPTree<>(upperCut,
-                                                               new BSPTree<Sphere1D>(Boolean.FALSE),
-                                                               new BSPTree<Sphere1D>(Boolean.TRUE),
-                                                               null),
-                                         new BSPTree<Sphere1D>(Boolean.TRUE),
-                                         null);
-        }
-
-    }
-
-    /** Check consistency.
-    * @exception InconsistentStateAt2PiWrapping if the tree leaf nodes are not
-    * consistent across the \( 0, 2 \pi \) crossing
-    */
-    private void check2PiConsistency() throws InconsistentStateAt2PiWrapping {
-
-        // start search at the tree root
-        BSPTree<Sphere1D> root = getTree(false);
-        if (root.getCut() == null) {
-            return;
-        }
-
-        // find the inside/outside state before the smallest internal node
-        final Boolean stateBefore = (Boolean) getFirstLeaf(root).getAttribute();
-
-        // find the inside/outside state after the largest internal node
-        final Boolean stateAfter = (Boolean) getLastLeaf(root).getAttribute();
-
-        if (stateBefore ^ stateAfter) {
-            throw new InconsistentStateAt2PiWrapping();
-        }
-
-    }
-
-    /** Get the first leaf node of a tree.
-     * @param root tree root
-     * @return first leaf node (i.e. node corresponding to the region just after 0.0 radians)
-     */
-    private BSPTree<Sphere1D> getFirstLeaf(final BSPTree<Sphere1D> root) {
-
-        if (root.getCut() == null) {
-            return root;
-        }
-
-        // find the smallest internal node
-        BSPTree<Sphere1D> smallest = null;
-        for (BSPTree<Sphere1D> n = root; n != null; n = previousInternalNode(n)) {
-            smallest = n;
-        }
-
-        return leafBefore(smallest);
-
-    }
-
-    /** Get the last leaf node of a tree.
-     * @param root tree root
-     * @return last leaf node (i.e. node corresponding to the region just before \( 2 \pi \) radians)
-     */
-    private BSPTree<Sphere1D> getLastLeaf(final BSPTree<Sphere1D> root) {
-
-        if (root.getCut() == null) {
-            return root;
-        }
-
-        // find the largest internal node
-        BSPTree<Sphere1D> largest = null;
-        for (BSPTree<Sphere1D> n = root; n != null; n = nextInternalNode(n)) {
-            largest = n;
-        }
-
-        return leafAfter(largest);
-
-    }
-
-    /** Get the node corresponding to the first arc start.
-     * @return smallest internal node (i.e. first after 0.0 radians, in trigonometric direction),
-     * or null if there are no internal nodes (i.e. the set is either empty or covers the full circle)
-     */
-    private BSPTree<Sphere1D> getFirstArcStart() {
-
-        // start search at the tree root
-        BSPTree<Sphere1D> node = getTree(false);
-        if (node.getCut() == null) {
-            return null;
-        }
-
-        // walk tree until we find the smallest internal node
-        node = getFirstLeaf(node).getParent();
-
-        // walk tree until we find an arc start
-        while (node != null && !isArcStart(node)) {
-            node = nextInternalNode(node);
-        }
-
-        return node;
-
-    }
-
-    /** Check if an internal node corresponds to the start angle of an arc.
-     * @param node internal node to check
-     * @return true if the node corresponds to the start angle of an arc
-     */
-    private boolean isArcStart(final BSPTree<Sphere1D> node) {
-
-        if ((Boolean) leafBefore(node).getAttribute()) {
-            // it has an inside cell before it, it may end an arc but not start it
-            return false;
-        }
-
-        if (!(Boolean) leafAfter(node).getAttribute()) {
-            // it has an outside cell after it, it is a dummy cut away from real arcs
-            return false;
-        }
-
-        // the cell has an outside before and an inside after it
-        // it is the start of an arc
-        return true;
-
-    }
-
-    /** Check if an internal node corresponds to the end angle of an arc.
-     * @param node internal node to check
-     * @return true if the node corresponds to the end angle of an arc
-     */
-    private boolean isArcEnd(final BSPTree<Sphere1D> node) {
-
-        if (!(Boolean) leafBefore(node).getAttribute()) {
-            // it has an outside cell before it, it may start an arc but not end it
-            return false;
-        }
-
-        if ((Boolean) leafAfter(node).getAttribute()) {
-            // it has an inside cell after it, it is a dummy cut in the middle of an arc
-            return false;
-        }
-
-        // the cell has an inside before and an outside after it
-        // it is the end of an arc
-        return true;
-
-    }
-
-    /** Get the next internal node.
-     * @param node current internal node
-     * @return next internal node in trigonometric order, or null
-     * if this is the last internal node
-     */
-    private BSPTree<Sphere1D> nextInternalNode(BSPTree<Sphere1D> node) {
-
-        if (childAfter(node).getCut() != null) {
-            // the next node is in the sub-tree
-            return leafAfter(node).getParent();
-        }
-
-        // there is nothing left deeper in the tree, we backtrack
-        while (isAfterParent(node)) {
-            node = node.getParent();
-        }
-        return node.getParent();
-
-    }
-
-    /** Get the previous internal node.
-     * @param node current internal node
-     * @return previous internal node in trigonometric order, or null
-     * if this is the first internal node
-     */
-    private BSPTree<Sphere1D> previousInternalNode(BSPTree<Sphere1D> node) {
-
-        if (childBefore(node).getCut() != null) {
-            // the next node is in the sub-tree
-            return leafBefore(node).getParent();
-        }
-
-        // there is nothing left deeper in the tree, we backtrack
-        while (isBeforeParent(node)) {
-            node = node.getParent();
-        }
-        return node.getParent();
-
-    }
-
-    /** Find the leaf node just before an internal node.
-     * @param node internal node at which the sub-tree starts
-     * @return leaf node just before the internal node
-     */
-    private BSPTree<Sphere1D> leafBefore(BSPTree<Sphere1D> node) {
-
-        node = childBefore(node);
-        while (node.getCut() != null) {
-            node = childAfter(node);
-        }
-
-        return node;
-
-    }
-
-    /** Find the leaf node just after an internal node.
-     * @param node internal node at which the sub-tree starts
-     * @return leaf node just after the internal node
-     */
-    private BSPTree<Sphere1D> leafAfter(BSPTree<Sphere1D> node) {
-
-        node = childAfter(node);
-        while (node.getCut() != null) {
-            node = childBefore(node);
-        }
-
-        return node;
-
-    }
-
-    /** Check if a node is the child before its parent in trigonometric order.
-     * @param node child node considered
-     * @return true is the node has a parent end is before it in trigonometric order
-     */
-    private boolean isBeforeParent(final BSPTree<Sphere1D> node) {
-        final BSPTree<Sphere1D> parent = node.getParent();
-        if (parent == null) {
-            return false;
-        } else {
-            return node == childBefore(parent);
-        }
-    }
-
-    /** Check if a node is the child after its parent in trigonometric order.
-     * @param node child node considered
-     * @return true is the node has a parent end is after it in trigonometric order
-     */
-    private boolean isAfterParent(final BSPTree<Sphere1D> node) {
-        final BSPTree<Sphere1D> parent = node.getParent();
-        if (parent == null) {
-            return false;
-        } else {
-            return node == childAfter(parent);
-        }
-    }
-
-    /** Find the child node just before an internal node.
-     * @param node internal node at which the sub-tree starts
-     * @return child node just before the internal node
-     */
-    private BSPTree<Sphere1D> childBefore(BSPTree<Sphere1D> node) {
-        if (isDirect(node)) {
-            // smaller angles are on minus side, larger angles are on plus side
-            return node.getMinus();
-        } else {
-            // smaller angles are on plus side, larger angles are on minus side
-            return node.getPlus();
-        }
-    }
-
-    /** Find the child node just after an internal node.
-     * @param node internal node at which the sub-tree starts
-     * @return child node just after the internal node
-     */
-    private BSPTree<Sphere1D> childAfter(BSPTree<Sphere1D> node) {
-        if (isDirect(node)) {
-            // smaller angles are on minus side, larger angles are on plus side
-            return node.getPlus();
-        } else {
-            // smaller angles are on plus side, larger angles are on minus side
-            return node.getMinus();
-        }
-    }
-
-    /** Check if an internal node has a direct limit angle.
-     * @param node internal node to check
-     * @return true if the limit angle is direct
-     */
-    private boolean isDirect(final BSPTree<Sphere1D> node) {
-        return ((LimitAngle) node.getCut().getHyperplane()).isDirect();
-    }
-
-    /** Get the limit angle of an internal node.
-     * @param node internal node to check
-     * @return limit angle
-     */
-    private double getAngle(final BSPTree<Sphere1D> node) {
-        return ((LimitAngle) node.getCut().getHyperplane()).getLocation().getAlpha();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public ArcsSet buildNew(final BSPTree<Sphere1D> tree) {
-        return new ArcsSet(tree, getTolerance());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void computeGeometricalProperties() {
-        if (getTree(false).getCut() == null) {
-            setBarycenter(S1Point.NaN);
-            setSize(((Boolean) getTree(false).getAttribute()) ? MathUtils.TWO_PI : 0);
-        } else {
-            double size = 0.0;
-            double sum  = 0.0;
-            for (final double[] a : this) {
-                final double length = a[1] - a[0];
-                size += length;
-                sum  += length * (a[0] + a[1]);
-            }
-            setSize(size);
-            if (Precision.equals(size, MathUtils.TWO_PI, 0)) {
-                setBarycenter(S1Point.NaN);
-            } else if (size >= Precision.SAFE_MIN) {
-                setBarycenter(new S1Point(sum / (2 * size)));
-            } else {
-                final LimitAngle limit = (LimitAngle) getTree(false).getCut().getHyperplane();
-                setBarycenter(limit.getLocation());
-            }
-        }
-    }
-
-    /** {@inheritDoc}
-     * @since 3.3
-     */
-    @Override
-    public BoundaryProjection<Sphere1D> projectToBoundary(final Point<Sphere1D> point) {
-
-        // get position of test point
-        final double alpha = ((S1Point) point).getAlpha();
-
-        boolean wrapFirst = false;
-        double first      = Double.NaN;
-        double previous   = Double.NaN;
-        for (final double[] a : this) {
-
-            if (Double.isNaN(first)) {
-                // remember the first angle in case we need it later
-                first = a[0];
-            }
-
-            if (!wrapFirst) {
-                if (alpha < a[0]) {
-                    // the test point lies between the previous and the current arcs
-                    // offset will be positive
-                    if (Double.isNaN(previous)) {
-                        // we need to wrap around the circle
-                        wrapFirst = true;
-                    } else {
-                        final double previousOffset = alpha - previous;
-                        final double currentOffset  = a[0] - alpha;
-                        if (previousOffset < currentOffset) {
-                            return new BoundaryProjection<>(point, new S1Point(previous), previousOffset);
-                        } else {
-                            return new BoundaryProjection<>(point, new S1Point(a[0]), currentOffset);
-                        }
-                    }
-                } else if (alpha <= a[1]) {
-                    // the test point lies within the current arc
-                    // offset will be negative
-                    final double offset0 = a[0] - alpha;
-                    final double offset1 = alpha - a[1];
-                    if (offset0 < offset1) {
-                        return new BoundaryProjection<>(point, new S1Point(a[1]), offset1);
-                    } else {
-                        return new BoundaryProjection<>(point, new S1Point(a[0]), offset0);
-                    }
-                }
-            }
-            previous = a[1];
-        }
-
-        if (Double.isNaN(previous)) {
-
-            // there are no points at all in the arcs set
-            return new BoundaryProjection<>(point, null, MathUtils.TWO_PI);
-
-        } else {
-
-            // the test point if before first arc and after last arc,
-            // somewhere around the 0/2 \pi crossing
-            if (wrapFirst) {
-                // the test point is between 0 and first
-                final double previousOffset = alpha - (previous - MathUtils.TWO_PI);
-                final double currentOffset  = first - alpha;
-                if (previousOffset < currentOffset) {
-                    return new BoundaryProjection<>(point, new S1Point(previous), previousOffset);
-                } else {
-                    return new BoundaryProjection<>(point, new S1Point(first), currentOffset);
-                }
-            } else {
-                // the test point is between last and 2\pi
-                final double previousOffset = alpha - previous;
-                final double currentOffset  = first + MathUtils.TWO_PI - alpha;
-                if (previousOffset < currentOffset) {
-                    return new BoundaryProjection<>(point, new S1Point(previous), previousOffset);
-                } else {
-                    return new BoundaryProjection<>(point, new S1Point(first), currentOffset);
-                }
-            }
-
-        }
-
-    }
-
-    /** Build an ordered list of arcs representing the instance.
-     * <p>This method builds this arcs set as an ordered list of
-     * {@link Arc Arc} elements. An empty tree will build an empty list
-     * while a tree representing the whole circle will build a one
-     * element list with bounds set to \( 0 and 2 \pi \).</p>
-     * @return a new ordered list containing {@link Arc Arc} elements
-     */
-    public List<Arc> asList() {
-        final List<Arc> list = new ArrayList<>();
-        for (final double[] a : this) {
-            list.add(new Arc(a[0], a[1], getTolerance()));
-        }
-        return list;
-    }
-
-    /** {@inheritDoc}
-     * <p>
-     * The iterator returns the limit angles pairs of sub-arcs in trigonometric order.
-     * </p>
-     * <p>
-     * The iterator does <em>not</em> support the optional {@code remove} operation.
-     * </p>
-     */
-    @Override
-    public Iterator<double[]> iterator() {
-        return new SubArcsIterator();
-    }
-
-    /** Local iterator for sub-arcs. */
-    private class SubArcsIterator implements Iterator<double[]> {
-
-        /** Start of the first arc. */
-        private final BSPTree<Sphere1D> firstStart;
-
-        /** Current node. */
-        private BSPTree<Sphere1D> current;
-
-        /** Sub-arc no yet returned. */
-        private double[] pending;
-
-        /** Simple constructor.
-         */
-        SubArcsIterator() {
-
-            firstStart = getFirstArcStart();
-            current    = firstStart;
-
-            if (firstStart == null) {
-                // all the leaf tree nodes share the same inside/outside status
-                if ((Boolean) getFirstLeaf(getTree(false)).getAttribute()) {
-                    // it is an inside node, it represents the full circle
-                    pending = new double[] {
-                        0, MathUtils.TWO_PI
-                    };
-                } else {
-                    pending = null;
-                }
-            } else {
-                selectPending();
-            }
-        }
-
-        /** Walk the tree to select the pending sub-arc.
-         */
-        private void selectPending() {
-
-            // look for the start of the arc
-            BSPTree<Sphere1D> start = current;
-            while (start != null && !isArcStart(start)) {
-                start = nextInternalNode(start);
-            }
-
-            if (start == null) {
-                // we have exhausted the iterator
-                current = null;
-                pending = null;
-                return;
-            }
-
-            // look for the end of the arc
-            BSPTree<Sphere1D> end = start;
-            while (end != null && !isArcEnd(end)) {
-                end = nextInternalNode(end);
-            }
-
-            if (end != null) {
-
-                // we have identified the arc
-                pending = new double[] {
-                    getAngle(start), getAngle(end)
-                };
-
-                // prepare search for next arc
-                current = end;
-
-            } else {
-
-                // the final arc wraps around 2\pi, its end is before the first start
-                end = firstStart;
-                while (end != null && !isArcEnd(end)) {
-                    end = previousInternalNode(end);
-                }
-                if (end == null) {
-                    // this should never happen
-                    throw new MathInternalError();
-                }
-
-                // we have identified the last arc
-                pending = new double[] {
-                    getAngle(start), getAngle(end) + MathUtils.TWO_PI
-                };
-
-                // there won't be any other arcs
-                current = null;
-
-            }
-
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public boolean hasNext() {
-            return pending != null;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public double[] next() {
-            if (pending == null) {
-                throw new NoSuchElementException();
-            }
-            final double[] next = pending;
-            selectPending();
-            return next;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-
-    }
-
-    /** Compute the relative position of the instance with respect
-     * to an arc.
-     * <p>
-     * The {@link Side#MINUS} side of the arc is the one covered by the arc.
-     * </p>
-     * @param arc arc to check instance against
-     * @return one of {@link Side#PLUS}, {@link Side#MINUS}, {@link Side#BOTH}
-     * or {@link Side#HYPER}
-     * @deprecated as of 3.6, replaced with {@link #split(Arc)}.{@link Split#getSide()}
-     */
-    @Deprecated
-    public Side side(final Arc arc) {
-        return split(arc).getSide();
-    }
-
-    /** Split the instance in two parts by an arc.
-     * @param arc splitting arc
-     * @return an object containing both the part of the instance
-     * on the plus side of the arc and the part of the
-     * instance on the minus side of the arc
-     */
-    public Split split(final Arc arc) {
-
-        final List<Double> minus = new ArrayList<>();
-        final List<Double>  plus = new ArrayList<>();
-
-        final double reference = FastMath.PI + arc.getInf();
-        final double arcLength = arc.getSup() - arc.getInf();
-
-        for (final double[] a : this) {
-            final double syncedStart = PlaneAngleRadians.normalize(a[0], reference) - arc.getInf();
-            final double arcOffset   = a[0] - syncedStart;
-            final double syncedEnd   = a[1] - arcOffset;
-            if (syncedStart < arcLength) {
-                // the start point a[0] is in the minus part of the arc
-                minus.add(a[0]);
-                if (syncedEnd > arcLength) {
-                    // the end point a[1] is past the end of the arc
-                    // so we leave the minus part and enter the plus part
-                    final double minusToPlus = arcLength + arcOffset;
-                    minus.add(minusToPlus);
-                    plus.add(minusToPlus);
-                    if (syncedEnd > MathUtils.TWO_PI) {
-                        // in fact the end point a[1] goes far enough that we
-                        // leave the plus part of the arc and enter the minus part again
-                        final double plusToMinus = MathUtils.TWO_PI + arcOffset;
-                        plus.add(plusToMinus);
-                        minus.add(plusToMinus);
-                        minus.add(a[1]);
-                    } else {
-                        // the end point a[1] is in the plus part of the arc
-                        plus.add(a[1]);
-                    }
-                } else {
-                    // the end point a[1] is in the minus part of the arc
-                    minus.add(a[1]);
-                }
-            } else {
-                // the start point a[0] is in the plus part of the arc
-                plus.add(a[0]);
-                if (syncedEnd > MathUtils.TWO_PI) {
-                    // the end point a[1] wraps around to the start of the arc
-                    // so we leave the plus part and enter the minus part
-                    final double plusToMinus = MathUtils.TWO_PI + arcOffset;
-                    plus.add(plusToMinus);
-                    minus.add(plusToMinus);
-                    if (syncedEnd > MathUtils.TWO_PI + arcLength) {
-                        // in fact the end point a[1] goes far enough that we
-                        // leave the minus part of the arc and enter the plus part again
-                        final double minusToPlus = MathUtils.TWO_PI + arcLength + arcOffset;
-                        minus.add(minusToPlus);
-                        plus.add(minusToPlus);
-                        plus.add(a[1]);
-                    } else {
-                        // the end point a[1] is in the minus part of the arc
-                        minus.add(a[1]);
-                    }
-                } else {
-                    // the end point a[1] is in the plus part of the arc
-                    plus.add(a[1]);
-                }
-            }
-        }
-
-        return new Split(createSplitPart(plus), createSplitPart(minus));
-
-    }
-
-    /** Add an arc limit to a BSP tree under construction.
-     * @param tree BSP tree under construction
-     * @param alpha arc limit
-     * @param isStart if true, the limit is the start of an arc
-     */
-    private void addArcLimit(final BSPTree<Sphere1D> tree, final double alpha, final boolean isStart) {
-
-        final LimitAngle limit = new LimitAngle(new S1Point(alpha), !isStart, getTolerance());
-        final BSPTree<Sphere1D> node = tree.getCell(limit.getLocation(), getTolerance());
-        if (node.getCut() != null) {
-            // this should never happen
-            throw new MathInternalError();
-        }
-
-        node.insertCut(limit);
-        node.setAttribute(null);
-        node.getPlus().setAttribute(Boolean.FALSE);
-        node.getMinus().setAttribute(Boolean.TRUE);
-
-    }
-
-    /** Create a split part.
-     * <p>
-     * As per construction, the list of limit angles is known to have
-     * an even number of entries, with start angles at even indices and
-     * end angles at odd indices.
-     * </p>
-     * @param limits limit angles of the split part
-     * @return split part (may be null)
-     */
-    private ArcsSet createSplitPart(final List<Double> limits) {
-        if (limits.isEmpty()) {
-            return null;
-        } else {
-
-            // collapse close limit angles
-            for (int i = 0; i < limits.size(); ++i) {
-                final int    j  = (i + 1) % limits.size();
-                final double lA = limits.get(i);
-                final double lB = PlaneAngleRadians.normalize(limits.get(j), lA);
-                if (FastMath.abs(lB - lA) <= getTolerance()) {
-                    // the two limits are too close to each other, we remove both of them
-                    if (j > 0) {
-                        // regular case, the two entries are consecutive ones
-                        limits.remove(j);
-                        limits.remove(i);
-                        i = i - 1;
-                    } else {
-                        // special case, i the last entry and j is the first entry
-                        // we have wrapped around list end
-                        final double lEnd   = limits.remove(limits.size() - 1);
-                        final double lStart = limits.remove(0);
-                        if (limits.isEmpty()) {
-                            // the ends were the only limits, is it a full circle or an empty circle?
-                            if (lEnd - lStart > FastMath.PI) {
-                                // it was full circle
-                                return new ArcsSet(new BSPTree<Sphere1D>(Boolean.TRUE), getTolerance());
-                            } else {
-                                // it was an empty circle
-                                return null;
-                            }
-                        } else {
-                            // we have removed the first interval start, so our list
-                            // currently starts with an interval end, which is wrong
-                            // we need to move this interval end to the end of the list
-                            limits.add(limits.remove(0) + MathUtils.TWO_PI);
-                        }
-                    }
-                }
-            }
-
-            // build the tree by adding all angular sectors
-            BSPTree<Sphere1D> tree = new BSPTree<>(Boolean.FALSE);
-            for (int i = 0; i < limits.size() - 1; i += 2) {
-                addArcLimit(tree, limits.get(i),     true);
-                addArcLimit(tree, limits.get(i + 1), false);
-            }
-
-            if (tree.getCut() == null) {
-                // we did not insert anything
-                return null;
-            }
-
-            return new ArcsSet(tree, getTolerance());
-
-        }
-    }
-
-    /** Class holding the results of the {@link #split split} method.
-     */
-    public static class Split {
-
-        /** Part of the arcs set on the plus side of the splitting arc. */
-        private final ArcsSet plus;
-
-        /** Part of the arcs set on the minus side of the splitting arc. */
-        private final ArcsSet minus;
-
-        /** Build a Split from its parts.
-         * @param plus part of the arcs set on the plus side of the
-         * splitting arc
-         * @param minus part of the arcs set on the minus side of the
-         * splitting arc
-         */
-        private Split(final ArcsSet plus, final ArcsSet minus) {
-            this.plus  = plus;
-            this.minus = minus;
-        }
-
-        /** Get the part of the arcs set on the plus side of the splitting arc.
-         * @return part of the arcs set on the plus side of the splitting arc
-         */
-        public ArcsSet getPlus() {
-            return plus;
-        }
-
-        /** Get the part of the arcs set on the minus side of the splitting arc.
-         * @return part of the arcs set on the minus side of the splitting arc
-         */
-        public ArcsSet getMinus() {
-            return minus;
-        }
-
-        /** Get the side of the split arc with respect to its splitter.
-         * @return {@link Side#PLUS} if only {@link #getPlus()} returns non-null,
-         * {@link Side#MINUS} if only {@link #getMinus()} returns non-null,
-         * {@link Side#BOTH} if both {@link #getPlus()} and {@link #getMinus()}
-         * return non-null or {@link Side#HYPER} if both {@link #getPlus()} and
-         * {@link #getMinus()} return null
-         * @since 3.6
-         */
-        public Side getSide() {
-            if (plus != null) {
-                if (minus != null) {
-                    return Side.BOTH;
-                } else {
-                    return Side.PLUS;
-                }
-            } else if (minus != null) {
-                return Side.MINUS;
-            } else {
-                return Side.HYPER;
-            }
-        }
-
-    }
-
-    /** Specialized exception for inconsistent BSP tree state inconsistency.
-     * <p>
-     * This exception is thrown at {@link ArcsSet} construction time when the
-     * {@link org.apache.commons.math4.geometry.partitioning.Region.Location inside/outside}
-     * state is not consistent at the 0, \(2 \pi \) crossing.
-     * </p>
-     */
-    public static class InconsistentStateAt2PiWrapping extends MathIllegalArgumentException {
-
-        /** Serializable UID. */
-        private static final long serialVersionUID = 20140107L;
-
-        /** Simple constructor.
-         */
-        public InconsistentStateAt2PiWrapping() {
-            super(LocalizedFormats.INCONSISTENT_STATE_AT_2_PI_WRAPPING);
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/LimitAngle.java b/src/main/java/org/apache/commons/math4/geometry/spherical/oned/LimitAngle.java
deleted file mode 100644
index 086931c..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/LimitAngle.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.spherical.oned;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.partitioning.Hyperplane;
-
-/** This class represents a 1D oriented hyperplane on the circle.
- * <p>An hyperplane on the 1-sphere is an angle with an orientation.</p>
- * <p>Instances of this class are guaranteed to be immutable.</p>
- * @since 3.3
- */
-public class LimitAngle implements Hyperplane<Sphere1D> {
-
-    /** Angle location. */
-    private final S1Point location;
-
-    /** Orientation. */
-    private final boolean direct;
-
-    /** Tolerance below which angles are considered identical. */
-    private final double tolerance;
-
-    /** Simple constructor.
-     * @param location location of the hyperplane
-     * @param direct if true, the plus side of the hyperplane is towards
-     * angles greater than {@code location}
-     * @param tolerance tolerance below which angles are considered identical
-     */
-    public LimitAngle(final S1Point location, final boolean direct, final double tolerance) {
-        this.location  = location;
-        this.direct    = direct;
-        this.tolerance = tolerance;
-    }
-
-    /** Copy the instance.
-     * <p>Since instances are immutable, this method directly returns
-     * the instance.</p>
-     * @return the instance itself
-     */
-    @Override
-    public LimitAngle copySelf() {
-        return this;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getOffset(final Point<Sphere1D> point) {
-        final double delta = ((S1Point) point).getAlpha() - location.getAlpha();
-        return direct ? delta : -delta;
-    }
-
-    /** Check if the hyperplane orientation is direct.
-     * @return true if the plus side of the hyperplane is towards
-     * angles greater than hyperplane location
-     */
-    public boolean isDirect() {
-        return direct;
-    }
-
-    /** Get the reverse of the instance.
-     * <p>Get a limit angle with reversed orientation with respect to the
-     * instance. A new object is built, the instance is untouched.</p>
-     * @return a new limit angle, with orientation opposite to the instance orientation
-     */
-    public LimitAngle getReverse() {
-        return new LimitAngle(location, !direct, tolerance);
-    }
-
-    /** Build a region covering the whole hyperplane.
-     * <p>Since this class represent zero dimension spaces which does
-     * not have lower dimension sub-spaces, this method returns a dummy
-     * implementation of a {@link
-     * org.apache.commons.math4.geometry.partitioning.SubHyperplane SubHyperplane}.
-     * This implementation is only used to allow the {@link
-     * org.apache.commons.math4.geometry.partitioning.SubHyperplane
-     * SubHyperplane} class implementation to work properly, it should
-     * <em>not</em> be used otherwise.</p>
-     * @return a dummy sub hyperplane
-     */
-    @Override
-    public SubLimitAngle wholeHyperplane() {
-        return new SubLimitAngle(this, null);
-    }
-
-    /** Build a region covering the whole space.
-     * @return a region containing the instance (really an {@link
-     * ArcsSet IntervalsSet} instance)
-     */
-    @Override
-    public ArcsSet wholeSpace() {
-        return new ArcsSet(tolerance);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean sameOrientationAs(final Hyperplane<Sphere1D> other) {
-        return !(direct ^ ((LimitAngle) other).direct);
-    }
-
-    /** Get the hyperplane location on the circle.
-     * @return the hyperplane location
-     */
-    public S1Point getLocation() {
-        return location;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Point<Sphere1D> project(Point<Sphere1D> point) {
-        return location;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getTolerance() {
-        return tolerance;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/S1Point.java b/src/main/java/org/apache/commons/math4/geometry/spherical/oned/S1Point.java
deleted file mode 100644
index e308bf4..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/S1Point.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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.spherical.oned;
-
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-
-/** This class represents a point on the 1-sphere.
- * <p>Instances of this class are guaranteed to be immutable.</p>
- * @since 3.3
- */
-public class S1Point implements Point<Sphere1D> {
-
-   // CHECKSTYLE: stop ConstantName
-    /** A vector with all coordinates set to NaN. */
-    public static final S1Point NaN = new S1Point(Double.NaN, Cartesian2D.NaN);
-    // CHECKSTYLE: resume ConstantName
-
-    /** Serializable UID. */
-    private static final long serialVersionUID = 20131218L;
-
-    /** Azimuthal angle \( \alpha \). */
-    private final double alpha;
-
-    /** Corresponding 2D normalized vector. */
-    private final Cartesian2D vector;
-
-    /** Simple constructor.
-     * Build a vector from its coordinates
-     * @param alpha azimuthal angle \( \alpha \)
-     * @see #getAlpha()
-     */
-    public S1Point(final double alpha) {
-        this(PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(alpha),
-             new Cartesian2D(FastMath.cos(alpha), FastMath.sin(alpha)));
-    }
-
-    /** Build a point from its internal components.
-     * @param alpha azimuthal angle \( \alpha \)
-     * @param vector corresponding vector
-     */
-    private S1Point(final double alpha, final Cartesian2D vector) {
-        this.alpha  = alpha;
-        this.vector = vector;
-    }
-
-    /** Get the azimuthal angle \( \alpha \).
-     * @return azimuthal angle \( \alpha \)
-     * @see #S1Point(double)
-     */
-    public double getAlpha() {
-        return alpha;
-    }
-
-    /** Get the corresponding normalized vector in the 2D euclidean space.
-     * @return normalized vector
-     */
-    public Cartesian2D getVector() {
-        return vector;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Space getSpace() {
-        return Sphere1D.getInstance();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isNaN() {
-        return Double.isNaN(alpha);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distance(final Point<Sphere1D> point) {
-        return distance(this, (S1Point) point);
-    }
-
-    /** Compute the distance (angular separation) between two points.
-     * @param p1 first vector
-     * @param p2 second vector
-     * @return the angular separation between p1 and p2
-     */
-    public static double distance(S1Point p1, S1Point p2) {
-        return Cartesian2D.angle(p1.vector, p2.vector);
-    }
-
-    /**
-     * Test for the equality of two points on the 2-sphere.
-     * <p>
-     * If all coordinates of two points are exactly the same, and none are
-     * <code>Double.NaN</code>, the two points are considered to be equal.
-     * </p>
-     * <p>
-     * <code>NaN</code> coordinates are considered to affect globally the vector
-     * and be equals to each other - i.e, if either (or all) coordinates of the
-     * 2D vector are equal to <code>Double.NaN</code>, the 2D vector is equal to
-     * {@link #NaN}.
-     * </p>
-     *
-     * @param other Object to test for equality to this
-     * @return true if two points on the 2-sphere objects are equal, false if
-     *         object is null, not an instance of S2Point, or
-     *         not equal to this S2Point instance
-     *
-     */
-    @Override
-    public boolean equals(Object other) {
-
-        if (this == other) {
-            return true;
-        }
-
-        if (other instanceof S1Point) {
-            final S1Point rhs = (S1Point) other;
-            if (rhs.isNaN()) {
-                return this.isNaN();
-            }
-
-            return alpha == rhs.alpha;
-        }
-
-        return false;
-
-    }
-
-    /**
-     * Get a hashCode for the 2D vector.
-     * <p>
-     * All NaN values have the same hash code.</p>
-     *
-     * @return a hash code value for this object
-     */
-    @Override
-    public int hashCode() {
-        if (isNaN()) {
-            return 542;
-        }
-        return 1759 * MathUtils.hash(alpha);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/Sphere1D.java b/src/main/java/org/apache/commons/math4/geometry/spherical/oned/Sphere1D.java
deleted file mode 100644
index 18f1a5d..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/Sphere1D.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.spherical.oned;
-
-import java.io.Serializable;
-
-import org.apache.commons.math4.exception.MathUnsupportedOperationException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.Space;
-
-/**
- * This class implements a one-dimensional sphere (i.e. a circle).
- * <p>
- * We use here the topologists definition of the 1-sphere (see
- * <a href="http://mathworld.wolfram.com/Sphere.html">Sphere</a> on
- * MathWorld), i.e. the 1-sphere is the one-dimensional closed curve
- * defined in 2D as x<sup>2</sup>+y<sup>2</sup>=1.
- * </p>
- * @since 3.3
- */
-public class Sphere1D implements Serializable, Space {
-
-    /** Serializable version identifier. */
-    private static final long serialVersionUID = 20131218L;
-
-    /** Private constructor for the singleton.
-     */
-    private Sphere1D() {
-    }
-
-    /** Get the unique instance.
-     * @return the unique instance
-     */
-    public static Sphere1D getInstance() {
-        return LazyHolder.INSTANCE;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int getDimension() {
-        return 1;
-    }
-
-    /** {@inheritDoc}
-     * <p>
-     * As the 1-dimension sphere does not have proper sub-spaces,
-     * this method always throws a {@link NoSubSpaceException}
-     * </p>
-     * @return nothing
-     * @throws NoSubSpaceException in all cases
-     */
-    @Override
-    public Space getSubSpace() throws NoSubSpaceException {
-        throw new NoSubSpaceException();
-    }
-
-    // CHECKSTYLE: stop HideUtilityClassConstructor
-    /** Holder for the instance.
-     * <p>We use here the Initialization On Demand Holder Idiom.</p>
-     */
-    private static class LazyHolder {
-        /** Cached field instance. */
-        private static final Sphere1D INSTANCE = new Sphere1D();
-    }
-    // CHECKSTYLE: resume HideUtilityClassConstructor
-
-    /** Handle deserialization of the singleton.
-     * @return the singleton instance
-     */
-    private Object readResolve() {
-        // return the singleton instance
-        return LazyHolder.INSTANCE;
-    }
-
-    /** Specialized exception for inexistent sub-space.
-     * <p>
-     * This exception is thrown when attempting to get the sub-space of a one-dimensional space
-     * </p>
-     */
-    public static class NoSubSpaceException extends MathUnsupportedOperationException {
-
-        /** Serializable UID. */
-        private static final long serialVersionUID = 20140225L;
-
-        /** Simple constructor.
-         */
-        public NoSubSpaceException() {
-            super(LocalizedFormats.NOT_SUPPORTED_IN_DIMENSION_N, 1);
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/SubLimitAngle.java b/src/main/java/org/apache/commons/math4/geometry/spherical/oned/SubLimitAngle.java
deleted file mode 100644
index 37a6de8..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/SubLimitAngle.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.spherical.oned;
-
-import org.apache.commons.math4.geometry.partitioning.AbstractSubHyperplane;
-import org.apache.commons.math4.geometry.partitioning.Hyperplane;
-import org.apache.commons.math4.geometry.partitioning.Region;
-
-/** This class represents sub-hyperplane for {@link LimitAngle}.
- * <p>Instances of this class are guaranteed to be immutable.</p>
- * @since 3.3
- */
-public class SubLimitAngle extends AbstractSubHyperplane<Sphere1D, Sphere1D> {
-
-    /** Simple constructor.
-     * @param hyperplane underlying hyperplane
-     * @param remainingRegion remaining region of the hyperplane
-     */
-    public SubLimitAngle(final Hyperplane<Sphere1D> hyperplane,
-                         final Region<Sphere1D> remainingRegion) {
-        super(hyperplane, remainingRegion);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getSize() {
-        return 0;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isEmpty() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected AbstractSubHyperplane<Sphere1D, Sphere1D> buildNew(final Hyperplane<Sphere1D> hyperplane,
-                                                                 final Region<Sphere1D> remainingRegion) {
-        return new SubLimitAngle(hyperplane, remainingRegion);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public SplitSubHyperplane<Sphere1D> split(final Hyperplane<Sphere1D> hyperplane) {
-        final double global = hyperplane.getOffset(((LimitAngle) getHyperplane()).getLocation());
-        return (global < -1.0e-10) ?
-                                    new SplitSubHyperplane<>(null, this) :
-                                    new SplitSubHyperplane<>(this, null);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/package-info.java b/src/main/java/org/apache/commons/math4/geometry/spherical/oned/package-info.java
deleted file mode 100644
index 0659050..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/oned/package-info.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- *
- * <p>
- * This package provides basic geometry components on the 1-sphere.
- * </p>
- * <p>
- * We use here the topologists definition of the 1-sphere (see
- * <a href="http://mathworld.wolfram.com/Sphere.html">Sphere</a> on
- * MathWorld), i.e. the 1-sphere is the one-dimensional closed curve
- * defined in 2D as x<sup>2</sup>+y<sup>2</sup>=1.
- * </p>
- *
- */
-package org.apache.commons.math4.geometry.spherical.oned;
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Circle.java b/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Circle.java
deleted file mode 100644
index 07b8c5f..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Circle.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.geometry.partitioning.Embedding;
-import org.apache.commons.math4.geometry.partitioning.Hyperplane;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-import org.apache.commons.math4.geometry.partitioning.Transform;
-import org.apache.commons.math4.geometry.spherical.oned.Arc;
-import org.apache.commons.math4.geometry.spherical.oned.ArcsSet;
-import org.apache.commons.math4.geometry.spherical.oned.S1Point;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.apache.commons.math4.util.FastMath;
-
-/** This class represents an oriented great circle on the 2-sphere.
-
- * <p>An oriented circle can be defined by a center point. The circle
- * is the set of points that are in the normal plan the center.</p>
-
- * <p>Since it is oriented the two spherical caps at its two sides are
- * unambiguously identified as a left cap and a right cap. This can be
- * used to identify the interior and the exterior in a simple way by
- * local properties only when part of a line is used to define part of
- * a spherical polygon boundary.</p>
-
- * @since 3.3
- */
-public class Circle implements Hyperplane<Sphere2D>, Embedding<Sphere2D, Sphere1D> {
-
-    /** Pole or circle center. */
-    private Cartesian3D pole;
-
-    /** First axis in the equator plane, origin of the phase angles. */
-    private Cartesian3D x;
-
-    /** Second axis in the equator plane, in quadrature with respect to x. */
-    private Cartesian3D y;
-
-    /** Tolerance below which close sub-arcs are merged together. */
-    private final double tolerance;
-
-    /** Build a great circle from its pole.
-     * <p>The circle is oriented in the trigonometric direction around pole.</p>
-     * @param pole circle pole
-     * @param tolerance tolerance below which close sub-arcs are merged together
-     */
-    public Circle(final Cartesian3D pole, final double tolerance) {
-        reset(pole);
-        this.tolerance = tolerance;
-    }
-
-    /** Build a great circle from two non-aligned points.
-     * <p>The circle is oriented from first to second point using the path smaller than \( \pi \).</p>
-     * @param first first point contained in the great circle
-     * @param second second point contained in the great circle
-     * @param tolerance tolerance below which close sub-arcs are merged together
-     */
-    public Circle(final S2Point first, final S2Point second, final double tolerance) {
-        reset(first.getVector().crossProduct(second.getVector()));
-        this.tolerance = tolerance;
-    }
-
-    /** Build a circle from its internal components.
-     * <p>The circle is oriented in the trigonometric direction around center.</p>
-     * @param pole circle pole
-     * @param x first axis in the equator plane
-     * @param y second axis in the equator plane
-     * @param tolerance tolerance below which close sub-arcs are merged together
-     */
-    private Circle(final Cartesian3D pole, final Cartesian3D x, final Cartesian3D y,
-                   final double tolerance) {
-        this.pole      = pole;
-        this.x         = x;
-        this.y         = y;
-        this.tolerance = tolerance;
-    }
-
-    /** Copy constructor.
-     * <p>The created instance is completely independent from the
-     * original instance, it is a deep copy.</p>
-     * @param circle circle to copy
-     */
-    public Circle(final Circle circle) {
-        this(circle.pole, circle.x, circle.y, circle.tolerance);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Circle copySelf() {
-        return new Circle(this);
-    }
-
-    /** Reset the instance as if built from a pole.
-     * <p>The circle is oriented in the trigonometric direction around pole.</p>
-     * @param newPole circle pole
-     */
-    public void reset(final Cartesian3D newPole) {
-        this.pole = newPole.normalize();
-        this.x    = newPole.orthogonal();
-        this.y    = Cartesian3D.crossProduct(newPole, x).normalize();
-    }
-
-    /** Revert the instance.
-     */
-    public void revertSelf() {
-        // x remains the same
-        y    = y.negate();
-        pole = pole.negate();
-    }
-
-    /** Get the reverse of the instance.
-     * <p>Get a circle with reversed orientation with respect to the
-     * instance. A new object is built, the instance is untouched.</p>
-     * @return a new circle, with orientation opposite to the instance orientation
-     */
-    public Circle getReverse() {
-        return new Circle(pole.negate(), x, y.negate(), tolerance);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Point<Sphere2D> project(Point<Sphere2D> point) {
-        return toSpace(toSubSpace(point));
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double getTolerance() {
-        return tolerance;
-    }
-
-    /** {@inheritDoc}
-     * @see #getPhase(Cartesian3D)
-     */
-    @Override
-    public S1Point toSubSpace(final Point<Sphere2D> point) {
-        return new S1Point(getPhase(((S2Point) point).getVector()));
-    }
-
-    /** Get the phase angle of a direction.
-     * <p>
-     * The direction may not belong to the circle as the
-     * phase is computed for the meridian plane between the circle
-     * pole and the direction.
-     * </p>
-     * @param direction direction for which phase is requested
-     * @return phase angle of the direction around the circle
-     * @see #toSubSpace(Point)
-     */
-    public double getPhase(final Cartesian3D direction) {
-        return FastMath.PI + FastMath.atan2(-direction.dotProduct(y), -direction.dotProduct(x));
-    }
-
-    /** {@inheritDoc}
-     * @see #getPointAt(double)
-     */
-    @Override
-    public S2Point toSpace(final Point<Sphere1D> point) {
-        return new S2Point(getPointAt(((S1Point) point).getAlpha()));
-    }
-
-    /** Get a circle point from its phase around the circle.
-     * @param alpha phase around the circle
-     * @return circle point on the sphere
-     * @see #toSpace(Point)
-     * @see #getXAxis()
-     * @see #getYAxis()
-     */
-    public Cartesian3D getPointAt(final double alpha) {
-        return new Cartesian3D(FastMath.cos(alpha), x, FastMath.sin(alpha), y);
-    }
-
-    /** Get the X axis of the circle.
-     * <p>
-     * This method returns the same value as {@link #getPointAt(double)
-     * getPointAt(0.0)} but it does not do any computation and always
-     * return the same instance.
-     * </p>
-     * @return an arbitrary x axis on the circle
-     * @see #getPointAt(double)
-     * @see #getYAxis()
-     * @see #getPole()
-     */
-    public Cartesian3D getXAxis() {
-        return x;
-    }
-
-    /** Get the Y axis of the circle.
-     * <p>
-     * This method returns the same value as {@link #getPointAt(double)
-     * getPointAt(0.5 * FastMath.PI)} but it does not do any computation and always
-     * return the same instance.
-     * </p>
-     * @return an arbitrary y axis point on the circle
-     * @see #getPointAt(double)
-     * @see #getXAxis()
-     * @see #getPole()
-     */
-    public Cartesian3D getYAxis() {
-        return y;
-    }
-
-    /** Get the pole of the circle.
-     * <p>
-     * As the circle is a great circle, the pole does <em>not</em>
-     * belong to it.
-     * </p>
-     * @return pole of the circle
-     * @see #getXAxis()
-     * @see #getYAxis()
-     */
-    public Cartesian3D getPole() {
-        return pole;
-    }
-
-    /** Get the arc of the instance that lies inside the other circle.
-     * @param other other circle
-     * @return arc of the instance that lies inside the other circle
-     */
-    public Arc getInsideArc(final Circle other) {
-        final double alpha  = getPhase(other.pole);
-        final double halfPi = 0.5 * FastMath.PI;
-        return new Arc(alpha - halfPi, alpha + halfPi, tolerance);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public SubCircle wholeHyperplane() {
-        return new SubCircle(this, new ArcsSet(tolerance));
-    }
-
-    /** Build a region covering the whole space.
-     * @return a region containing the instance (really a {@link
-     * SphericalPolygonsSet SphericalPolygonsSet} instance)
-     */
-    @Override
-    public SphericalPolygonsSet wholeSpace() {
-        return new SphericalPolygonsSet(tolerance);
-    }
-
-    /** {@inheritDoc}
-     * @see #getOffset(Cartesian3D)
-     */
-    @Override
-    public double getOffset(final Point<Sphere2D> point) {
-        return getOffset(((S2Point) point).getVector());
-    }
-
-    /** Get the offset (oriented distance) of a direction.
-     * <p>The offset is defined as the angular distance between the
-     * circle center and the direction minus the circle radius. It
-     * is therefore 0 on the circle, positive for directions outside of
-     * the cone delimited by the circle, and negative inside the cone.</p>
-     * @param direction direction to check
-     * @return offset of the direction
-     * @see #getOffset(Point)
-     */
-    public double getOffset(final Cartesian3D direction) {
-        return Cartesian3D.angle(pole, direction) - 0.5 * FastMath.PI;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean sameOrientationAs(final Hyperplane<Sphere2D> other) {
-        final Circle otherC = (Circle) other;
-        return Cartesian3D.dotProduct(pole, otherC.pole) >= 0.0;
-    }
-
-    /** Get a {@link org.apache.commons.math4.geometry.partitioning.Transform
-     * Transform} embedding a 3D rotation.
-     * @param rotation rotation to use
-     * @return a new transform that can be applied to either {@link
-     * Point Point}, {@link Circle Line} or {@link
-     * org.apache.commons.math4.geometry.partitioning.SubHyperplane
-     * SubHyperplane} instances
-     */
-    public static Transform<Sphere2D, Sphere1D> getTransform(final Rotation rotation) {
-        return new CircleTransform(rotation);
-    }
-
-    /** Class embedding a 3D rotation. */
-    private static class CircleTransform implements Transform<Sphere2D, Sphere1D> {
-
-        /** Underlying rotation. */
-        private final Rotation rotation;
-
-        /** Build a transform from a {@code Rotation}.
-         * @param rotation rotation to use
-         */
-        CircleTransform(final Rotation rotation) {
-            this.rotation = rotation;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public S2Point apply(final Point<Sphere2D> point) {
-            return new S2Point(rotation.applyTo(((S2Point) point).getVector()));
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Circle apply(final Hyperplane<Sphere2D> hyperplane) {
-            final Circle circle = (Circle) hyperplane;
-            return new Circle(rotation.applyTo(circle.pole),
-                              rotation.applyTo(circle.x),
-                              rotation.applyTo(circle.y),
-                              circle.tolerance);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public SubHyperplane<Sphere1D> apply(final SubHyperplane<Sphere1D> sub,
-                                             final Hyperplane<Sphere2D> original,
-                                             final Hyperplane<Sphere2D> transformed) {
-            // as the circle is rotated, the limit angles are rotated too
-            return sub;
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Edge.java b/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Edge.java
deleted file mode 100644
index c2139f7..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Edge.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import java.util.List;
-
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.geometry.spherical.oned.Arc;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-
-/** Spherical polygons boundary edge.
- * @see SphericalPolygonsSet#getBoundaryLoops()
- * @see Vertex
- * @since 3.3
- */
-public class Edge {
-
-    /** Start vertex. */
-    private final Vertex start;
-
-    /** End vertex. */
-    private Vertex end;
-
-    /** Length of the arc. */
-    private final double length;
-
-    /** Circle supporting the edge. */
-    private final Circle circle;
-
-    /** Build an edge not contained in any node yet.
-     * @param start start vertex
-     * @param end end vertex
-     * @param length length of the arc (it can be greater than \( \pi \))
-     * @param circle circle supporting the edge
-     */
-    Edge(final Vertex start, final Vertex end, final double length, final Circle circle) {
-
-        this.start  = start;
-        this.end    = end;
-        this.length = length;
-        this.circle = circle;
-
-        // connect the vertices back to the edge
-        start.setOutgoing(this);
-        end.setIncoming(this);
-
-    }
-
-    /** Get start vertex.
-     * @return start vertex
-     */
-    public Vertex getStart() {
-        return start;
-    }
-
-    /** Get end vertex.
-     * @return end vertex
-     */
-    public Vertex getEnd() {
-        return end;
-    }
-
-    /** Get the length of the arc.
-     * @return length of the arc (can be greater than \( \pi \))
-     */
-    public double getLength() {
-        return length;
-    }
-
-    /** Get the circle supporting this edge.
-     * @return circle supporting this edge
-     */
-    public Circle getCircle() {
-        return circle;
-    }
-
-    /** Get an intermediate point.
-     * <p>
-     * The angle along the edge should normally be between 0 and {@link #getLength()}
-     * in order to remain within edge limits. However, there are no checks on the
-     * value of the angle, so user can rebuild the full circle on which an edge is
-     * defined if they want.
-     * </p>
-     * @param alpha angle along the edge, counted from {@link #getStart()}
-     * @return an intermediate point
-     */
-    public Cartesian3D getPointAt(final double alpha) {
-        return circle.getPointAt(alpha + circle.getPhase(start.getLocation().getVector()));
-    }
-
-    /** Connect the instance with a following edge.
-     * @param next edge following the instance
-     */
-    void setNextEdge(final Edge next) {
-        end = next.getStart();
-        end.setIncoming(this);
-        end.bindWith(getCircle());
-    }
-
-    /** Split the edge.
-     * <p>
-     * Once split, this edge is not referenced anymore by the vertices,
-     * it is replaced by the two or three sub-edges and intermediate splitting
-     * vertices are introduced to connect these sub-edges together.
-     * </p>
-     * @param splitCircle circle splitting the edge in several parts
-     * @param outsideList list where to put parts that are outside of the split circle
-     * @param insideList list where to put parts that are inside the split circle
-     */
-    void split(final Circle splitCircle,
-                       final List<Edge> outsideList, final List<Edge> insideList) {
-
-        // get the inside arc, synchronizing its phase with the edge itself
-        final double edgeStart        = circle.getPhase(start.getLocation().getVector());
-        final Arc    arc              = circle.getInsideArc(splitCircle);
-        final double arcRelativeStart = PlaneAngleRadians.normalize(arc.getInf(), edgeStart + FastMath.PI) - edgeStart;
-        final double arcRelativeEnd   = arcRelativeStart + arc.getSize();
-        final double unwrappedEnd     = arcRelativeEnd - MathUtils.TWO_PI;
-
-        // build the sub-edges
-        final double tolerance = circle.getTolerance();
-        Vertex previousVertex = start;
-        if (unwrappedEnd >= length - tolerance) {
-
-            // the edge is entirely contained inside the circle
-            // we don't split anything
-            insideList.add(this);
-
-        } else {
-
-            // there are at least some parts of the edge that should be outside
-            // (even is they are later be filtered out as being too small)
-            double alreadyManagedLength = 0;
-            if (unwrappedEnd >= 0) {
-                // the start of the edge is inside the circle
-                previousVertex = addSubEdge(previousVertex,
-                                            new Vertex(new S2Point(circle.getPointAt(edgeStart + unwrappedEnd))),
-                                            unwrappedEnd, insideList, splitCircle);
-                alreadyManagedLength = unwrappedEnd;
-            }
-
-            if (arcRelativeStart >= length - tolerance) {
-                // the edge ends while still outside of the circle
-                if (unwrappedEnd >= 0) {
-                    previousVertex = addSubEdge(previousVertex, end,
-                                                length - alreadyManagedLength, outsideList, splitCircle);
-                } else {
-                    // the edge is entirely outside of the circle
-                    // we don't split anything
-                    outsideList.add(this);
-                }
-            } else {
-                // the edge is long enough to enter inside the circle
-                previousVertex = addSubEdge(previousVertex,
-                                            new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeStart))),
-                                            arcRelativeStart - alreadyManagedLength, outsideList, splitCircle);
-                alreadyManagedLength = arcRelativeStart;
-
-                if (arcRelativeEnd >= length - tolerance) {
-                    // the edge ends while still inside of the circle
-                    previousVertex = addSubEdge(previousVertex, end,
-                                                length - alreadyManagedLength, insideList, splitCircle);
-                } else {
-                    // the edge is long enough to exit outside of the circle
-                    previousVertex = addSubEdge(previousVertex,
-                                                new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeStart))),
-                                                arcRelativeStart - alreadyManagedLength, insideList, splitCircle);
-                    alreadyManagedLength = arcRelativeStart;
-                    previousVertex = addSubEdge(previousVertex, end,
-                                                length - alreadyManagedLength, outsideList, splitCircle);
-                }
-            }
-
-        }
-
-    }
-
-    /** Add a sub-edge to a list if long enough.
-     * <p>
-     * If the length of the sub-edge to add is smaller than the {@link Circle#getTolerance()}
-     * tolerance of the support circle, it will be ignored.
-     * </p>
-     * @param subStart start of the sub-edge
-     * @param subEnd end of the sub-edge
-     * @param subLength length of the sub-edge
-     * @param splitCircle circle splitting the edge in several parts
-     * @param list list where to put the sub-edge
-     * @return end vertex of the edge ({@code subEnd} if the edge was long enough and really
-     * added, {@code subStart} if the edge was too small and therefore ignored)
-     */
-    private Vertex addSubEdge(final Vertex subStart, final Vertex subEnd, final double subLength,
-                              final List<Edge> list, final Circle splitCircle) {
-
-        if (subLength <= circle.getTolerance()) {
-            // the edge is too short, we ignore it
-            return subStart;
-        }
-
-        // really add the edge
-        subEnd.bindWith(splitCircle);
-        final Edge edge = new Edge(subStart, subEnd, subLength, circle);
-        list.add(edge);
-        return subEnd;
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/EdgesBuilder.java b/src/main/java/org/apache/commons/math4/geometry/spherical/twod/EdgesBuilder.java
deleted file mode 100644
index 0c5d40f..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/EdgesBuilder.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import java.util.ArrayList;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.math4.exception.MathIllegalStateException;
-import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-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.spherical.oned.Arc;
-import org.apache.commons.math4.geometry.spherical.oned.ArcsSet;
-import org.apache.commons.math4.geometry.spherical.oned.S1Point;
-
-/** Visitor building edges.
- * @since 3.3
- */
-class EdgesBuilder implements BSPTreeVisitor<Sphere2D> {
-
-    /** Root of the tree. */
-    private final BSPTree<Sphere2D> root;
-
-    /** Tolerance below which points are consider to be identical. */
-    private final double tolerance;
-
-    /** Built edges and their associated nodes. */
-    private final Map<Edge, BSPTree<Sphere2D>> edgeToNode;
-
-    /** Reversed map. */
-    private final Map<BSPTree<Sphere2D>, List<Edge>> nodeToEdgesList;
-
-    /** Simple constructor.
-     * @param root tree root
-     * @param tolerance below which points are consider to be identical
-     */
-    EdgesBuilder(final BSPTree<Sphere2D> root, final double tolerance) {
-        this.root            = root;
-        this.tolerance       = tolerance;
-        this.edgeToNode      = new IdentityHashMap<>();
-        this.nodeToEdgesList = new IdentityHashMap<>();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Order visitOrder(final BSPTree<Sphere2D> node) {
-        return Order.MINUS_SUB_PLUS;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void visitInternalNode(final BSPTree<Sphere2D> node) {
-        nodeToEdgesList.put(node, new ArrayList<Edge>());
-        @SuppressWarnings("unchecked")
-        final BoundaryAttribute<Sphere2D> attribute = (BoundaryAttribute<Sphere2D>) node.getAttribute();
-        if (attribute.getPlusOutside() != null) {
-            addContribution((SubCircle) attribute.getPlusOutside(), false, node);
-        }
-        if (attribute.getPlusInside() != null) {
-            addContribution((SubCircle) attribute.getPlusInside(), true, node);
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void visitLeafNode(final BSPTree<Sphere2D> node) {
-    }
-
-    /** Add the contribution of a boundary edge.
-     * @param sub boundary facet
-     * @param reversed if true, the facet has the inside on its plus side
-     * @param node node to which the edge belongs
-     */
-    private void addContribution(final SubCircle sub, final boolean reversed,
-                                 final BSPTree<Sphere2D> node) {
-        final Circle circle  = (Circle) sub.getHyperplane();
-        final List<Arc> arcs = ((ArcsSet) sub.getRemainingRegion()).asList();
-        for (final Arc a : arcs) {
-            final Vertex start = new Vertex((S2Point) circle.toSpace(new S1Point(a.getInf())));
-            final Vertex end   = new Vertex((S2Point) circle.toSpace(new S1Point(a.getSup())));
-            start.bindWith(circle);
-            end.bindWith(circle);
-            final Edge edge;
-            if (reversed) {
-                edge = new Edge(end, start, a.getSize(), circle.getReverse());
-            } else {
-                edge = new Edge(start, end, a.getSize(), circle);
-            }
-            edgeToNode.put(edge, node);
-            nodeToEdgesList.get(node).add(edge);
-        }
-    }
-
-    /** Get the edge that should naturally follow another one.
-     * @param previous edge to be continued
-     * @return other edge, starting where the previous one ends (they
-     * have not been connected yet)
-     * @exception MathIllegalStateException if there is not a single other edge
-     */
-    private Edge getFollowingEdge(final Edge previous)
-        throws MathIllegalStateException {
-
-        // get the candidate nodes
-        final S2Point point = previous.getEnd().getLocation();
-        final List<BSPTree<Sphere2D>> candidates = root.getCloseCuts(point, tolerance);
-
-        // the following edge we are looking for must start from one of the candidates nodes
-        double closest = tolerance;
-        Edge following = null;
-        for (final BSPTree<Sphere2D> node : candidates) {
-            for (final Edge edge : nodeToEdgesList.get(node)) {
-                if (edge != previous && edge.getStart().getIncoming() == null) {
-                    final Cartesian3D edgeStart = edge.getStart().getLocation().getVector();
-                    final double gap         = Cartesian3D.angle(point.getVector(), edgeStart);
-                    if (gap <= closest) {
-                        closest   = gap;
-                        following = edge;
-                    }
-                }
-            }
-        }
-
-        if (following == null) {
-            final Cartesian3D previousStart = previous.getStart().getLocation().getVector();
-            if (Cartesian3D.angle(point.getVector(), previousStart) <= tolerance) {
-                // the edge connects back to itself
-                return previous;
-            }
-
-            // this should never happen
-            throw new MathIllegalStateException(LocalizedFormats.OUTLINE_BOUNDARY_LOOP_OPEN);
-
-        }
-
-        return following;
-
-    }
-
-    /** Get the boundary edges.
-     * @return boundary edges
-     * @exception MathIllegalStateException if there is not a single other edge
-     */
-    public List<Edge> getEdges() throws MathIllegalStateException {
-
-        // connect the edges
-        for (final Edge previous : edgeToNode.keySet()) {
-            previous.setNextEdge(getFollowingEdge(previous));
-        }
-
-        return new ArrayList<>(edgeToNode.keySet());
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/PropertiesComputer.java b/src/main/java/org/apache/commons/math4/geometry/spherical/twod/PropertiesComputer.java
deleted file mode 100644
index d6a4f27..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/PropertiesComputer.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.math4.exception.MathInternalError;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.geometry.partitioning.BSPTree;
-import org.apache.commons.math4.geometry.partitioning.BSPTreeVisitor;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-
-/** Visitor computing geometrical properties.
- * @since 3.3
- */
-class PropertiesComputer implements BSPTreeVisitor<Sphere2D> {
-
-    /** Tolerance below which points are consider to be identical. */
-    private final double tolerance;
-
-    /** Summed area. */
-    private double summedArea;
-
-    /** Summed barycenter. */
-    private Cartesian3D summedBarycenter;
-
-    /** List of points strictly inside convex cells. */
-    private final List<Cartesian3D> convexCellsInsidePoints;
-
-    /** Simple constructor.
-     * @param tolerance below which points are consider to be identical
-     */
-    PropertiesComputer(final double tolerance) {
-        this.tolerance              = tolerance;
-        this.summedArea             = 0;
-        this.summedBarycenter       = Cartesian3D.ZERO;
-        this.convexCellsInsidePoints = new ArrayList<>();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Order visitOrder(final BSPTree<Sphere2D> node) {
-        return Order.MINUS_SUB_PLUS;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void visitInternalNode(final BSPTree<Sphere2D> node) {
-        // nothing to do here
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void visitLeafNode(final BSPTree<Sphere2D> node) {
-        if ((Boolean) node.getAttribute()) {
-
-            // transform this inside leaf cell into a simple convex polygon
-            final SphericalPolygonsSet convex =
-                    new SphericalPolygonsSet(node.pruneAroundConvexCell(Boolean.TRUE,
-                                                                        Boolean.FALSE,
-                                                                        null),
-                                             tolerance);
-
-            // extract the start of the single loop boundary of the convex cell
-            final List<Vertex> boundary = convex.getBoundaryLoops();
-            if (boundary.size() != 1) {
-                // this should never happen
-                throw new MathInternalError();
-            }
-
-            // compute the geometrical properties of the convex cell
-            final double area  = convexCellArea(boundary.get(0));
-            final Cartesian3D barycenter = convexCellBarycenter(boundary.get(0));
-            convexCellsInsidePoints.add(barycenter);
-
-            // add the cell contribution to the global properties
-            summedArea      += area;
-            summedBarycenter = new Cartesian3D(1, summedBarycenter, area, barycenter);
-
-        }
-    }
-
-    /** Compute convex cell area.
-     * @param start start vertex of the convex cell boundary
-     * @return area
-     */
-    private double convexCellArea(final Vertex start) {
-
-        int n = 0;
-        double sum = 0;
-
-        // loop around the cell
-        for (Edge e = start.getOutgoing(); n == 0 || e.getStart() != start; e = e.getEnd().getOutgoing()) {
-
-            // find path interior angle at vertex
-            final Cartesian3D previousPole = e.getCircle().getPole();
-            final Cartesian3D nextPole     = e.getEnd().getOutgoing().getCircle().getPole();
-            final Cartesian3D point        = e.getEnd().getLocation().getVector();
-            double alpha = FastMath.atan2(Cartesian3D.dotProduct(nextPole, Cartesian3D.crossProduct(point, previousPole)),
-                                          -Cartesian3D.dotProduct(nextPole, previousPole));
-            if (alpha < 0) {
-                alpha += MathUtils.TWO_PI;
-            }
-            sum += alpha;
-            n++;
-        }
-
-        // compute area using extended Girard theorem
-        // see Spherical Trigonometry: For the Use of Colleges and Schools by I. Todhunter
-        // article 99 in chapter VIII Area Of a Spherical Triangle. Spherical Excess.
-        // book available from project Gutenberg at http://www.gutenberg.org/ebooks/19770
-        return sum - (n - 2) * FastMath.PI;
-
-    }
-
-    /** Compute convex cell barycenter.
-     * @param start start vertex of the convex cell boundary
-     * @return barycenter
-     */
-    private Cartesian3D convexCellBarycenter(final Vertex start) {
-
-        int n = 0;
-        Cartesian3D sumB = Cartesian3D.ZERO;
-
-        // loop around the cell
-        for (Edge e = start.getOutgoing(); n == 0 || e.getStart() != start; e = e.getEnd().getOutgoing()) {
-            sumB = new Cartesian3D(1, sumB, e.getLength(), e.getCircle().getPole());
-            n++;
-        }
-
-        return sumB.normalize();
-
-    }
-
-    /** Get the area.
-     * @return area
-     */
-    public double getArea() {
-        return summedArea;
-    }
-
-    /** Get the barycenter.
-     * @return barycenter
-     */
-    public S2Point getBarycenter() {
-        if (summedBarycenter.getNormSq() == 0) {
-            return S2Point.NaN;
-        } else {
-            return new S2Point(summedBarycenter);
-        }
-    }
-
-    /** Get the points strictly inside convex cells.
-     * @return points strictly inside convex cells
-     */
-    public List<Cartesian3D> getConvexCellsInsidePoints() {
-        return convexCellsInsidePoints;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/S2Point.java b/src/main/java/org/apache/commons/math4/geometry/spherical/twod/S2Point.java
deleted file mode 100644
index 6931ac0..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/S2Point.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import org.apache.commons.math4.exception.MathArithmeticException;
-import org.apache.commons.math4.exception.OutOfRangeException;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-
-/** This class represents a point on the 2-sphere.
- * <p>
- * We use the mathematical convention to use the azimuthal angle \( \theta \)
- * in the x-y plane as the first coordinate, and the polar angle \( \varphi \)
- * as the second coordinate (see <a
- * href="http://mathworld.wolfram.com/SphericalCoordinates.html">Spherical
- * Coordinates</a> in MathWorld).
- * </p>
- * <p>Instances of this class are guaranteed to be immutable.</p>
- * @since 3.3
- */
-public class S2Point implements Point<Sphere2D> {
-
-    /** +I (coordinates: \( \theta = 0, \varphi = \pi/2 \)). */
-    public static final S2Point PLUS_I = new S2Point(0, 0.5 * FastMath.PI, Cartesian3D.PLUS_I);
-
-    /** +J (coordinates: \( \theta = \pi/2, \varphi = \pi/2 \))). */
-    public static final S2Point PLUS_J = new S2Point(0.5 * FastMath.PI, 0.5 * FastMath.PI, Cartesian3D.PLUS_J);
-
-    /** +K (coordinates: \( \theta = any angle, \varphi = 0 \)). */
-    public static final S2Point PLUS_K = new S2Point(0, 0, Cartesian3D.PLUS_K);
-
-    /** -I (coordinates: \( \theta = \pi, \varphi = \pi/2 \)). */
-    public static final S2Point MINUS_I = new S2Point(FastMath.PI, 0.5 * FastMath.PI, Cartesian3D.MINUS_I);
-
-    /** -J (coordinates: \( \theta = 3\pi/2, \varphi = \pi/2 \)). */
-    public static final S2Point MINUS_J = new S2Point(1.5 * FastMath.PI, 0.5 * FastMath.PI, Cartesian3D.MINUS_J);
-
-    /** -K (coordinates: \( \theta = any angle, \varphi = \pi \)). */
-    public static final S2Point MINUS_K = new S2Point(0, FastMath.PI, Cartesian3D.MINUS_K);
-
-    // CHECKSTYLE: stop ConstantName
-    /** A vector with all coordinates set to NaN. */
-    public static final S2Point NaN = new S2Point(Double.NaN, Double.NaN, Cartesian3D.NaN);
-    // CHECKSTYLE: resume ConstantName
-
-    /** Serializable UID. */
-    private static final long serialVersionUID = 20131218L;
-
-    /** Azimuthal angle \( \theta \) in the x-y plane. */
-    private final double theta;
-
-    /** Polar angle \( \varphi \). */
-    private final double phi;
-
-    /** Corresponding 3D normalized vector. */
-    private final Cartesian3D vector;
-
-    /** Simple constructor.
-     * Build a vector from its spherical coordinates
-     * @param theta azimuthal angle \( \theta \) in the x-y plane
-     * @param phi polar angle \( \varphi \)
-     * @see #getTheta()
-     * @see #getPhi()
-     * @exception OutOfRangeException if \( \varphi \) is not in the [\( 0; \pi \)] range
-     */
-    public S2Point(final double theta, final double phi)
-        throws OutOfRangeException {
-        this(theta, phi, vector(theta, phi));
-    }
-
-    /** Simple constructor.
-     * Build a vector from its underlying 3D vector
-     * @param vector 3D vector
-     * @exception MathArithmeticException if vector norm is zero
-     */
-    public S2Point(final Cartesian3D vector) throws MathArithmeticException {
-        this(FastMath.atan2(vector.getY(), vector.getX()), Cartesian3D.angle(Cartesian3D.PLUS_K, vector),
-             vector.normalize());
-    }
-
-    /** Build a point from its internal components.
-     * @param theta azimuthal angle \( \theta \) in the x-y plane
-     * @param phi polar angle \( \varphi \)
-     * @param vector corresponding vector
-     */
-    private S2Point(final double theta, final double phi, final Cartesian3D vector) {
-        this.theta  = theta;
-        this.phi    = phi;
-        this.vector = vector;
-    }
-
-    /** Build the normalized vector corresponding to spherical coordinates.
-     * @param theta azimuthal angle \( \theta \) in the x-y plane
-     * @param phi polar angle \( \varphi \)
-     * @return normalized vector
-     * @exception OutOfRangeException if \( \varphi \) is not in the [\( 0; \pi \)] range
-     */
-    private static Cartesian3D vector(final double theta, final double phi)
-       throws OutOfRangeException {
-
-        if (phi < 0 || phi > FastMath.PI) {
-            throw new OutOfRangeException(phi, 0, FastMath.PI);
-        }
-
-        final double cosTheta = FastMath.cos(theta);
-        final double sinTheta = FastMath.sin(theta);
-        final double cosPhi   = FastMath.cos(phi);
-        final double sinPhi   = FastMath.sin(phi);
-
-        return new Cartesian3D(cosTheta * sinPhi, sinTheta * sinPhi, cosPhi);
-
-    }
-
-    /** Get the azimuthal angle \( \theta \) in the x-y plane.
-     * @return azimuthal angle \( \theta \) in the x-y plane
-     * @see #S2Point(double, double)
-     */
-    public double getTheta() {
-        return theta;
-    }
-
-    /** Get the polar angle \( \varphi \).
-     * @return polar angle \( \varphi \)
-     * @see #S2Point(double, double)
-     */
-    public double getPhi() {
-        return phi;
-    }
-
-    /** Get the corresponding normalized vector in the 3D euclidean space.
-     * @return normalized vector
-     */
-    public Cartesian3D getVector() {
-        return vector;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Space getSpace() {
-        return Sphere2D.getInstance();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isNaN() {
-        return Double.isNaN(theta) || Double.isNaN(phi);
-    }
-
-    /** Get the opposite of the instance.
-     * @return a new vector which is opposite to the instance
-     */
-    public S2Point negate() {
-        return new S2Point(-theta, FastMath.PI - phi, vector.negate());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public double distance(final Point<Sphere2D> point) {
-        return distance(this, (S2Point) point);
-    }
-
-    /** Compute the distance (angular separation) between two points.
-     * @param p1 first vector
-     * @param p2 second vector
-     * @return the angular separation between p1 and p2
-     */
-    public static double distance(S2Point p1, S2Point p2) {
-        return Cartesian3D.angle(p1.vector, p2.vector);
-    }
-
-    /**
-     * Test for the equality of two points on the 2-sphere.
-     * <p>
-     * If all coordinates of two points are exactly the same, and none are
-     * <code>Double.NaN</code>, the two points are considered to be equal.
-     * </p>
-     * <p>
-     * <code>NaN</code> coordinates are considered to affect globally the vector
-     * and be equals to each other - i.e, if either (or all) coordinates of the
-     * 2D vector are equal to <code>Double.NaN</code>, the 2D vector is equal to
-     * {@link #NaN}.
-     * </p>
-     *
-     * @param other Object to test for equality to this
-     * @return true if two points on the 2-sphere objects are equal, false if
-     *         object is null, not an instance of S2Point, or
-     *         not equal to this S2Point instance
-     *
-     */
-    @Override
-    public boolean equals(Object other) {
-
-        if (this == other) {
-            return true;
-        }
-
-        if (other instanceof S2Point) {
-            final S2Point rhs = (S2Point) other;
-            if (rhs.isNaN()) {
-                return this.isNaN();
-            }
-
-            return (theta == rhs.theta) && (phi == rhs.phi);
-        }
-        return false;
-    }
-
-    /**
-     * Get a hashCode for the 2D vector.
-     * <p>
-     * All NaN values have the same hash code.</p>
-     *
-     * @return a hash code value for this object
-     */
-    @Override
-    public int hashCode() {
-        if (isNaN()) {
-            return 542;
-        }
-        return 134 * (37 * MathUtils.hash(theta) +  MathUtils.hash(phi));
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Sphere2D.java b/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Sphere2D.java
deleted file mode 100644
index 8ada69f..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Sphere2D.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import java.io.Serializable;
-
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-
-/**
- * This class implements a two-dimensional sphere (i.e. the regular sphere).
- * <p>
- * We use here the topologists definition of the 2-sphere (see
- * <a href="http://mathworld.wolfram.com/Sphere.html">Sphere</a> on
- * MathWorld), i.e. the 2-sphere is the two-dimensional surface
- * defined in 3D as x<sup>2</sup>+y<sup>2</sup>+z<sup>2</sup>=1.
- * </p>
- * @since 3.3
- */
-public class Sphere2D implements Serializable, Space {
-
-    /** Serializable version identifier. */
-    private static final long serialVersionUID = 20131218L;
-
-    /** Private constructor for the singleton.
-     */
-    private Sphere2D() {
-    }
-
-    /** Get the unique instance.
-     * @return the unique instance
-     */
-    public static Sphere2D getInstance() {
-        return LazyHolder.INSTANCE;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int getDimension() {
-        return 2;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Sphere1D getSubSpace() {
-        return Sphere1D.getInstance();
-    }
-
-    // CHECKSTYLE: stop HideUtilityClassConstructor
-    /** Holder for the instance.
-     * <p>We use here the Initialization On Demand Holder Idiom.</p>
-     */
-    private static class LazyHolder {
-        /** Cached field instance. */
-        private static final Sphere2D INSTANCE = new Sphere2D();
-    }
-    // CHECKSTYLE: resume HideUtilityClassConstructor
-
-    /** Handle deserialization of the singleton.
-     * @return the singleton instance
-     */
-    private Object readResolve() {
-        // return the singleton instance
-        return LazyHolder.INSTANCE;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/SphericalPolygonsSet.java b/src/main/java/org/apache/commons/math4/geometry/spherical/twod/SphericalPolygonsSet.java
deleted file mode 100644
index e6f94f2..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/SphericalPolygonsSet.java
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.commons.math4.exception.MathIllegalStateException;
-import org.apache.commons.math4.geometry.enclosing.EnclosingBall;
-import org.apache.commons.math4.geometry.enclosing.WelzlEncloser;
-import org.apache.commons.math4.geometry.euclidean.threed.Euclidean3D;
-import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
-import org.apache.commons.math4.geometry.euclidean.threed.RotationConvention;
-import org.apache.commons.math4.geometry.euclidean.threed.SphereGenerator;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.geometry.partitioning.AbstractRegion;
-import org.apache.commons.math4.geometry.partitioning.BSPTree;
-import org.apache.commons.math4.geometry.partitioning.BoundaryProjection;
-import org.apache.commons.math4.geometry.partitioning.RegionFactory;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-
-/** This class represents a region on the 2-sphere: a set of spherical polygons.
- * @since 3.3
- */
-public class SphericalPolygonsSet extends AbstractRegion<Sphere2D, Sphere1D> {
-
-    /** Boundary defined as an array of closed loops start vertices. */
-    private List<Vertex> loops;
-
-    /** Build a polygons set representing the whole real 2-sphere.
-     * @param tolerance below which points are consider to be identical
-     */
-    public SphericalPolygonsSet(final double tolerance) {
-        super(tolerance);
-    }
-
-    /** Build a polygons set representing a hemisphere.
-     * @param pole pole of the hemisphere (the pole is in the inside half)
-     * @param tolerance below which points are consider to be identical
-     */
-    public SphericalPolygonsSet(final Cartesian3D pole, final double tolerance) {
-        super(new BSPTree<>(new Circle(pole, tolerance).wholeHyperplane(),
-                                    new BSPTree<Sphere2D>(Boolean.FALSE),
-                                    new BSPTree<Sphere2D>(Boolean.TRUE),
-                                    null),
-              tolerance);
-    }
-
-    /** Build a polygons set representing a regular polygon.
-     * @param center center of the polygon (the center is in the inside half)
-     * @param meridian point defining the reference meridian for first polygon vertex
-     * @param outsideRadius distance of the vertices to the center
-     * @param n number of sides of the polygon
-     * @param tolerance below which points are consider to be identical
-     */
-    public SphericalPolygonsSet(final Cartesian3D center, final Cartesian3D meridian,
-                                final double outsideRadius, final int n,
-                                final double tolerance) {
-        this(tolerance, createRegularPolygonVertices(center, meridian, outsideRadius, n));
-    }
-
-    /** Build a polygons set from a BSP tree.
-     * <p>The leaf nodes of the BSP tree <em>must</em> have a
-     * {@code Boolean} attribute representing the inside status of
-     * the corresponding cell (true for inside cells, false for outside
-     * cells). In order to avoid building too many small objects, it is
-     * recommended to use the predefined constants
-     * {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
-     * @param tree inside/outside BSP tree representing the region
-     * @param tolerance below which points are consider to be identical
-     */
-    public SphericalPolygonsSet(final BSPTree<Sphere2D> tree, final double tolerance) {
-        super(tree, tolerance);
-    }
-
-    /** Build a polygons set from a Boundary REPresentation (B-rep).
-     * <p>The boundary is provided as a collection of {@link
-     * SubHyperplane sub-hyperplanes}. Each sub-hyperplane has the
-     * interior part of the region on its minus side and the exterior on
-     * its plus side.</p>
-     * <p>The boundary elements can be in any order, and can form
-     * several non-connected sets (like for example polygons with holes
-     * or a set of disjoint polygons considered as a whole). In
-     * fact, the elements do not even need to be connected together
-     * (their topological connections are not used here). However, if the
-     * boundary does not really separate an inside open from an outside
-     * open (open having here its topological meaning), then subsequent
-     * calls to the {@link
-     * org.apache.commons.math4.geometry.partitioning.Region#checkPoint(org.apache.commons.math4.geometry.Point)
-     * checkPoint} method will not be meaningful anymore.</p>
-     * <p>If the boundary is empty, the region will represent the whole
-     * space.</p>
-     * @param boundary collection of boundary elements, as a
-     * collection of {@link SubHyperplane SubHyperplane} objects
-     * @param tolerance below which points are consider to be identical
-     */
-    public SphericalPolygonsSet(final Collection<SubHyperplane<Sphere2D>> boundary, final double tolerance) {
-        super(boundary, tolerance);
-    }
-
-    /** Build a polygon from a simple list of vertices.
-     * <p>The boundary is provided as a list of points considering to
-     * represent the vertices of a simple loop. The interior part of the
-     * region is on the left side of this path and the exterior is on its
-     * right side.</p>
-     * <p>This constructor does not handle polygons with a boundary
-     * forming several disconnected paths (such as polygons with holes).</p>
-     * <p>For cases where this simple constructor applies, it is expected to
-     * be numerically more robust than the {@link #SphericalPolygonsSet(Collection,
-     * double) general constructor} using {@link SubHyperplane subhyperplanes}.</p>
-     * <p>If the list is empty, the region will represent the whole
-     * space.</p>
-     * <p>
-     * Polygons with thin pikes or dents are inherently difficult to handle because
-     * they involve circles with almost opposite directions at some vertices. Polygons
-     * whose vertices come from some physical measurement with noise are also
-     * difficult because an edge that should be straight may be broken in lots of
-     * different pieces with almost equal directions. In both cases, computing the
-     * circles intersections is not numerically robust due to the almost 0 or almost
-     * &pi; angle. Such cases need to carefully adjust the {@code hyperplaneThickness}
-     * parameter. A too small value would often lead to completely wrong polygons
-     * with large area wrongly identified as inside or outside. Large values are
-     * often much safer. As a rule of thumb, a value slightly below the size of the
-     * most accurate detail needed is a good value for the {@code hyperplaneThickness}
-     * parameter.
-     * </p>
-     * @param hyperplaneThickness tolerance below which points are considered to
-     * belong to the hyperplane (which is therefore more a slab)
-     * @param vertices vertices of the simple loop boundary
-     */
-    public SphericalPolygonsSet(final double hyperplaneThickness, final S2Point ... vertices) {
-        super(verticesToTree(hyperplaneThickness, vertices), hyperplaneThickness);
-    }
-
-    /** Build the vertices representing a regular polygon.
-     * @param center center of the polygon (the center is in the inside half)
-     * @param meridian point defining the reference meridian for first polygon vertex
-     * @param outsideRadius distance of the vertices to the center
-     * @param n number of sides of the polygon
-     * @return vertices array
-     */
-    private static S2Point[] createRegularPolygonVertices(final Cartesian3D center, final Cartesian3D meridian,
-                                                          final double outsideRadius, final int n) {
-        final S2Point[] array = new S2Point[n];
-        final Rotation r0 = new Rotation(Cartesian3D.crossProduct(center, meridian),
-                                         outsideRadius, RotationConvention.VECTOR_OPERATOR);
-        array[0] = new S2Point(r0.applyTo(center));
-
-        final Rotation r = new Rotation(center, MathUtils.TWO_PI / n, RotationConvention.VECTOR_OPERATOR);
-        for (int i = 1; i < n; ++i) {
-            array[i] = new S2Point(r.applyTo(array[i - 1].getVector()));
-        }
-
-        return array;
-    }
-
-    /** Build the BSP tree of a polygons set from a simple list of vertices.
-     * <p>The boundary is provided as a list of points considering to
-     * represent the vertices of a simple loop. The interior part of the
-     * region is on the left side of this path and the exterior is on its
-     * right side.</p>
-     * <p>This constructor does not handle polygons with a boundary
-     * forming several disconnected paths (such as polygons with holes).</p>
-     * <p>This constructor handles only polygons with edges strictly shorter
-     * than \( \pi \). If longer edges are needed, they need to be broken up
-     * in smaller sub-edges so this constraint holds.</p>
-     * <p>For cases where this simple constructor applies, it is expected to
-     * be numerically more robust than the {@link #PolygonsSet(Collection) general
-     * constructor} using {@link SubHyperplane subhyperplanes}.</p>
-     * @param hyperplaneThickness tolerance below which points are consider to
-     * belong to the hyperplane (which is therefore more a slab)
-     * @param vertices vertices of the simple loop boundary
-     * @return the BSP tree of the input vertices
-     */
-    private static BSPTree<Sphere2D> verticesToTree(final double hyperplaneThickness,
-                                                    final S2Point ... vertices) {
-
-        final int n = vertices.length;
-        if (n == 0) {
-            // the tree represents the whole space
-            return new BSPTree<>(Boolean.TRUE);
-        }
-
-        // build the vertices
-        final Vertex[] vArray = new Vertex[n];
-        for (int i = 0; i < n; ++i) {
-            vArray[i] = new Vertex(vertices[i]);
-        }
-
-        // build the edges
-        List<Edge> edges = new ArrayList<>(n);
-        Vertex end = vArray[n - 1];
-        for (int i = 0; i < n; ++i) {
-
-            // get the endpoints of the edge
-            final Vertex start = end;
-            end = vArray[i];
-
-            // get the circle supporting the edge, taking care not to recreate it
-            // if it was already created earlier due to another edge being aligned
-            // with the current one
-            Circle circle = start.sharedCircleWith(end);
-            if (circle == null) {
-                circle = new Circle(start.getLocation(), end.getLocation(), hyperplaneThickness);
-            }
-
-            // create the edge and store it
-            edges.add(new Edge(start, end,
-                               Cartesian3D.angle(start.getLocation().getVector(),
-                                              end.getLocation().getVector()),
-                               circle));
-
-            // check if another vertex also happens to be on this circle
-            for (final Vertex vertex : vArray) {
-                if (vertex != start && vertex != end &&
-                    FastMath.abs(circle.getOffset(vertex.getLocation())) <= hyperplaneThickness) {
-                    vertex.bindWith(circle);
-                }
-            }
-
-        }
-
-        // build the tree top-down
-        final BSPTree<Sphere2D> tree = new BSPTree<>();
-        insertEdges(hyperplaneThickness, tree, edges);
-
-        return tree;
-
-    }
-
-    /** Recursively build a tree by inserting cut sub-hyperplanes.
-     * @param hyperplaneThickness tolerance below which points are considered to
-     * belong to the hyperplane (which is therefore more a slab)
-     * @param node current tree node (it is a leaf node at the beginning
-     * of the call)
-     * @param edges list of edges to insert in the cell defined by this node
-     * (excluding edges not belonging to the cell defined by this node)
-     */
-    private static void insertEdges(final double hyperplaneThickness,
-                                    final BSPTree<Sphere2D> node,
-                                    final List<Edge> edges) {
-
-        // find an edge with an hyperplane that can be inserted in the node
-        int index = 0;
-        Edge inserted = null;
-        while (inserted == null && index < edges.size()) {
-            inserted = edges.get(index++);
-            if (!node.insertCut(inserted.getCircle())) {
-                inserted = null;
-            }
-        }
-
-        if (inserted == null) {
-            // no suitable edge was found, the node remains a leaf node
-            // we need to set its inside/outside boolean indicator
-            final BSPTree<Sphere2D> parent = node.getParent();
-            if (parent == null || node == parent.getMinus()) {
-                node.setAttribute(Boolean.TRUE);
-            } else {
-                node.setAttribute(Boolean.FALSE);
-            }
-            return;
-        }
-
-        // we have split the node by inserting an edge as a cut sub-hyperplane
-        // distribute the remaining edges in the two sub-trees
-        final List<Edge> outsideList = new ArrayList<>();
-        final List<Edge> insideList  = new ArrayList<>();
-        for (final Edge edge : edges) {
-            if (edge != inserted) {
-                edge.split(inserted.getCircle(), outsideList, insideList);
-            }
-        }
-
-        // recurse through lower levels
-        if (!outsideList.isEmpty()) {
-            insertEdges(hyperplaneThickness, node.getPlus(), outsideList);
-        } else {
-            node.getPlus().setAttribute(Boolean.FALSE);
-        }
-        if (!insideList.isEmpty()) {
-            insertEdges(hyperplaneThickness, node.getMinus(),  insideList);
-        } else {
-            node.getMinus().setAttribute(Boolean.TRUE);
-        }
-
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public SphericalPolygonsSet buildNew(final BSPTree<Sphere2D> tree) {
-        return new SphericalPolygonsSet(tree, getTolerance());
-    }
-
-    /** {@inheritDoc}
-     * @exception MathIllegalStateException if the tolerance setting does not allow to build
-     * a clean non-ambiguous boundary
-     */
-    @Override
-    protected void computeGeometricalProperties() throws MathIllegalStateException {
-
-        final BSPTree<Sphere2D> tree = getTree(true);
-
-        if (tree.getCut() == null) {
-
-            // the instance has a single cell without any boundaries
-
-            if (tree.getCut() == null && (Boolean) tree.getAttribute()) {
-                // the instance covers the whole space
-                setSize(4 * FastMath.PI);
-                setBarycenter(new S2Point(0, 0));
-            } else {
-                setSize(0);
-                setBarycenter(S2Point.NaN);
-            }
-
-        } else {
-
-            // the instance has a boundary
-            final PropertiesComputer pc = new PropertiesComputer(getTolerance());
-            tree.visit(pc);
-            setSize(pc.getArea());
-            setBarycenter(pc.getBarycenter());
-
-        }
-
-    }
-
-    /** Get the boundary loops of the polygon.
-     * <p>The polygon boundary can be represented as a list of closed loops,
-     * each loop being given by exactly one of its vertices. From each loop
-     * start vertex, one can follow the loop by finding the outgoing edge,
-     * then the end vertex, then the next outgoing edge ... until the start
-     * vertex of the loop (exactly the same instance) is found again once
-     * the full loop has been visited.</p>
-     * <p>If the polygon has no boundary at all, a zero length loop
-     * array will be returned.</p>
-     * <p>If the polygon is a simple one-piece polygon, then the returned
-     * array will contain a single vertex.
-     * </p>
-     * <p>All edges in the various loops have the inside of the region on
-     * their left side (i.e. toward their pole) and the outside on their
-     * right side (i.e. away from their pole) when moving in the underlying
-     * circle direction. This means that the closed loops obey the direct
-     * trigonometric orientation.</p>
-     * @return boundary of the polygon, organized as an unmodifiable list of loops start vertices.
-     * @exception MathIllegalStateException if the tolerance setting does not allow to build
-     * a clean non-ambiguous boundary
-     * @see Vertex
-     * @see Edge
-     */
-    public List<Vertex> getBoundaryLoops() throws MathIllegalStateException {
-
-        if (loops == null) {
-            if (getTree(false).getCut() == null) {
-                loops = Collections.emptyList();
-            } else {
-
-                // sort the arcs according to their start point
-                final BSPTree<Sphere2D> root = getTree(true);
-                final EdgesBuilder visitor = new EdgesBuilder(root, getTolerance());
-                root.visit(visitor);
-                final List<Edge> edges = visitor.getEdges();
-
-
-                // convert the list of all edges into a list of start vertices
-                loops = new ArrayList<>();
-                while (!edges.isEmpty()) {
-
-                    // this is an edge belonging to a new loop, store it
-                    Edge edge = edges.get(0);
-                    final Vertex startVertex = edge.getStart();
-                    loops.add(startVertex);
-
-                    // remove all remaining edges in the same loop
-                    do {
-
-                        // remove one edge
-                        for (final Iterator<Edge> iterator = edges.iterator(); iterator.hasNext();) {
-                            if (iterator.next() == edge) {
-                                iterator.remove();
-                                break;
-                            }
-                        }
-
-                        // go to next edge following the boundary loop
-                        edge = edge.getEnd().getOutgoing();
-
-                    } while (edge.getStart() != startVertex);
-
-                }
-
-            }
-        }
-
-        return Collections.unmodifiableList(loops);
-
-    }
-
-    /** Get a spherical cap enclosing the polygon.
-     * <p>
-     * This method is intended as a first test to quickly identify points
-     * that are guaranteed to be outside of the region, hence performing a full
-     * {@link #checkPoint(org.apache.commons.math4.geometry.Point) checkPoint}
-     * only if the point status remains undecided after the quick check. It is
-     * is therefore mostly useful to speed up computation for small polygons with
-     * complex shapes (say a country boundary on Earth), as the spherical cap will
-     * be small and hence will reliably identify a large part of the sphere as outside,
-     * whereas the full check can be more computing intensive. A typical use case is
-     * therefore:
-     * </p>
-     * <pre>{@code
-     *   // compute region, plus an enclosing spherical cap
-     *   SphericalPolygonsSet complexShape = ...;
-     *   EnclosingBall<Sphere2D, S2Point> cap = complexShape.getEnclosingCap();
-     *
-     *   // check lots of points
-     *   for (Cartesian3D p : points) {
-     *
-     *     final Location l;
-     *     if (cap.contains(p)) {
-     *       // we cannot be sure where the point is
-     *       // we need to perform the full computation
-     *       l = complexShape.checkPoint(v);
-     *     } else {
-     *       // no need to do further computation,
-     *       // we already know the point is outside
-     *       l = Location.OUTSIDE;
-     *     }
-     *
-     *     // use l ...
-     *
-     *   }
-     * }</pre>
-     * <p>
-     * In the special cases of empty or whole sphere polygons, special
-     * spherical caps are returned, with angular radius set to negative
-     * or positive infinity so the {@link
-     * EnclosingBall#contains(org.apache.commons.math4.geometry.Point) ball.contains(point)}
-     * method return always false or true.
-     * </p>
-     * <p>
-     * This method is <em>not</em> guaranteed to return the smallest enclosing cap.
-     * </p>
-     * @return a spherical cap enclosing the polygon
-     */
-    public EnclosingBall<Sphere2D, S2Point> getEnclosingCap() {
-
-        // handle special cases first
-        if (isEmpty()) {
-            return new EnclosingBall<>(S2Point.PLUS_K, Double.NEGATIVE_INFINITY);
-        }
-        if (isFull()) {
-            return new EnclosingBall<>(S2Point.PLUS_K, Double.POSITIVE_INFINITY);
-        }
-
-        // as the polygons is neither empty nor full, it has some boundaries and cut hyperplanes
-        final BSPTree<Sphere2D> root = getTree(false);
-        if (isEmpty(root.getMinus()) && isFull(root.getPlus())) {
-            // the polygon covers an hemisphere, and its boundary is one 2π long edge
-            final Circle circle = (Circle) root.getCut().getHyperplane();
-            return new EnclosingBall<>(new S2Point(circle.getPole()).negate(),
-                                                        0.5 * FastMath.PI);
-        }
-        if (isFull(root.getMinus()) && isEmpty(root.getPlus())) {
-            // the polygon covers an hemisphere, and its boundary is one 2π long edge
-            final Circle circle = (Circle) root.getCut().getHyperplane();
-            return new EnclosingBall<>(new S2Point(circle.getPole()),
-                                                        0.5 * FastMath.PI);
-        }
-
-        // gather some inside points, to be used by the encloser
-        final List<Cartesian3D> points = getInsidePoints();
-
-        // extract points from the boundary loops, to be used by the encloser as well
-        final List<Vertex> boundary = getBoundaryLoops();
-        for (final Vertex loopStart : boundary) {
-            int count = 0;
-            for (Vertex v = loopStart; count == 0 || v != loopStart; v = v.getOutgoing().getEnd()) {
-                ++count;
-                points.add(v.getLocation().getVector());
-            }
-        }
-
-        // find the smallest enclosing 3D sphere
-        final SphereGenerator generator = new SphereGenerator();
-        final WelzlEncloser<Euclidean3D, Cartesian3D> encloser =
-                new WelzlEncloser<>(getTolerance(), generator);
-        EnclosingBall<Euclidean3D, Cartesian3D> enclosing3D = encloser.enclose(points);
-        final Cartesian3D[] support3D = enclosing3D.getSupport();
-
-        // convert to 3D sphere to spherical cap
-        final double r = enclosing3D.getRadius();
-        final double h = enclosing3D.getCenter().getNorm();
-        if (h < getTolerance()) {
-            // the 3D sphere is centered on the unit sphere and covers it
-            // fall back to a crude approximation, based only on outside convex cells
-            EnclosingBall<Sphere2D, S2Point> enclosingS2 =
-                    new EnclosingBall<>(S2Point.PLUS_K, Double.POSITIVE_INFINITY);
-            for (Cartesian3D outsidePoint : getOutsidePoints()) {
-                final S2Point outsideS2 = new S2Point(outsidePoint);
-                final BoundaryProjection<Sphere2D> projection = projectToBoundary(outsideS2);
-                if (FastMath.PI - projection.getOffset() < enclosingS2.getRadius()) {
-                    enclosingS2 = new EnclosingBall<>(outsideS2.negate(),
-                                                                       FastMath.PI - projection.getOffset(),
-                                                                       (S2Point) projection.getProjected());
-                }
-            }
-            return enclosingS2;
-        }
-        final S2Point[] support = new S2Point[support3D.length];
-        for (int i = 0; i < support3D.length; ++i) {
-            support[i] = new S2Point(support3D[i]);
-        }
-
-        final EnclosingBall<Sphere2D, S2Point> enclosingS2 =
-                new EnclosingBall<>(new S2Point(enclosing3D.getCenter()),
-                                                     FastMath.acos((1 + h * h - r * r) / (2 * h)),
-                                                     support);
-
-        return enclosingS2;
-
-    }
-
-    /** Gather some inside points.
-     * @return list of points known to be strictly in all inside convex cells
-     */
-    private List<Cartesian3D> getInsidePoints() {
-        final PropertiesComputer pc = new PropertiesComputer(getTolerance());
-        getTree(true).visit(pc);
-        return pc.getConvexCellsInsidePoints();
-    }
-
-    /** Gather some outside points.
-     * @return list of points known to be strictly in all outside convex cells
-     */
-    private List<Cartesian3D> getOutsidePoints() {
-        final SphericalPolygonsSet complement =
-                (SphericalPolygonsSet) new RegionFactory<Sphere2D>().getComplement(this);
-        final PropertiesComputer pc = new PropertiesComputer(getTolerance());
-        complement.getTree(true).visit(pc);
-        return pc.getConvexCellsInsidePoints();
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/SubCircle.java b/src/main/java/org/apache/commons/math4/geometry/spherical/twod/SubCircle.java
deleted file mode 100644
index 8710e47..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/SubCircle.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.geometry.partitioning.AbstractSubHyperplane;
-import org.apache.commons.math4.geometry.partitioning.Hyperplane;
-import org.apache.commons.math4.geometry.partitioning.Region;
-import org.apache.commons.math4.geometry.spherical.oned.Arc;
-import org.apache.commons.math4.geometry.spherical.oned.ArcsSet;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.apache.commons.math4.util.FastMath;
-
-/** This class represents a sub-hyperplane for {@link Circle}.
- * @since 3.3
- */
-public class SubCircle extends AbstractSubHyperplane<Sphere2D, Sphere1D> {
-
-    /** Simple constructor.
-     * @param hyperplane underlying hyperplane
-     * @param remainingRegion remaining region of the hyperplane
-     */
-    public SubCircle(final Hyperplane<Sphere2D> hyperplane,
-                     final Region<Sphere1D> remainingRegion) {
-        super(hyperplane, remainingRegion);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected AbstractSubHyperplane<Sphere2D, Sphere1D> buildNew(final Hyperplane<Sphere2D> hyperplane,
-                                                                 final Region<Sphere1D> remainingRegion) {
-        return new SubCircle(hyperplane, remainingRegion);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public SplitSubHyperplane<Sphere2D> split(final Hyperplane<Sphere2D> hyperplane) {
-
-        final Circle thisCircle   = (Circle) getHyperplane();
-        final Circle otherCircle  = (Circle) hyperplane;
-        final double angle = Cartesian3D.angle(thisCircle.getPole(), otherCircle.getPole());
-
-        if (angle < thisCircle.getTolerance() || angle > FastMath.PI - thisCircle.getTolerance()) {
-            // the two circles are aligned or opposite
-            return new SplitSubHyperplane<>(null, null);
-        } else {
-            // the two circles intersect each other
-            final Arc    arc          = thisCircle.getInsideArc(otherCircle);
-            final ArcsSet.Split split = ((ArcsSet) getRemainingRegion()).split(arc);
-            final ArcsSet plus        = split.getPlus();
-            final ArcsSet minus       = split.getMinus();
-            return new SplitSubHyperplane<>(plus  == null ? null : new SubCircle(thisCircle.copySelf(), plus),
-                                                    minus == null ? null : new SubCircle(thisCircle.copySelf(), minus));
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Vertex.java b/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Vertex.java
deleted file mode 100644
index a8b1db2..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/Vertex.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** Spherical polygons boundary vertex.
- * @see SphericalPolygonsSet#getBoundaryLoops()
- * @see Edge
- * @since 3.3
- */
-public class Vertex {
-
-    /** Vertex location. */
-    private final S2Point location;
-
-    /** Incoming edge. */
-    private Edge incoming;
-
-    /** Outgoing edge. */
-    private Edge outgoing;
-
-    /** Circles bound with this vertex. */
-    private final List<Circle> circles;
-
-    /** Build a non-processed vertex not owned by any node yet.
-     * @param location vertex location
-     */
-    Vertex(final S2Point location) {
-        this.location = location;
-        this.incoming = null;
-        this.outgoing = null;
-        this.circles  = new ArrayList<>();
-    }
-
-    /** Get Vertex location.
-     * @return vertex location
-     */
-    public S2Point getLocation() {
-        return location;
-    }
-
-    /** Bind a circle considered to contain this vertex.
-     * @param circle circle to bind with this vertex
-     */
-    void bindWith(final Circle circle) {
-        circles.add(circle);
-    }
-
-    /** Get the common circle bound with both the instance and another vertex, if any.
-     * <p>
-     * When two vertices are both bound to the same circle, this means they are
-     * already handled by node associated with this circle, so there is no need
-     * to create a cut hyperplane for them.
-     * </p>
-     * @param vertex other vertex to check instance against
-     * @return circle bound with both the instance and another vertex, or null if the
-     * two vertices do not share a circle yet
-     */
-    Circle sharedCircleWith(final Vertex vertex) {
-        for (final Circle circle1 : circles) {
-            for (final Circle circle2 : vertex.circles) {
-                if (circle1 == circle2) {
-                    return circle1;
-                }
-            }
-        }
-        return null;
-    }
-
-    /** Set incoming edge.
-     * <p>
-     * The circle supporting the incoming edge is automatically bound
-     * with the instance.
-     * </p>
-     * @param incoming incoming edge
-     */
-    void setIncoming(final Edge incoming) {
-        this.incoming = incoming;
-        bindWith(incoming.getCircle());
-    }
-
-    /** Get incoming edge.
-     * @return incoming edge
-     */
-    public Edge getIncoming() {
-        return incoming;
-    }
-
-    /** Set outgoing edge.
-     * <p>
-     * The circle supporting the outgoing edge is automatically bound
-     * with the instance.
-     * </p>
-     * @param outgoing outgoing edge
-     */
-    void setOutgoing(final Edge outgoing) {
-        this.outgoing = outgoing;
-        bindWith(outgoing.getCircle());
-    }
-
-    /** Get outgoing edge.
-     * @return outgoing edge
-     */
-    public Edge getOutgoing() {
-        return outgoing;
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/package-info.java b/src/main/java/org/apache/commons/math4/geometry/spherical/twod/package-info.java
deleted file mode 100644
index 4614d85..0000000
--- a/src/main/java/org/apache/commons/math4/geometry/spherical/twod/package-info.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- *
- * <p>
- * This package provides basic geometry components on the 2-sphere.
- * </p>
- * <p>
- * We use here the topologists definition of the 2-sphere (see
- * <a href="http://mathworld.wolfram.com/Sphere.html">Sphere</a> on
- * MathWorld), i.e. the 2-sphere is the two-dimensional surface
- * defined in 3D as x<sup>2</sup>+y<sup>2</sup>+z<sup>2</sup>=1.
- * </p>
- *
- */
-package org.apache.commons.math4.geometry.spherical.twod;
diff --git a/src/test/java/org/apache/commons/math4/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java b/src/test/java/org/apache/commons/math4/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java
index 0d5884e..ccc24ae 100644
--- a/src/test/java/org/apache/commons/math4/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java
+++ b/src/test/java/org/apache/commons/math4/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.commons.math4.fitting.leastsquares;
 
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.math4.analysis.MultivariateMatrixFunction;
 import org.apache.commons.math4.analysis.MultivariateVectorFunction;
 import org.apache.commons.math4.exception.ConvergenceException;
@@ -26,7 +27,6 @@
 import org.apache.commons.math4.fitting.leastsquares.MultivariateJacobianFunction;
 import org.apache.commons.math4.fitting.leastsquares.LeastSquaresOptimizer.Optimum;
 import org.apache.commons.math4.fitting.leastsquares.LeastSquaresProblem.Evaluation;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
 import org.apache.commons.math4.linear.Array2DRowRealMatrix;
 import org.apache.commons.math4.linear.ArrayRealVector;
 import org.apache.commons.math4.linear.BlockRealMatrix;
@@ -412,7 +412,7 @@
         double rms = optimum.getRMS();
         Assert.assertEquals(1.768262623567235, FastMath.sqrt(circle.getN()) * rms, TOl);
 
-        Cartesian2D center = new Cartesian2D(optimum.getPoint().getEntry(0), optimum.getPoint().getEntry(1));
+        Vector2D center = Vector2D.of(optimum.getPoint().getEntry(0), optimum.getPoint().getEntry(1));
         Assert.assertEquals(69.96016176931406, circle.getRadius(center), 1e-6);
         Assert.assertEquals(96.07590211815305, center.getX(), 1e-6);
         Assert.assertEquals(48.13516790438953, center.getY(), 1e-6);
@@ -455,7 +455,7 @@
 
         Optimum optimum = optimizer.optimize(builder(circle).weight(new DiagonalMatrix(weights)).start(start).build());
 
-        Cartesian2D center = new Cartesian2D(optimum.getPoint().getEntry(0), optimum.getPoint().getEntry(1));
+        Vector2D center = Vector2D.of(optimum.getPoint().getEntry(0), optimum.getPoint().getEntry(1));
         Assert.assertTrue(optimum.getEvaluations() < 25);
         Assert.assertEquals(0.043, optimum.getRMS(), 1e-3);
         Assert.assertEquals(0.292235, circle.getRadius(center), 1e-6);
diff --git a/src/test/java/org/apache/commons/math4/fitting/leastsquares/CircleVectorial.java b/src/test/java/org/apache/commons/math4/fitting/leastsquares/CircleVectorial.java
index db9cef8..fc6ea99 100644
--- a/src/test/java/org/apache/commons/math4/fitting/leastsquares/CircleVectorial.java
+++ b/src/test/java/org/apache/commons/math4/fitting/leastsquares/CircleVectorial.java
@@ -18,31 +18,31 @@
 
 import java.util.ArrayList;
 
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.math4.analysis.MultivariateMatrixFunction;
 import org.apache.commons.math4.analysis.MultivariateVectorFunction;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
 
 /**
  * Class used in the tests.
  */
 class CircleVectorial {
-    private ArrayList<Cartesian2D> points;
+    private ArrayList<Vector2D> points;
 
     public CircleVectorial() {
         points  = new ArrayList<>();
     }
 
     public void addPoint(double px, double py) {
-        points.add(new Cartesian2D(px, py));
+        points.add(Vector2D.of(px, py));
     }
 
     public int getN() {
         return points.size();
     }
 
-    public double getRadius(Cartesian2D center) {
+    public double getRadius(Vector2D center) {
         double r = 0;
-        for (Cartesian2D point : points) {
+        for (Vector2D point : points) {
             r += point.distance(center);
         }
         return r / points.size();
@@ -52,7 +52,7 @@
         return new MultivariateVectorFunction() {
             @Override
             public double[] value(double[] params) {
-                Cartesian2D center = new Cartesian2D(params[0], params[1]);
+                Vector2D center = Vector2D.of(params[0], params[1]);
                 double radius = getRadius(center);
                 double[] residuals = new double[points.size()];
                 for (int i = 0; i < residuals.length; i++) {
@@ -69,11 +69,11 @@
             @Override
             public double[][] value(double[] params) {
                 final int n = points.size();
-                final Cartesian2D center = new Cartesian2D(params[0], params[1]);
+                final Vector2D center = Vector2D.of(params[0], params[1]);
 
                 double dRdX = 0;
                 double dRdY = 0;
-                for (Cartesian2D pk : points) {
+                for (Vector2D pk : points) {
                     double dk = pk.distance(center);
                     dRdX += (center.getX() - pk.getX()) / dk;
                     dRdY += (center.getY() - pk.getY()) / dk;
@@ -84,7 +84,7 @@
                 // Jacobian of the radius residuals.
                 double[][] jacobian = new double[n][2];
                 for (int i = 0; i < n; i++) {
-                    final Cartesian2D pi = points.get(i);
+                    final Vector2D pi = points.get(i);
                     final double di = pi.distance(center);
                     jacobian[i][0] = (center.getX() - pi.getX()) / di - dRdX;
                     jacobian[i][1] = (center.getY() - pi.getY()) / di - dRdY;
diff --git a/src/test/java/org/apache/commons/math4/fitting/leastsquares/GaussNewtonOptimizerWithSVDTest.java b/src/test/java/org/apache/commons/math4/fitting/leastsquares/GaussNewtonOptimizerWithSVDTest.java
index 626a3a0..8583f1a 100644
--- a/src/test/java/org/apache/commons/math4/fitting/leastsquares/GaussNewtonOptimizerWithSVDTest.java
+++ b/src/test/java/org/apache/commons/math4/fitting/leastsquares/GaussNewtonOptimizerWithSVDTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.commons.math4.fitting.leastsquares;
 
+import org.apache.commons.geometry.euclidean.threed.Plane;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.math4.exception.ConvergenceException;
 import org.apache.commons.math4.exception.TooManyEvaluationsException;
 import org.apache.commons.math4.fitting.leastsquares.GaussNewtonOptimizer;
@@ -24,8 +27,6 @@
 import org.apache.commons.math4.fitting.leastsquares.LeastSquaresProblem;
 import org.apache.commons.math4.fitting.leastsquares.GaussNewtonOptimizer.Decomposition;
 import org.apache.commons.math4.fitting.leastsquares.LeastSquaresOptimizer.Optimum;
-import org.apache.commons.math4.geometry.euclidean.threed.Plane;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
 import org.apache.commons.math4.optim.SimpleVectorValueChecker;
 import org.apache.commons.math4.util.FastMath;
 import org.junit.Assert;
@@ -140,8 +141,9 @@
 
         Optimum optimum = optimizer.optimize(problem.getBuilder().build());
 
-        Plane span = new Plane(Cartesian3D.ZERO, new Cartesian3D(1, 2, -3), new Cartesian3D(2, 1, 0), TOl);
-        double expected = FastMath.abs(span.getOffset(new Cartesian3D(1, 1, 1)));
+        Plane span = Plane.fromPoints(Vector3D.ZERO, Vector3D.of(1, 2, -3), Vector3D.of(2, 1, 0),
+                                      new EpsilonDoublePrecisionContext(TOl));
+        double expected = FastMath.abs(span.offset(Vector3D.of(1, 1, 1)));
         double actual = optimum.getResiduals().getNorm();
 
         //verify
diff --git a/src/test/java/org/apache/commons/math4/fitting/leastsquares/LevenbergMarquardtOptimizerTest.java b/src/test/java/org/apache/commons/math4/fitting/leastsquares/LevenbergMarquardtOptimizerTest.java
index 0be1116..76aa0d2 100644
--- a/src/test/java/org/apache/commons/math4/fitting/leastsquares/LevenbergMarquardtOptimizerTest.java
+++ b/src/test/java/org/apache/commons/math4/fitting/leastsquares/LevenbergMarquardtOptimizerTest.java
@@ -17,11 +17,11 @@
 
 package org.apache.commons.math4.fitting.leastsquares;
 
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.math4.exception.DimensionMismatchException;
 import org.apache.commons.math4.exception.TooManyEvaluationsException;
 import org.apache.commons.math4.fitting.leastsquares.LeastSquaresOptimizer.Optimum;
 import org.apache.commons.math4.fitting.leastsquares.LeastSquaresProblem.Evaluation;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
 import org.apache.commons.math4.linear.DiagonalMatrix;
 import org.apache.commons.math4.linear.RealMatrix;
 import org.apache.commons.math4.linear.RealVector;
@@ -106,7 +106,7 @@
         checkEstimate(
                 circle, 0.1, 10, 1.0e-14, 1.0e-16, 1.0e-10, false);
         checkEstimate(
-                circle, 0.1, 10, 1.0e-15, 1.0e-17, 1.0e-10, true);
+                circle, 0.1, 10, 1.0e-15, 1.0e-17, 1.0e-10, false);
         checkEstimate(
                 circle, 0.1,  5, 1.0e-15, 1.0e-16, 1.0e-10, true);
         circle.addPoint(300, -300);
@@ -260,7 +260,7 @@
         final CircleProblem circle = new CircleProblem(xSigma, ySigma);
 
         final int numPoints = 10;
-        for (Cartesian2D p : factory.generate(numPoints)) {
+        for (Vector2D p : factory.generate(numPoints)) {
             circle.addPoint(p.getX(), p.getY());
         }
 
@@ -297,7 +297,7 @@
         final CircleProblem circle = new CircleProblem(xSigma, ySigma);
 
         final int numPoints = 10;
-        for (Cartesian2D p : factory.generate(numPoints)) {
+        for (Vector2D p : factory.generate(numPoints)) {
             circle.addPoint(p.getX(), p.getY());
         }
 
diff --git a/src/test/java/org/apache/commons/math4/fitting/leastsquares/RandomCirclePointGenerator.java b/src/test/java/org/apache/commons/math4/fitting/leastsquares/RandomCirclePointGenerator.java
index c991629..2e09b54 100644
--- a/src/test/java/org/apache/commons/math4/fitting/leastsquares/RandomCirclePointGenerator.java
+++ b/src/test/java/org/apache/commons/math4/fitting/leastsquares/RandomCirclePointGenerator.java
@@ -16,10 +16,10 @@
  */
 package org.apache.commons.math4.fitting.leastsquares;
 
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.statistics.distribution.NormalDistribution;
 import org.apache.commons.statistics.distribution.ContinuousDistribution;
 import org.apache.commons.statistics.distribution.UniformContinuousDistribution;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
 import org.apache.commons.rng.UniformRandomProvider;
 import org.apache.commons.rng.simple.RandomSource;
 import org.apache.commons.math4.util.FastMath;
@@ -65,8 +65,8 @@
      * @param n Number of points to create.
      * @return the cloud of {@code n} points.
      */
-    public Cartesian2D[] generate(int n) {
-        final Cartesian2D[] cloud = new Cartesian2D[n];
+    public Vector2D[] generate(int n) {
+        final Vector2D[] cloud = new Vector2D[n];
         for (int i = 0; i < n; i++) {
             cloud[i] = create();
         }
@@ -78,11 +78,11 @@
      *
      * @return a point.
      */
-    private Cartesian2D create() {
+    private Vector2D create() {
         final double t = tP.sample();
         final double pX = cX.sample() + radius * FastMath.cos(t);
         final double pY = cY.sample() + radius * FastMath.sin(t);
 
-        return new Cartesian2D(pX, pY);
+        return Vector2D.of(pX, pY);
     }
 }
diff --git a/src/test/java/org/apache/commons/math4/geometry/GeometryTestUtils.java b/src/test/java/org/apache/commons/math4/geometry/GeometryTestUtils.java
deleted file mode 100644
index edb34e8..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/GeometryTestUtils.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * 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 java.util.Objects;
-
-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);
-    }
-
-    /** Asserts that the given value is positive infinity.
-     * @param value
-     */
-    public static void assertPositiveInfinity(double value) {
-        String msg = "Expected value to be positive infinity but was " + value;
-        Assert.assertTrue(msg, Double.isInfinite(value));
-        Assert.assertTrue(msg, value > 0);
-    }
-
-    /** Asserts that the given value is negative infinity..
-     * @param value
-     */
-    public static void assertNegativeInfinity(double value) {
-        String msg = "Expected value to be negative infinity but was " + value;
-        Assert.assertTrue(msg, Double.isInfinite(value));
-        Assert.assertTrue(msg, value < 0);
-    }
-
-    /** 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(nodeIdString(node) + " | ");
-        }
-
-        /** Returns a short string identifier for the given node.
-         * @param node
-         * @return
-         */
-        protected String nodeIdString(BSPTree<S> node) {
-            String str = Objects.toString(node);
-            int idx = str.lastIndexOf('.');
-            if (idx > -1) {
-                return str.substring(idx + 1, str.length());
-            }
-            return str;
-        }
-
-        /** 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("]");
-        }
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/enclosing/WelzlEncloser2DTest.java b/src/test/java/org/apache/commons/math4/geometry/enclosing/WelzlEncloser2DTest.java
deleted file mode 100644
index bde0468..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/enclosing/WelzlEncloser2DTest.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * 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.enclosing;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.commons.math4.geometry.enclosing.EnclosingBall;
-import org.apache.commons.math4.geometry.enclosing.WelzlEncloser;
-import org.apache.commons.math4.geometry.euclidean.twod.DiskGenerator;
-import org.apache.commons.math4.geometry.euclidean.twod.Euclidean2D;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.rng.UniformRandomProvider;
-import org.apache.commons.rng.simple.RandomSource;
-import org.junit.Assert;
-import org.junit.Test;
-
-
-public class WelzlEncloser2DTest {
-
-    @Test
-    public void testNullList() {
-        DiskGenerator generator = new DiskGenerator();
-        WelzlEncloser<Euclidean2D, Cartesian2D> encloser =
-                new WelzlEncloser<>(1.0e-10, generator);
-        EnclosingBall<Euclidean2D, Cartesian2D> ball = encloser.enclose(null);
-        Assert.assertTrue(ball.getRadius() < 0);
-    }
-
-    @Test
-    public void testNoPoints() {
-        DiskGenerator generator = new DiskGenerator();
-        WelzlEncloser<Euclidean2D, Cartesian2D> encloser =
-                new WelzlEncloser<>(1.0e-10, generator);
-        EnclosingBall<Euclidean2D, Cartesian2D> ball = encloser.enclose(new ArrayList<Cartesian2D>());
-        Assert.assertTrue(ball.getRadius() < 0);
-    }
-
-    @Test
-    public void testRegularPoints() {
-        List<Cartesian2D> list = buildList(22, 26, 30, 38, 64, 28,  8, 54, 11, 15);
-        checkDisk(list, Arrays.asList(list.get(2), list.get(3), list.get(4)));
-    }
-
-    @Test
-    public void testSolutionOnDiameter() {
-        List<Cartesian2D> list = buildList(22, 26, 30, 38, 64, 28,  8, 54);
-        checkDisk(list, Arrays.asList(list.get(2), list.get(3)));
-    }
-
-    @Test
-    public void testReducingBall1() {
-        List<Cartesian2D> list = buildList(0.05380958511396061, 0.57332359658700000,
-                                        0.99348810731127870, 0.02056421361521466,
-                                        0.01203950647796437, 0.99779675042261860,
-                                        0.00810189987706078, 0.00589246003827815,
-                                        0.00465180821202149, 0.99219972923046940);
-        checkDisk(list, Arrays.asList(list.get(1), list.get(3), list.get(4)));
-    }
-
-    @Test
-    public void testReducingBall2() {
-        List<Cartesian2D> list = buildList(0.016930586154703, 0.333955448537779,
-                                        0.987189104892331, 0.969778855274507,
-                                        0.983696889599935, 0.012904580013266,
-                                        0.013114499572905, 0.034740156356895);
-        checkDisk(list, Arrays.asList(list.get(1), list.get(2), list.get(3)));
-    }
-
-    @Test
-    public void testLargeSamples() {
-        UniformRandomProvider random = RandomSource.create(RandomSource.WELL_1024_A, 0xa2a63cad12c01fb2l);
-        for (int k = 0; k < 100; ++k) {
-            int nbPoints = random.nextInt(10000);
-            List<Cartesian2D> points = new ArrayList<>();
-            for (int i = 0; i < nbPoints; ++i) {
-                double x = random.nextDouble();
-                double y = random.nextDouble();
-                points.add(new Cartesian2D(x, y));
-            }
-            checkDisk(points);
-        }
-    }
-
-    private List<Cartesian2D> buildList(final double ... coordinates) {
-        List<Cartesian2D> list = new ArrayList<>(coordinates.length / 2);
-        for (int i = 0; i < coordinates.length; i += 2) {
-            list.add(new Cartesian2D(coordinates[i], coordinates[i + 1]));
-        }
-        return list;
-    }
-
-    private void checkDisk(List<Cartesian2D> points, List<Cartesian2D> refSupport) {
-
-        EnclosingBall<Euclidean2D, Cartesian2D> disk = checkDisk(points);
-
-        // compare computed disk with expected disk
-        DiskGenerator generator = new DiskGenerator();
-        EnclosingBall<Euclidean2D, Cartesian2D> expected = generator.ballOnSupport(refSupport);
-        Assert.assertEquals(refSupport.size(), disk.getSupportSize());
-        Assert.assertEquals(expected.getRadius(),        disk.getRadius(),        1.0e-10);
-        Assert.assertEquals(expected.getCenter().getX(), disk.getCenter().getX(), 1.0e-10);
-        Assert.assertEquals(expected.getCenter().getY(), disk.getCenter().getY(), 1.0e-10);
-
-        for (Cartesian2D s : disk.getSupport()) {
-            boolean found = false;
-            for (Cartesian2D rs : refSupport) {
-                if (s == rs) {
-                    found = true;
-                }
-            }
-            Assert.assertTrue(found);
-        }
-
-        // check removing any point of the support disk fails to enclose the point
-        for (int i = 0; i < disk.getSupportSize(); ++i) {
-            List<Cartesian2D> reducedSupport = new ArrayList<>();
-            int count = 0;
-            for (Cartesian2D s : disk.getSupport()) {
-                if (count++ != i) {
-                    reducedSupport.add(s);
-                }
-            }
-            EnclosingBall<Euclidean2D, Cartesian2D> reducedDisk = generator.ballOnSupport(reducedSupport);
-            boolean foundOutside = false;
-            for (int j = 0; j < points.size() && !foundOutside; ++j) {
-                if (!reducedDisk.contains(points.get(j), 1.0e-10)) {
-                    foundOutside = true;
-                }
-            }
-            Assert.assertTrue(foundOutside);
-        }
-
-    }
-
-    private EnclosingBall<Euclidean2D, Cartesian2D> checkDisk(List<Cartesian2D> points) {
-
-        WelzlEncloser<Euclidean2D, Cartesian2D> encloser =
-                new WelzlEncloser<>(1.0e-10, new DiskGenerator());
-        EnclosingBall<Euclidean2D, Cartesian2D> disk = encloser.enclose(points);
-
-        // all points are enclosed
-        for (Cartesian2D v : points) {
-            Assert.assertTrue(disk.contains(v, 1.0e-10));
-        }
-
-        for (Cartesian2D v : points) {
-            boolean inSupport = false;
-            for (Cartesian2D s : disk.getSupport()) {
-                if (v == s) {
-                    inSupport = true;
-                }
-            }
-            if (inSupport) {
-                // points on the support should be outside of reduced ball
-                Assert.assertFalse(disk.contains(v, -0.001));
-            }
-        }
-
-        return disk;
-
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/enclosing/WelzlEncloser3DTest.java b/src/test/java/org/apache/commons/math4/geometry/enclosing/WelzlEncloser3DTest.java
deleted file mode 100644
index 5f585b4..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/enclosing/WelzlEncloser3DTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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.enclosing;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.apache.commons.rng.UniformRandomProvider;
-import org.apache.commons.rng.simple.RandomSource;
-import org.apache.commons.rng.sampling.UnitSphereSampler;
-import org.apache.commons.math4.geometry.enclosing.EnclosingBall;
-import org.apache.commons.math4.geometry.enclosing.WelzlEncloser;
-import org.apache.commons.math4.geometry.euclidean.threed.Euclidean3D;
-import org.apache.commons.math4.geometry.euclidean.threed.SphereGenerator;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-
-
-public class WelzlEncloser3DTest {
-
-    @Test
-    public void testNullList() {
-        SphereGenerator generator = new SphereGenerator();
-        WelzlEncloser<Euclidean3D, Cartesian3D> encloser =
-                new WelzlEncloser<>(1.0e-10, generator);
-        EnclosingBall<Euclidean3D, Cartesian3D> ball = encloser.enclose(null);
-        Assert.assertTrue(ball.getRadius() < 0);
-    }
-
-    @Test
-    public void testNoPoints() {
-        SphereGenerator generator = new SphereGenerator();
-        WelzlEncloser<Euclidean3D, Cartesian3D> encloser =
-                new WelzlEncloser<>(1.0e-10, generator);
-        EnclosingBall<Euclidean3D, Cartesian3D> ball = encloser.enclose(new ArrayList<Cartesian3D>());
-        Assert.assertTrue(ball.getRadius() < 0);
-    }
-
-    @Test
-    public void testReducingBall() {
-        List<Cartesian3D> list =
-                Arrays.asList(new Cartesian3D(-7.140397329568118, -16.571661242582177,  11.714458961735405),
-                              new Cartesian3D(-7.137986707455888, -16.570767323375720,  11.708602108715928),
-                              new Cartesian3D(-7.139185068549035, -16.570891204702250,  11.715554057357394),
-                              new Cartesian3D(-7.142682716997507, -16.571609818234290,  11.710787934580328),
-                              new Cartesian3D(-7.139018392423351, -16.574405614157020,  11.710518716711425),
-                              new Cartesian3D(-7.140870659936730, -16.567993074240455,  11.710914678204503),
-                              new Cartesian3D(-7.136350173659562, -16.570498228820930,  11.713965225900928),
-                              new Cartesian3D(-7.141675762759172, -16.572852471407028,  11.714033471449508),
-                              new Cartesian3D(-7.140453077221105, -16.570212820780647,  11.708624578004980),
-                              new Cartesian3D(-7.140322188726825, -16.574152894557717,  11.710305611121410),
-                              new Cartesian3D(-7.141116131477088, -16.574061164624560,  11.712938509321699));
-        WelzlEncloser<Euclidean3D, Cartesian3D> encloser =
-                new WelzlEncloser<>(1.0e-10, new SphereGenerator());
-        EnclosingBall<Euclidean3D, Cartesian3D> ball = encloser.enclose(list);
-        Assert.assertTrue(ball.getRadius() > 0);
-    }
-
-    @Test
-    public void testInfiniteLoop() {
-        // this test used to generate an infinite loop
-        List<Cartesian3D> list =
-                Arrays.asList(new Cartesian3D( -0.89227075512164380,  -2.89317694645713900,  14.84572323743355500),
-                              new Cartesian3D( -0.92099498940693580,  -2.31086108263908940,  12.92071026467688300),
-                              new Cartesian3D( -0.85227999411005200,  -3.06314731441320730,  15.40163831651287000),
-                              new Cartesian3D( -1.77399413020785970,  -3.65630391378114260,  14.13190097751873400),
-                              new Cartesian3D(  0.33157833272465354,  -2.22813591757792160,  14.21225234159008200),
-                              new Cartesian3D( -1.53065579165484400,  -1.65692084770139570,  14.61483055714788500),
-                              new Cartesian3D( -1.08457093941217140,  -1.96100325935602980,  13.09265170575555000),
-                              new Cartesian3D(  0.30029469589708850,  -3.05470831395667370,  14.56352400426342600),
-                              new Cartesian3D( -0.95007443938638460,  -1.86810946486118360,  15.14491234340057000),
-                              new Cartesian3D( -1.89661503804130830,  -2.17004080885185860,  14.81235128513927000),
-                              new Cartesian3D( -0.72193328761607530,  -1.44513142833618270,  14.52355724218561800),
-                              new Cartesian3D( -0.26895980939606550,  -3.69512371522084140,  14.72272846327652000),
-                              new Cartesian3D( -1.53501693431786170,  -3.25055166611021900,  15.15509062584274800),
-                              new Cartesian3D( -0.71727553535519410,  -3.62284279460799100,  13.26256700929380700),
-                              new Cartesian3D( -0.30220950676137365,  -3.25410412500779070,  13.13682612771606000),
-                              new Cartesian3D( -0.04543996608267075,  -1.93081853923797750,  14.79497997883171400),
-                              new Cartesian3D( -1.53348892951571640,  -3.66688919703524900,  14.73095600812074200),
-                              new Cartesian3D( -0.98034899533935820,  -3.34004481162763960,  13.03245014017556800));
-
-        WelzlEncloser<Euclidean3D, Cartesian3D> encloser =
-                new WelzlEncloser<>(1.0e-10, new SphereGenerator());
-        EnclosingBall<Euclidean3D, Cartesian3D> ball = encloser.enclose(list);
-        Assert.assertTrue(ball.getRadius() > 0);
-    }
-
-    @Test
-    public void testLargeSamples() throws IOException {
-        final UniformRandomProvider random = RandomSource.create(RandomSource.WELL_1024_A,
-                                                                 0x35ddecfc78131e1dl);
-        final UnitSphereSampler sr = new UnitSphereSampler(3, random);
-        for (int k = 0; k < 50; ++k) {
-
-            // define the reference sphere we want to compute
-            double d = 25 * random.nextDouble();
-            double refRadius = 10 * random.nextDouble();
-            Cartesian3D refCenter = new Cartesian3D(d, new Cartesian3D(sr.nextVector()));
-            // set up a large sample inside the reference sphere
-            int nbPoints = random.nextInt(1000);
-            List<Cartesian3D> points = new ArrayList<>();
-            for (int i = 0; i < nbPoints; ++i) {
-                double r = refRadius * random.nextDouble();
-                points.add(new Cartesian3D(1.0, refCenter, r, new Cartesian3D(sr.nextVector())));
-            }
-
-            // test we find a sphere at most as large as the one used for random drawings
-            checkSphere(points, refRadius);
-
-        }
-    }
-
-    private void checkSphere(List<Cartesian3D> points, double refRadius) {
-
-        EnclosingBall<Euclidean3D, Cartesian3D> sphere = checkSphere(points);
-
-        // compare computed sphere with bounding sphere
-        Assert.assertTrue(sphere.getRadius() <= refRadius);
-
-        // check removing any point of the support Sphere fails to enclose the point
-        for (int i = 0; i < sphere.getSupportSize(); ++i) {
-            List<Cartesian3D> reducedSupport = new ArrayList<>();
-            int count = 0;
-            for (Cartesian3D s : sphere.getSupport()) {
-                if (count++ != i) {
-                    reducedSupport.add(s);
-                }
-            }
-            EnclosingBall<Euclidean3D, Cartesian3D> reducedSphere =
-                    new SphereGenerator().ballOnSupport(reducedSupport);
-            boolean foundOutside = false;
-            for (int j = 0; j < points.size() && !foundOutside; ++j) {
-                if (!reducedSphere.contains(points.get(j), 1.0e-10)) {
-                    foundOutside = true;
-                }
-            }
-            Assert.assertTrue(foundOutside);
-        }
-
-    }
-
-    private EnclosingBall<Euclidean3D, Cartesian3D> checkSphere(List<Cartesian3D> points) {
-
-        WelzlEncloser<Euclidean3D, Cartesian3D> encloser =
-                new WelzlEncloser<>(1.0e-10, new SphereGenerator());
-        EnclosingBall<Euclidean3D, Cartesian3D> Sphere = encloser.enclose(points);
-
-        // all points are enclosed
-        for (Cartesian3D v : points) {
-            Assert.assertTrue(Sphere.contains(v, 1.0e-10));
-        }
-
-        for (Cartesian3D v : points) {
-            boolean inSupport = false;
-            for (Cartesian3D s : Sphere.getSupport()) {
-                if (v == s) {
-                    inSupport = true;
-                }
-            }
-            if (inSupport) {
-                // points on the support should be outside of reduced ball
-                Assert.assertFalse(Sphere.contains(v, -0.001));
-            }
-        }
-
-        return Sphere;
-
-    }
-
-}
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
deleted file mode 100644
index ebac525..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Cartesian1DTest.java
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * 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 java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.NumberFormat;
-import java.util.Locale;
-
-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 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() {
-        // act
-        Cartesian1D zero = new Cartesian1D(1).getZero();
-
-        // assert
-        Assert.assertEquals(0, zero.getX(), TEST_TOLERANCE);
-    }
-
-    @Test
-    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 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 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 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 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 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 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 testNegate() {
-        // act/assert
-        checkVector(new Cartesian1D(0.1).negate(), -0.1);
-        checkVector(new Cartesian1D(-0.1).negate(), 0.1);
-    }
-
-    @Test
-    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 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);
-
-        // 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);
-
-        // 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 testDistance_static() {
-        // arrange
-        Cartesian1D v1 = new Cartesian1D(1);
-        Cartesian1D v2 = new Cartesian1D(-4);
-
-        // 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);
-
-        // 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 testDistanceInf_static() {
-        // arrange
-        Cartesian1D v1 = new Cartesian1D(1);
-        Cartesian1D v2 = new Cartesian1D(-4);
-
-        // 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 testDistanceSq() {
-        // arrange
-        Cartesian1D v1 = new Cartesian1D(1);
-        Cartesian1D v2 = new Cartesian1D(-4);
-
-        // 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 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);
-
-        Assert.assertEquals(Cartesian1D.distance(v1, v2) * Cartesian1D.distance(v1, v2),
-                            Cartesian1D.distanceSq(v1, v2), TEST_TOLERANCE);
-    }
-
-    @Test
-    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 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(), TEST_TOLERANCE);
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Euclidean1DTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Euclidean1DTest.java
deleted file mode 100644
index 92a3e7b..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Euclidean1DTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.apache.commons.math4.TestUtils;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.euclidean.oned.Euclidean1D;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class Euclidean1DTest {
-
-    @Test
-    public void testDimension() {
-        Assert.assertEquals(1, Euclidean1D.getInstance().getDimension());
-    }
-
-    @Test(expected=Euclidean1D.NoSubSpaceException.class)
-    public void testSubSpace() {
-        Euclidean1D.getInstance().getSubSpace();
-    }
-
-    @Test
-    public void testSerialization() {
-        Space e1 = Euclidean1D.getInstance();
-        Space deserialized = (Space) TestUtils.serializeAndRecover(e1);
-        Assert.assertTrue(e1 == deserialized);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/FrenchVector1DFormatTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/FrenchVector1DFormatTest.java
deleted file mode 100644
index d083c8d..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/FrenchVector1DFormatTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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 java.util.Locale;
-
-
-public class FrenchVector1DFormatTest extends Vector1DFormatAbstractTest {
-
-    @Override
-    protected char getDecimalCharacter() {
-        return ',';
-    }
-
-    @Override
-    protected Locale getLocale() {
-        return Locale.FRENCH;
-    }
-}
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
deleted file mode 100644
index 09ed41f..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalTest.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * 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.apache.commons.math4.geometry.GeometryTestUtils;
-import org.apache.commons.math4.geometry.euclidean.oned.Interval;
-import org.apache.commons.math4.geometry.partitioning.Region;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.numbers.core.Precision;
-import org.apache.commons.math4.exception.NumberIsTooSmallException;
-import org.junit.Assert;
-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 testCheckPoint() {
-        // arrange
-        Interval interval = new Interval(2.3, 5.7);
-
-        // 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 testCheckPoint_tolerance() {
-        // arrange
-        Interval interval = new Interval(2.3, 5.7);
-
-        // 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_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));
-        }
-        GeometryTestUtils.assertPositiveInfinity(interval.getSize());
-        GeometryTestUtils.assertNegativeInfinity(interval.getInf());
-        Assert.assertEquals(9.0, interval.getSup(), TEST_TOLERANCE);
-    }
-
-    @Test
-    public void testInfinite_sup() {
-        // act
-        Interval interval = new Interval(9.0, Double.POSITIVE_INFINITY);
-
-        // 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), TEST_TOLERANCE));
-        }
-        GeometryTestUtils.assertPositiveInfinity(interval.getSize());
-        Assert.assertEquals(9.0, interval.getInf(), TEST_TOLERANCE);
-        GeometryTestUtils.assertPositiveInfinity(interval.getSup());
-    }
-
-    @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));
-        }
-        GeometryTestUtils.assertPositiveInfinity(interval.getSize());
-        GeometryTestUtils.assertNegativeInfinity(interval.getInf());
-        GeometryTestUtils.assertPositiveInfinity(interval.getSup());
-    }
-
-    @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);
-    }
-
-    @Test
-    public void testSingleInfinitePoint_positive() {
-        // act
-        Interval interval = new Interval(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
-
-        // assert
-        Assert.assertTrue(Double.isNaN(interval.getSize())); // inf - inf = NaN according to floating point spec
-        GeometryTestUtils.assertPositiveInfinity(interval.getBarycenter());
-    }
-
-    @Test
-    public void testSingleInfinitePoint_negative() {
-        // act
-        Interval interval = new Interval(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
-
-        // assert
-        Assert.assertTrue(Double.isNaN(interval.getSize())); // inf - inf = NaN according to floating point spec
-        GeometryTestUtils.assertNegativeInfinity(interval.getBarycenter());
-    }
-}
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
deleted file mode 100644
index 0343b8d..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalsSetTest.java
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * 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 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;
-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);
-        GeometryTestUtils.assertNegativeInfinity(set.getInf());
-        GeometryTestUtils.assertPositiveInfinity(set.getSup());
-        GeometryTestUtils.assertPositiveInfinity(set.getSize());
-        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);
-        GeometryTestUtils.assertNegativeInfinity(set.getInf());
-        GeometryTestUtils.assertPositiveInfinity(set.getSup());
-        GeometryTestUtils.assertPositiveInfinity(set.getSize());
-        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);
-        GeometryTestUtils.assertPositiveInfinity(set.getSup());
-        GeometryTestUtils.assertPositiveInfinity(set.getSize());
-        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);
-        GeometryTestUtils.assertNegativeInfinity(set.getInf());
-        Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
-        GeometryTestUtils.assertPositiveInfinity(set.getSize());
-        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);
-        GeometryTestUtils.assertNegativeInfinity(set.getInf());
-        GeometryTestUtils.assertPositiveInfinity(set.getSup());
-        GeometryTestUtils.assertPositiveInfinity(set.getSize());
-        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);
-        GeometryTestUtils.assertPositiveInfinity(set.getSup());
-        GeometryTestUtils.assertPositiveInfinity(set.getSize());
-        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);
-        GeometryTestUtils.assertNegativeInfinity(set.getInf());
-        Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
-        GeometryTestUtils.assertPositiveInfinity(set.getSize());
-        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);
-        GeometryTestUtils.assertNegativeInfinity(set.getInf());
-        GeometryTestUtils.assertPositiveInfinity(set.getSup());
-        GeometryTestUtils.assertPositiveInfinity(set.getSize());
-        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);
-        GeometryTestUtils.assertNegativeInfinity(set.getInf());
-        Assert.assertEquals(first, set.getSup(), TEST_TOLERANCE);
-        GeometryTestUtils.assertPositiveInfinity(set.getSize());
-        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);
-        GeometryTestUtils.assertPositiveInfinity(set.getSup());
-        GeometryTestUtils.assertPositiveInfinity(set.getSize());
-        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);
-        Assert.assertEquals(3.4, set.getSize(), 1.0e-10);
-        Assert.assertEquals(4.0, ((Cartesian1D) set.getBarycenter()).getX(), 1.0e-10);
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Cartesian1D(2.3)));
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Cartesian1D(5.7)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new Cartesian1D(1.2)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new Cartesian1D(8.7)));
-        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new Cartesian1D(3.0)));
-        Assert.assertEquals(2.3, set.getInf(), 1.0e-10);
-        Assert.assertEquals(5.7, set.getSup(), 1.0e-10);
-    }
-
-    @Test
-    public void testInfinite() {
-        IntervalsSet set = new IntervalsSet(9.0, Double.POSITIVE_INFINITY, 1.0e-10);
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Cartesian1D(9.0)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new Cartesian1D(8.4)));
-        for (double e = 1.0; e <= 6.0; e += 1.0) {
-            Assert.assertEquals(Region.Location.INSIDE,
-                                set.checkPoint(new Cartesian1D(FastMath.pow(10.0, e))));
-        }
-        Assert.assertTrue(Double.isInfinite(set.getSize()));
-        Assert.assertEquals(9.0, set.getInf(), 1.0e-10);
-        Assert.assertTrue(Double.isInfinite(set.getSup()));
-
-        set = (IntervalsSet) new RegionFactory<Euclidean1D>().getComplement(set);
-        Assert.assertEquals(9.0, set.getSup(), 1.0e-10);
-        Assert.assertTrue(Double.isInfinite(set.getInf()));
-
-    }
-
-    @Test
-    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, 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());
-        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)));
-    }
-
-    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);
-    }
-}
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
deleted file mode 100644
index 8da1d1e..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/OrientedPointTest.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * 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.GeometryTestUtils;
-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.assertTrue(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.assertTrue(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
-        GeometryTestUtils.assertNegativeInfinity(set.getInf());
-        GeometryTestUtils.assertPositiveInfinity(set.getSup());
-    }
-
-    @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.assertTrue(notDirect1.sameOrientationAs(notDirect1));
-        Assert.assertTrue(notDirect1.sameOrientationAs(notDirect2));
-        Assert.assertTrue(notDirect2.sameOrientationAs(notDirect1));
-
-        Assert.assertTrue(direct1.sameOrientationAs(direct1));
-        Assert.assertTrue(direct1.sameOrientationAs(direct2));
-        Assert.assertTrue(direct2.sameOrientationAs(direct1));
-
-        Assert.assertFalse(notDirect1.sameOrientationAs(direct1));
-        Assert.assertFalse(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.assertFalse(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);
-    }
-}
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
deleted file mode 100644
index 7b8561a..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPointTest.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * 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.apache.commons.math4.geometry.partitioning.Side;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane.SplitSubHyperplane;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SubOrientedPointTest {
-    private static final double TEST_TOLERANCE = 1e-10;
-
-    @Test
-    public void testGetSize() {
-        // arrange
-        OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-        SubOrientedPoint pt = hyperplane.wholeHyperplane();
-
-        // act/assert
-        Assert.assertEquals(0.0, pt.getSize(), TEST_TOLERANCE);
-    }
-
-    @Test
-    public void testIsEmpty() {
-        // arrange
-        OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-        SubOrientedPoint pt = hyperplane.wholeHyperplane();
-
-        // act/assert
-        Assert.assertFalse(pt.isEmpty());
-    }
-
-    @Test
-    public void testBuildNew() {
-        // arrange
-        OrientedPoint originalHyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-        SubOrientedPoint pt = originalHyperplane.wholeHyperplane();
-
-        OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(2), true, TEST_TOLERANCE);
-        IntervalsSet intervals = new IntervalsSet(2, 3, TEST_TOLERANCE);
-
-        // act
-        SubHyperplane<Euclidean1D> result = pt.buildNew(hyperplane, intervals);
-
-        // assert
-        Assert.assertTrue(result instanceof SubOrientedPoint);
-        Assert.assertSame(hyperplane, result.getHyperplane());
-        Assert.assertSame(intervals, ((SubOrientedPoint) result).getRemainingRegion());
-    }
-
-    @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);
-
-        OrientedPoint splitter = new OrientedPoint(new Cartesian1D(2), true, TEST_TOLERANCE);
-
-        // act
-        SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
-
-        // assert
-        Assert.assertEquals(Side.MINUS, split.getSide());
-
-        SubOrientedPoint minusSub = ((SubOrientedPoint) split.getMinus());
-        Assert.assertNotNull(minusSub);
-
-        OrientedPoint minusHyper = (OrientedPoint) minusSub.getHyperplane();
-        Assert.assertEquals(1, minusHyper.getLocation().getX(), TEST_TOLERANCE);
-
-        Assert.assertSame(interval, minusSub.getRemainingRegion());
-
-        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);
-
-        OrientedPoint splitter = new OrientedPoint(new Cartesian1D(0), true, TEST_TOLERANCE);
-
-        // act
-        SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
-
-        // assert
-        Assert.assertEquals(Side.PLUS, split.getSide());
-
-        Assert.assertNull(split.getMinus());
-
-        SubOrientedPoint plusSub = ((SubOrientedPoint) split.getPlus());
-        Assert.assertNotNull(plusSub);
-
-        OrientedPoint plusHyper = (OrientedPoint) plusSub.getHyperplane();
-        Assert.assertEquals(1, plusHyper.getLocation().getX(), 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(TEST_TOLERANCE);
-        SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
-
-        OrientedPoint splitter = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-
-        // act
-        SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
-
-        // assert
-        Assert.assertEquals(Side.HYPER, split.getSide());
-
-        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 = hyperplane.wholeHyperplane();
-
-        // act/assert
-        SplitSubHyperplane<Euclidean1D> plusSplit = pt.split(new OrientedPoint(new Cartesian1D(0.899), true, 1e-10));
-        Assert.assertNull(plusSplit.getMinus());
-        Assert.assertNotNull(plusSplit.getPlus());
-
-        SplitSubHyperplane<Euclidean1D> lowWithinTolerance = pt.split(new OrientedPoint(new Cartesian1D(0.901), true, 1e-10));
-        Assert.assertNull(lowWithinTolerance.getMinus());
-        Assert.assertNull(lowWithinTolerance.getPlus());
-
-        SplitSubHyperplane<Euclidean1D> highWithinTolerance = pt.split(new OrientedPoint(new Cartesian1D(1.09), true, 1e-10));
-        Assert.assertNull(highWithinTolerance.getMinus());
-        Assert.assertNull(highWithinTolerance.getPlus());
-
-        SplitSubHyperplane<Euclidean1D> minusSplit = pt.split(new OrientedPoint(new Cartesian1D(1.101), true, 1e-10));
-        Assert.assertNotNull(minusSplit.getMinus());
-        Assert.assertNull(minusSplit.getPlus());
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1DFormatAbstractTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1DFormatAbstractTest.java
deleted file mode 100644
index e73cdc5..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1DFormatAbstractTest.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * 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 java.text.NumberFormat;
-import java.text.ParsePosition;
-import java.util.Locale;
-
-import org.apache.commons.math4.exception.MathParseException;
-import org.apache.commons.math4.geometry.euclidean.oned.Vector1DFormat;
-import org.junit.Assert;
-import org.junit.Test;
-
-public abstract class Vector1DFormatAbstractTest {
-
-    Vector1DFormat vector1DFormat = null;
-    Vector1DFormat vector1DFormatSquare = null;
-
-    protected abstract Locale getLocale();
-
-    protected abstract char getDecimalCharacter();
-
-    protected Vector1DFormatAbstractTest() {
-        vector1DFormat = Vector1DFormat.getInstance(getLocale());
-        final NumberFormat nf = NumberFormat.getInstance(getLocale());
-        nf.setMaximumFractionDigits(2);
-        vector1DFormatSquare = new Vector1DFormat("[", "]", nf);
-    }
-
-    @Test
-    public void testSimpleNoDecimals() {
-        Cartesian1D c = new Cartesian1D(1);
-        String expected = "{1}";
-        String actual = vector1DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testSimpleWithDecimals() {
-        Cartesian1D c = new Cartesian1D(1.23);
-        String expected =
-            "{1"    + getDecimalCharacter() +
-            "23}";
-        String actual = vector1DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testSimpleWithDecimalsTrunc() {
-        Cartesian1D c = new Cartesian1D(1.232323232323);
-        String expected =
-            "{1"    + getDecimalCharacter() +
-            "2323232323}";
-        String actual = vector1DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testNegativeX() {
-        Cartesian1D c = new Cartesian1D(-1.232323232323);
-        String expected =
-            "{-1"    + getDecimalCharacter() +
-            "2323232323}";
-        String actual = vector1DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testNonDefaultSetting() {
-        Cartesian1D c = new Cartesian1D(1);
-        String expected = "[1]";
-        String actual = vector1DFormatSquare.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testDefaultFormatVector1D() {
-        Locale defaultLocal = Locale.getDefault();
-        Locale.setDefault(getLocale());
-
-        Cartesian1D c = new Cartesian1D(232.22222222222);
-        String expected =
-            "{232"    + getDecimalCharacter() +
-            "2222222222}";
-        String actual = (new Vector1DFormat()).format(c);
-        Assert.assertEquals(expected, actual);
-
-        Locale.setDefault(defaultLocal);
-    }
-
-    @Test
-    public void testNan() {
-        Cartesian1D c = Cartesian1D.NaN;
-        String expected = "{(NaN)}";
-        String actual = vector1DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testPositiveInfinity() {
-        Cartesian1D c = Cartesian1D.POSITIVE_INFINITY;
-        String expected = "{(Infinity)}";
-        String actual = vector1DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void tesNegativeInfinity() {
-        Cartesian1D c = Cartesian1D.NEGATIVE_INFINITY;
-        String expected = "{(-Infinity)}";
-        String actual = vector1DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseSimpleNoDecimals() throws MathParseException {
-        String source = "{1}";
-        Vector1D expected = new Cartesian1D(1);
-        Vector1D actual = vector1DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseIgnoredWhitespace() {
-        Vector1D expected = new Cartesian1D(1);
-        ParsePosition pos1 = new ParsePosition(0);
-        String source1 = "{1}";
-        Assert.assertEquals(expected, vector1DFormat.parse(source1, pos1));
-        Assert.assertEquals(source1.length(), pos1.getIndex());
-        ParsePosition pos2 = new ParsePosition(0);
-        String source2 = " { 1 } ";
-        Assert.assertEquals(expected, vector1DFormat.parse(source2, pos2));
-        Assert.assertEquals(source2.length() - 1, pos2.getIndex());
-    }
-
-    @Test
-    public void testParseSimpleWithDecimals() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "23}";
-        Vector1D expected = new Cartesian1D(1.23);
-        Vector1D actual = vector1DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseSimpleWithDecimalsTrunc() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "2323}";
-        Vector1D expected = new Cartesian1D(1.2323);
-        Vector1D actual = vector1DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeX() throws MathParseException {
-        String source =
-            "{-1" + getDecimalCharacter() +
-            "2323}";
-        Vector1D expected = new Cartesian1D(-1.2323);
-        Vector1D actual = vector1DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeY() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "2323}";
-        Vector1D expected = new Cartesian1D(1.2323);
-        Vector1D actual = vector1DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeZ() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "2323}";
-        Vector1D expected = new Cartesian1D(1.2323);
-        Vector1D actual = vector1DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeAll() throws MathParseException {
-        String source =
-            "{-1" + getDecimalCharacter() +
-            "2323}";
-        Vector1D expected = new Cartesian1D(-1.2323);
-        Vector1D actual = vector1DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseZeroX() throws MathParseException {
-        String source =
-            "{0" + getDecimalCharacter() +
-            "0}";
-        Vector1D expected = new Cartesian1D(0.0);
-        Vector1D actual = vector1DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNonDefaultSetting() throws MathParseException {
-        String source =
-            "[1" + getDecimalCharacter() +
-            "2323]";
-        Vector1D expected = new Cartesian1D(1.2323);
-        Vector1D actual = vector1DFormatSquare.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNan() throws MathParseException {
-        String source = "{(NaN)}";
-        Vector1D actual = vector1DFormat.parse(source);
-        Assert.assertEquals(Cartesian1D.NaN, actual);
-    }
-
-    @Test
-    public void testParsePositiveInfinity() throws MathParseException {
-        String source = "{(Infinity)}";
-        Vector1D actual = vector1DFormat.parse(source);
-        Assert.assertEquals(Cartesian1D.POSITIVE_INFINITY, actual);
-    }
-
-    @Test
-    public void testParseNegativeInfinity() throws MathParseException {
-        String source = "{(-Infinity)}";
-        Vector1D actual = vector1DFormat.parse(source);
-        Assert.assertEquals(Cartesian1D.NEGATIVE_INFINITY, actual);
-    }
-
-    @Test
-    public void testConstructorSingleFormat() {
-        NumberFormat nf = NumberFormat.getInstance();
-        Vector1DFormat cf = new Vector1DFormat(nf);
-        Assert.assertNotNull(cf);
-        Assert.assertEquals(nf, cf.getFormat());
-    }
-
-    @Test
-    public void testForgottenPrefix() {
-        ParsePosition pos = new ParsePosition(0);
-        Assert.assertNull(new Vector1DFormat().parse("1}", pos));
-        Assert.assertEquals(0, pos.getErrorIndex());
-    }
-
-    @Test
-    public void testForgottenSuffix() {
-        ParsePosition pos = new ParsePosition(0);
-        Assert.assertNull(new Vector1DFormat().parse("{1 ", pos));
-        Assert.assertEquals(2, pos.getErrorIndex());
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1DFormatTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1DFormatTest.java
deleted file mode 100644
index 9ad0eb1..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Vector1DFormatTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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 java.util.Locale;
-
-
-public class Vector1DFormatTest extends Vector1DFormatAbstractTest {
-
-    @Override
-    protected char getDecimalCharacter() {
-        return '.';
-    }
-
-    @Override
-    protected Locale getLocale() {
-        return Locale.US;
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Euclidean3DTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Euclidean3DTest.java
deleted file mode 100644
index 66c494d..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Euclidean3DTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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 org.apache.commons.math4.TestUtils;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.euclidean.threed.Euclidean3D;
-import org.apache.commons.math4.geometry.euclidean.twod.Euclidean2D;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class Euclidean3DTest {
-
-    @Test
-    public void testDimension() {
-        Assert.assertEquals(3, Euclidean3D.getInstance().getDimension());
-    }
-
-    @Test
-    public void testSubSpace() {
-        Assert.assertTrue(Euclidean2D.getInstance() == Euclidean3D.getInstance().getSubSpace());
-    }
-
-    @Test
-    public void testSerialization() {
-        Space e3 = Euclidean3D.getInstance();
-        Space deserialized = (Space) TestUtils.serializeAndRecover(e3);
-        Assert.assertTrue(e3 == deserialized);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotationDSTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotationDSTest.java
index 83351b6..929ee16 100644
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotationDSTest.java
+++ b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotationDSTest.java
@@ -20,9 +20,12 @@
 import org.junit.Assert;
 import org.junit.Test;
 import org.apache.commons.numbers.angle.PlaneAngleRadians;
+import org.apache.commons.numbers.quaternion.Quaternion;
 import org.apache.commons.rng.UniformRandomProvider;
 import org.apache.commons.rng.simple.RandomSource;
 import org.apache.commons.rng.sampling.UnitSphereSampler;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
 import org.apache.commons.math4.analysis.differentiation.DerivativeStructure;
 import org.apache.commons.math4.exception.MathArithmeticException;
 import org.apache.commons.math4.exception.MathIllegalArgumentException;
@@ -30,9 +33,7 @@
 import org.apache.commons.math4.geometry.euclidean.threed.FieldRotation;
 import org.apache.commons.math4.geometry.euclidean.threed.FieldVector3D;
 import org.apache.commons.math4.geometry.euclidean.threed.NotARotationMatrixException;
-import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
 import org.apache.commons.math4.geometry.euclidean.threed.RotationOrder;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
 import org.apache.commons.math4.linear.MatrixUtils;
 import org.apache.commons.math4.linear.RealMatrix;
 import org.apache.commons.math4.util.FastMath;
@@ -779,10 +780,11 @@
         checkRotationDS(r1,
                         -r1.getQ0().getReal(), -r1.getQ1().getReal(),
                         -r1.getQ2().getReal(), -r1.getQ3().getReal());
-        Assert.assertEquals(0.288, r1.toRotation().getQ0(), 1.0e-15);
-        Assert.assertEquals(0.384, r1.toRotation().getQ1(), 1.0e-15);
-        Assert.assertEquals(0.36,  r1.toRotation().getQ2(), 1.0e-15);
-        Assert.assertEquals(0.8,   r1.toRotation().getQ3(), 1.0e-15);
+        final Quaternion r1Quat = r1.toRotation().getQuaternion();
+        Assert.assertEquals(0.288, r1Quat.getW(), 1.0e-15);
+        Assert.assertEquals(0.384, r1Quat.getX(), 1.0e-15);
+        Assert.assertEquals(0.36,  r1Quat.getY(), 1.0e-15);
+        Assert.assertEquals(0.8,   r1Quat.getZ(), 1.0e-15);
 
     }
 
@@ -796,11 +798,10 @@
                                                                                              createAngle(0.3),
                                                                                              RotationConvention.VECTOR_OPERATOR);
         FieldRotation<DerivativeStructure> r3       = r2.applyTo(r1);
-        FieldRotation<DerivativeStructure> r3Double = r2.applyTo(new Rotation(r1.getQ0().getReal(),
-                                                                              r1.getQ1().getReal(),
-                                                                              r1.getQ2().getReal(),
-                                                                              r1.getQ3().getReal(),
-                                                                              false));
+        FieldRotation<DerivativeStructure> r3Double = r2.applyTo(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                                       r1.getQ1().getReal(),
+                                                                                       r1.getQ2().getReal(),
+                                                                                       r1.getQ3().getReal()));
 
         for (double x = -0.9; x < 0.9; x += 0.2) {
             for (double y = -0.9; y < 0.9; y += 0.2) {
@@ -824,11 +825,10 @@
                                                                                              createAngle(0.3),
                                                                                              RotationConvention.VECTOR_OPERATOR);
         FieldRotation<DerivativeStructure> r3       = r2.compose(r1, RotationConvention.VECTOR_OPERATOR);
-        FieldRotation<DerivativeStructure> r3Double = r2.compose(new Rotation(r1.getQ0().getReal(),
-                                                                              r1.getQ1().getReal(),
-                                                                              r1.getQ2().getReal(),
-                                                                              r1.getQ3().getReal(),
-                                                                              false),
+        FieldRotation<DerivativeStructure> r3Double = r2.compose(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                                       r1.getQ1().getReal(),
+                                                                                       r1.getQ2().getReal(),
+                                                                                       r1.getQ3().getReal()),
                                                                  RotationConvention.VECTOR_OPERATOR);
 
         for (double x = -0.9; x < 0.9; x += 0.2) {
@@ -853,11 +853,10 @@
                                                                                              createAngle(0.3),
                                                                                              RotationConvention.FRAME_TRANSFORM);
         FieldRotation<DerivativeStructure> r3       = r2.compose(r1, RotationConvention.FRAME_TRANSFORM);
-        FieldRotation<DerivativeStructure> r3Double = r2.compose(new Rotation(r1.getQ0().getReal(),
-                                                                              r1.getQ1().getReal(),
-                                                                              r1.getQ2().getReal(),
-                                                                              r1.getQ3().getReal(),
-                                                                              false),
+        FieldRotation<DerivativeStructure> r3Double = r2.compose(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                                       r1.getQ1().getReal(),
+                                                                                       r1.getQ2().getReal(),
+                                                                                       r1.getQ3().getReal()),
                                                                  RotationConvention.FRAME_TRANSFORM);
 
         for (double x = -0.9; x < 0.9; x += 0.2) {
@@ -882,11 +881,10 @@
                                                                                        createAngle(0.3),
                                                                                        RotationConvention.VECTOR_OPERATOR);
         FieldRotation<DerivativeStructure> r3 = r2.applyInverseTo(r1);
-        FieldRotation<DerivativeStructure> r3Double = r2.applyInverseTo(new Rotation(r1.getQ0().getReal(),
-                                                                                     r1.getQ1().getReal(),
-                                                                                     r1.getQ2().getReal(),
-                                                                                     r1.getQ3().getReal(),
-                                                                                    false));
+        FieldRotation<DerivativeStructure> r3Double = r2.applyInverseTo(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                                              r1.getQ1().getReal(),
+                                                                                              r1.getQ2().getReal(),
+                                                                                              r1.getQ3().getReal()));
 
         for (double x = -0.9; x < 0.9; x += 0.2) {
             for (double y = -0.9; y < 0.9; y += 0.2) {
@@ -910,11 +908,10 @@
                                                                                        createAngle(0.3),
                                                                                        RotationConvention.VECTOR_OPERATOR);
         FieldRotation<DerivativeStructure> r3 = r2.composeInverse(r1, RotationConvention.VECTOR_OPERATOR);
-        FieldRotation<DerivativeStructure> r3Double = r2.composeInverse(new Rotation(r1.getQ0().getReal(),
-                                                                                     r1.getQ1().getReal(),
-                                                                                     r1.getQ2().getReal(),
-                                                                                     r1.getQ3().getReal(),
-                                                                                     false),
+        FieldRotation<DerivativeStructure> r3Double = r2.composeInverse(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                                              r1.getQ1().getReal(),
+                                                                                              r1.getQ2().getReal(),
+                                                                                              r1.getQ3().getReal()),
                                                                         RotationConvention.VECTOR_OPERATOR);
 
         for (double x = -0.9; x < 0.9; x += 0.2) {
@@ -939,11 +936,10 @@
                                                                                        createAngle(0.3),
                                                                                        RotationConvention.FRAME_TRANSFORM);
         FieldRotation<DerivativeStructure> r3 = r2.composeInverse(r1, RotationConvention.FRAME_TRANSFORM);
-        FieldRotation<DerivativeStructure> r3Double = r2.composeInverse(new Rotation(r1.getQ0().getReal(),
-                                                                                     r1.getQ1().getReal(),
-                                                                                     r1.getQ2().getReal(),
-                                                                                     r1.getQ3().getReal(),
-                                                                                     false),
+        FieldRotation<DerivativeStructure> r3Double = r2.composeInverse(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                                              r1.getQ1().getReal(),
+                                                                                              r1.getQ2().getReal(),
+                                                                                              r1.getQ3().getReal()),
                                                                         RotationConvention.FRAME_TRANSFORM);
 
         for (double x = -0.9; x < 0.9; x += 0.2) {
@@ -975,7 +971,7 @@
                         FieldVector3D<DerivativeStructure> uds   = createVector(x, y, z);
                         FieldVector3D<DerivativeStructure> ruds  = r.applyTo(uds);
                         FieldVector3D<DerivativeStructure> rIuds = r.applyInverseTo(uds);
-                        Cartesian3D   u     = new Cartesian3D(x, y, z);
+                        Vector3D u = Vector3D.of(x, y, z);
                         FieldVector3D<DerivativeStructure> ru    = r.applyTo(u);
                         FieldVector3D<DerivativeStructure> rIu   = r.applyInverseTo(u);
                         DerivativeStructure[] ruArray = new DerivativeStructure[3];
@@ -1000,12 +996,13 @@
         UnitSphereSampler g = new UnitSphereSampler(3, random);
         for (int i = 0; i < 10; ++i) {
             double[] unit1 = g.nextVector();
-            Rotation r1 = new Rotation(new Cartesian3D(unit1[0], unit1[1], unit1[2]),
-                                      random.nextDouble(), RotationConvention.VECTOR_OPERATOR);
-            FieldRotation<DerivativeStructure> r1Prime = new FieldRotation<>(new DerivativeStructure(4, 1, 0, r1.getQ0()),
-                                                new DerivativeStructure(4, 1, 1, r1.getQ1()),
-                                                new DerivativeStructure(4, 1, 2, r1.getQ2()),
-                                                new DerivativeStructure(4, 1, 3, r1.getQ3()),
+            QuaternionRotation r1 = QuaternionRotation.of(random.nextDouble(),
+                                                          unit1[0], unit1[1], unit1[2]);
+            final Quaternion r1Quat = r1.getQuaternion();
+            FieldRotation<DerivativeStructure> r1Prime = new FieldRotation<>(new DerivativeStructure(4, 1, 0, r1Quat.getW()),
+                                                new DerivativeStructure(4, 1, 1, r1Quat.getX()),
+                                                new DerivativeStructure(4, 1, 2, r1Quat.getY()),
+                                                new DerivativeStructure(4, 1, 3, r1Quat.getZ()),
                                                 false);
             double[] unit2 = g.nextVector();
             FieldRotation<DerivativeStructure> r2 = new FieldRotation<>(createVector(unit2[0], unit2[1], unit2[2]),
@@ -1051,7 +1048,7 @@
         FieldRotation<DerivativeStructure> r    = new FieldRotation<>(createAxis(kx, ky, kz),
                                                                                          createAngle(theta),
                                                                                          RotationConvention.VECTOR_OPERATOR);
-        Cartesian3D a      = new Cartesian3D(kx / n, ky / n, kz / n);
+        Vector3D a      = Vector3D.of(kx / n, ky / n, kz / n);
 
         // Jacobian of the normalized rotation axis a with respect to the Cartesian vector k
         RealMatrix dadk = MatrixUtils.createRealMatrix(new double[][] {
@@ -1063,15 +1060,15 @@
         for (double x = -0.9; x < 0.9; x += 0.2) {
             for (double y = -0.9; y < 0.9; y += 0.2) {
                 for (double z = -0.9; z < 0.9; z += 0.2) {
-                    Cartesian3D   u = new Cartesian3D(x, y, z);
+                    Vector3D   u = Vector3D.of(x, y, z);
                     FieldVector3D<DerivativeStructure> v = r.applyTo(createVector(x, y, z));
 
                     // explicit formula for rotation of vector u around axis a with angle theta
-                    double dot     = Cartesian3D.dotProduct(u, a);
-                    Cartesian3D cross = Cartesian3D.crossProduct(a, u);
+                    double dot     = u.dot(a);
+                    Vector3D cross = a.cross(u);
                     double c1      = 1 - cosTheta;
                     double c2      = c1 * dot;
-                    Cartesian3D rt    = new Cartesian3D(cosTheta, u, c2, a, sinTheta, cross);
+                    Vector3D rt    = Vector3D.linearCombination(cosTheta, u, c2, a, sinTheta, cross);
                     Assert.assertEquals(rt.getX(), v.getX().getReal(), eps);
                     Assert.assertEquals(rt.getY(), v.getY().getReal(), eps);
                     Assert.assertEquals(rt.getZ(), v.getZ().getReal(), eps);
@@ -1100,8 +1097,8 @@
 
                     // derivative with respect to rotation angle
                     // (analytical differentiation of the explicit formula)
-                    Cartesian3D dvdTheta =
-                            new Cartesian3D(-sinTheta, u, sinTheta * dot, a, cosTheta, cross);
+                    Vector3D dvdTheta =
+                        Vector3D.linearCombination(-sinTheta, u, sinTheta * dot, a, cosTheta, cross);
                     Assert.assertEquals(dvdTheta.getX(), v.getX().getPartialDerivative(0, 0, 0, 1), eps);
                     Assert.assertEquals(dvdTheta.getY(), v.getY().getPartialDerivative(0, 0, 0, 1), eps);
                     Assert.assertEquals(dvdTheta.getZ(), v.getZ().getPartialDerivative(0, 0, 0, 1), eps);
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotationDfpTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotationDfpTest.java
index a835b77..3bda1c4 100644
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotationDfpTest.java
+++ b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldRotationDfpTest.java
@@ -20,10 +20,12 @@
 import org.junit.Assert;
 import org.junit.Test;
 import org.apache.commons.numbers.angle.PlaneAngleRadians;
+import org.apache.commons.numbers.quaternion.Quaternion;
 import org.apache.commons.rng.UniformRandomProvider;
 import org.apache.commons.rng.simple.RandomSource;
 import org.apache.commons.rng.sampling.UnitSphereSampler;
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
 import org.apache.commons.math4.dfp.Dfp;
 import org.apache.commons.math4.dfp.DfpField;
 import org.apache.commons.math4.exception.MathArithmeticException;
@@ -32,9 +34,7 @@
 import org.apache.commons.math4.geometry.euclidean.threed.FieldRotation;
 import org.apache.commons.math4.geometry.euclidean.threed.FieldVector3D;
 import org.apache.commons.math4.geometry.euclidean.threed.NotARotationMatrixException;
-import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
 import org.apache.commons.math4.geometry.euclidean.threed.RotationOrder;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
 import org.apache.commons.math4.util.FastMath;
 
 public class FieldRotationDfpTest {
@@ -633,11 +633,10 @@
                                                              createAngle(0.3),
                                                              RotationConvention.VECTOR_OPERATOR);
         FieldRotation<Dfp> r3       = r2.applyTo(r1);
-        FieldRotation<Dfp> r3Double = r2.applyTo(new Rotation(r1.getQ0().getReal(),
-                                                      r1.getQ1().getReal(),
-                                                      r1.getQ2().getReal(),
-                                                      r1.getQ3().getReal(),
-                                                      false));
+        FieldRotation<Dfp> r3Double = r2.applyTo(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                       r1.getQ1().getReal(),
+                                                                       r1.getQ2().getReal(),
+                                                                       r1.getQ3().getReal()));
 
         for (double x = -0.9; x < 0.9; x += 0.2) {
             for (double y = -0.9; y < 0.9; y += 0.2) {
@@ -661,11 +660,10 @@
                                                              createAngle(0.3),
                                                              RotationConvention.VECTOR_OPERATOR);
         FieldRotation<Dfp> r3       = r2.compose(r1, RotationConvention.VECTOR_OPERATOR);
-        FieldRotation<Dfp> r3Double = r2.compose(new Rotation(r1.getQ0().getReal(),
-                                                      r1.getQ1().getReal(),
-                                                      r1.getQ2().getReal(),
-                                                      r1.getQ3().getReal(),
-                                                      false),
+        FieldRotation<Dfp> r3Double = r2.compose(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                       r1.getQ1().getReal(),
+                                                                       r1.getQ2().getReal(),
+                                                                       r1.getQ3().getReal()),
                                                  RotationConvention.VECTOR_OPERATOR);
 
         for (double x = -0.9; x < 0.9; x += 0.2) {
@@ -690,11 +688,10 @@
                                                              createAngle(0.3),
                                                              RotationConvention.FRAME_TRANSFORM);
         FieldRotation<Dfp> r3       = r2.compose(r1, RotationConvention.FRAME_TRANSFORM);
-        FieldRotation<Dfp> r3Double = r2.compose(new Rotation(r1.getQ0().getReal(),
-                                                      r1.getQ1().getReal(),
-                                                      r1.getQ2().getReal(),
-                                                      r1.getQ3().getReal(),
-                                                      false),
+        FieldRotation<Dfp> r3Double = r2.compose(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                       r1.getQ1().getReal(),
+                                                                       r1.getQ2().getReal(),
+                                                                       r1.getQ3().getReal()),
                                                  RotationConvention.FRAME_TRANSFORM);
         FieldRotation<Dfp> r4 = r1.compose(r2, RotationConvention.VECTOR_OPERATOR);
         Assert.assertEquals(0.0, FieldRotation.distance(r3, r4).getReal(), 1.0e-15);
@@ -721,11 +718,10 @@
                                                        createAngle(0.3),
                                                        RotationConvention.VECTOR_OPERATOR);
         FieldRotation<Dfp> r3 = r2.applyInverseTo(r1);
-        FieldRotation<Dfp> r3Double = r2.applyInverseTo(new Rotation(r1.getQ0().getReal(),
-                                                             r1.getQ1().getReal(),
-                                                             r1.getQ2().getReal(),
-                                                             r1.getQ3().getReal(),
-                                                             false));
+        FieldRotation<Dfp> r3Double = r2.applyInverseTo(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                              r1.getQ1().getReal(),
+                                                                              r1.getQ2().getReal(),
+                                                                              r1.getQ3().getReal()));
 
         for (double x = -0.9; x < 0.9; x += 0.2) {
             for (double y = -0.9; y < 0.9; y += 0.2) {
@@ -749,11 +745,10 @@
                                                        createAngle(0.3),
                                                        RotationConvention.VECTOR_OPERATOR);
         FieldRotation<Dfp> r3 = r2.composeInverse(r1, RotationConvention.VECTOR_OPERATOR);
-        FieldRotation<Dfp> r3Double = r2.composeInverse(new Rotation(r1.getQ0().getReal(),
-                                                             r1.getQ1().getReal(),
-                                                             r1.getQ2().getReal(),
-                                                             r1.getQ3().getReal(),
-                                                             false),
+        FieldRotation<Dfp> r3Double = r2.composeInverse(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                              r1.getQ1().getReal(),
+                                                                              r1.getQ2().getReal(),
+                                                                              r1.getQ3().getReal()),
                                                         RotationConvention.VECTOR_OPERATOR);
 
         for (double x = -0.9; x < 0.9; x += 0.2) {
@@ -778,11 +773,10 @@
                                                        createAngle(0.3),
                                                        RotationConvention.FRAME_TRANSFORM);
         FieldRotation<Dfp> r3 = r2.composeInverse(r1, RotationConvention.FRAME_TRANSFORM);
-        FieldRotation<Dfp> r3Double = r2.composeInverse(new Rotation(r1.getQ0().getReal(),
-                                                             r1.getQ1().getReal(),
-                                                             r1.getQ2().getReal(),
-                                                             r1.getQ3().getReal(),
-                                                             false),
+        FieldRotation<Dfp> r3Double = r2.composeInverse(QuaternionRotation.of(r1.getQ0().getReal(),
+                                                                              r1.getQ1().getReal(),
+                                                                              r1.getQ2().getReal(),
+                                                                              r1.getQ3().getReal()),
                                                         RotationConvention.FRAME_TRANSFORM);
         FieldRotation<Dfp> r4 = r1.revert().composeInverse(r2.revert(), RotationConvention.VECTOR_OPERATOR);
         Assert.assertEquals(0.0, FieldRotation.distance(r3, r4).getReal(), 1.0e-15);
@@ -816,7 +810,7 @@
                         FieldVector3D<Dfp> uds   = createVector(x, y, z);
                         FieldVector3D<Dfp> ruds  = r.applyTo(uds);
                         FieldVector3D<Dfp> rIuds = r.applyInverseTo(uds);
-                        Cartesian3D   u     = new Cartesian3D(x, y, z);
+                        Vector3D u = Vector3D.of(x, y, z);
                         FieldVector3D<Dfp> ru    = r.applyTo(u);
                         FieldVector3D<Dfp> rIu   = r.applyInverseTo(u);
                         Dfp[] ruArray = new Dfp[3];
@@ -831,7 +825,6 @@
                 }
             }
         }
-
     }
 
     @Test
@@ -842,13 +835,14 @@
         UnitSphereSampler g = new UnitSphereSampler(3, random);
         for (int i = 0; i < 10; ++i) {
             double[] unit1 = g.nextVector();
-            Rotation r1 = new Rotation(new Cartesian3D(unit1[0], unit1[1], unit1[2]),
-                                      random.nextDouble(), RotationConvention.VECTOR_OPERATOR);
-            FieldRotation<Dfp> r1Prime = new FieldRotation<>(field.newDfp(r1.getQ0()),
-                                                                field.newDfp(r1.getQ1()),
-                                                                field.newDfp(r1.getQ2()),
-                                                                field.newDfp(r1.getQ3()),
-                                                                false);
+            QuaternionRotation r1 = QuaternionRotation.of(random.nextDouble(),
+                                                          unit1[0], unit1[1], unit1[2]);
+            final Quaternion r1Quat = r1.getQuaternion();
+            FieldRotation<Dfp> r1Prime = new FieldRotation<>(field.newDfp(r1Quat.getW()),
+                                                             field.newDfp(r1Quat.getX()),
+                                                             field.newDfp(r1Quat.getY()),
+                                                             field.newDfp(r1Quat.getZ()),
+                                                             false);
             double[] unit2 = g.nextVector();
             FieldRotation<Dfp> r2 = new FieldRotation<>(createVector(unit2[0], unit2[1], unit2[2]),
                                                            createAngle(random.nextDouble()),
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldVector3DTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldVector3DTest.java
index e3d0123..95ee47a 100644
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldVector3DTest.java
+++ b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FieldVector3DTest.java
@@ -22,11 +22,11 @@
 import java.text.NumberFormat;
 import java.util.Locale;
 
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.math4.analysis.differentiation.DerivativeStructure;
 import org.apache.commons.math4.exception.DimensionMismatchException;
 import org.apache.commons.math4.exception.MathArithmeticException;
 import org.apache.commons.math4.geometry.euclidean.threed.FieldVector3D;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
 import org.apache.commons.rng.UniformRandomProvider;
 import org.apache.commons.rng.simple.RandomSource;
 import org.apache.commons.math4.util.FastMath;
@@ -59,7 +59,7 @@
                                    createVector(1, 0,  0, 4)),
                                    2, 0, 0, 2, 0, 0, 1, 0, 2, 0, 0, 0, 0, 2, 0);
         checkVector(new FieldVector3D<>(new DerivativeStructure(4, 1, 3,  2.0),
-                                   new Cartesian3D(1, 0,  0)),
+                                   Vector3D.of(1, 0,  0)),
                                    2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0);
 
         checkVector(new FieldVector3D<>(2, createVector(1, 0,  0, 3),
@@ -71,9 +71,9 @@
                                    createVector(0, 0, -1, 4)),
                                    2, 0, 3, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, -1, -1);
         checkVector(new FieldVector3D<>(new DerivativeStructure(4, 1, 3,  2.0),
-                                   new Cartesian3D(1, 0,  0),
+                                   Vector3D.of(1, 0,  0),
                                    new DerivativeStructure(4, 1, 3, -3.0),
-                                   new Cartesian3D(0, 0, -1)),
+                                   Vector3D.of(0, 0, -1)),
                                    2, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1);
 
         checkVector(new FieldVector3D<>(2, createVector(1, 0, 0, 3),
@@ -88,11 +88,11 @@
                                    createVector(0, 0, -1, 4)),
                                    2, 5, 3, 4, 0, 0, 1, 0, 4, 0, 1, 0, 0, 4, -1);
         checkVector(new FieldVector3D<>(new DerivativeStructure(4, 1, 3,  2.0),
-                                   new Cartesian3D(1, 0,  0),
+                                   Vector3D.of(1, 0,  0),
                                    new DerivativeStructure(4, 1, 3,  5.0),
-                                   new Cartesian3D(0, 1,  0),
+                                   Vector3D.of(0, 1,  0),
                                    new DerivativeStructure(4, 1, 3, -3.0),
-                                   new Cartesian3D(0, 0, -1)),
+                                   Vector3D.of(0, 0, -1)),
                                    2, 5, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, -1);
 
         checkVector(new FieldVector3D<>(2, createVector(1, 0, 0, 3),
@@ -110,13 +110,13 @@
                                    createVector(0, 0, -1, 4)),
                                    2, 0, 3, 9, 0, 0, 1, 0, 9, 0, 0, 0, 0, 9, -1);
         checkVector(new FieldVector3D<>(new DerivativeStructure(4, 1, 3,  2.0),
-                                   new Cartesian3D(1, 0,  0),
+                                   Vector3D.of(1, 0,  0),
                                    new DerivativeStructure(4, 1, 3,  5.0),
-                                   new Cartesian3D(0, 1,  0),
+                                   Vector3D.of(0, 1,  0),
                                    new DerivativeStructure(4, 1, 3,  5.0),
-                                   new Cartesian3D(0, -1,  0),
+                                   Vector3D.of(0, -1,  0),
                                    new DerivativeStructure(4, 1, 3, -3.0),
-                                   new Cartesian3D(0, 0, -1)),
+                                   Vector3D.of(0, 0, -1)),
                                    2, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1);
 
         checkVector(new FieldVector3D<>(new DerivativeStructure[] {
@@ -178,9 +178,8 @@
 
     @Test
     public void testToString() {
-        Assert.assertEquals("{3; 2; 1}", createVector(3, 2, 1, 3).toString());
-        NumberFormat format = new DecimalFormat("0.000", new DecimalFormatSymbols(Locale.US));
-        Assert.assertEquals("{3.000; 2.000; 1.000}", createVector(3, 2, 1, 3).toString(format));
+        Assert.assertEquals(Vector3D.of(3, 2, 1).toString(),
+                            createVector(3, 2, 1, 3).toString());
     }
 
     @Test(expected=DimensionMismatchException.class)
@@ -270,12 +269,12 @@
         Assert.assertEquals(0, distance.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(0, distance.getPartialDerivative(0, 1, 0), 1.0e-12);
         Assert.assertEquals(0, distance.getPartialDerivative(0, 0, 1), 1.0e-12);
-        distance = FieldVector3D.distance1(v1, new Cartesian3D(-4, 2, 0));
+        distance = FieldVector3D.distance1(v1, Vector3D.of(-4, 2, 0));
         Assert.assertEquals(12.0, distance.getReal(), 1.0e-12);
         Assert.assertEquals( 1, distance.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(-1, distance.getPartialDerivative(0, 1, 0), 1.0e-12);
         Assert.assertEquals( 1, distance.getPartialDerivative(0, 0, 1), 1.0e-12);
-        distance = FieldVector3D.distance1(new Cartesian3D(-4, 2, 0), v1);
+        distance = FieldVector3D.distance1(Vector3D.of(-4, 2, 0), v1);
         Assert.assertEquals(12.0, distance.getReal(), 1.0e-12);
         Assert.assertEquals( 1, distance.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(-1, distance.getPartialDerivative(0, 1, 0), 1.0e-12);
@@ -292,12 +291,12 @@
         Assert.assertEquals(0, distance.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(0, distance.getPartialDerivative(0, 1, 0), 1.0e-12);
         Assert.assertEquals(0, distance.getPartialDerivative(0, 0, 1), 1.0e-12);
-        distance = FieldVector3D.distance(v1, new Cartesian3D(-4, 2, 0));
+        distance = FieldVector3D.distance(v1, Vector3D.of(-4, 2, 0));
         Assert.assertEquals(FastMath.sqrt(50), distance.getReal(), 1.0e-12);
         Assert.assertEquals( 5 / FastMath.sqrt(50), distance.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(-4 / FastMath.sqrt(50), distance.getPartialDerivative(0, 1, 0), 1.0e-12);
         Assert.assertEquals( 3 / FastMath.sqrt(50), distance.getPartialDerivative(0, 0, 1), 1.0e-12);
-        distance = FieldVector3D.distance(new Cartesian3D(-4, 2, 0), v1);
+        distance = FieldVector3D.distance(Vector3D.of(-4, 2, 0), v1);
         Assert.assertEquals(FastMath.sqrt(50), distance.getReal(), 1.0e-12);
         Assert.assertEquals( 5 / FastMath.sqrt(50), distance.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(-4 / FastMath.sqrt(50), distance.getPartialDerivative(0, 1, 0), 1.0e-12);
@@ -314,12 +313,12 @@
         Assert.assertEquals(0, distanceSq.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(0, distanceSq.getPartialDerivative(0, 1, 0), 1.0e-12);
         Assert.assertEquals(0, distanceSq.getPartialDerivative(0, 0, 1), 1.0e-12);
-        distanceSq = FieldVector3D.distanceSq(v1, new Cartesian3D(-4, 2, 0));
+        distanceSq = FieldVector3D.distanceSq(v1, Vector3D.of(-4, 2, 0));
         Assert.assertEquals(50.0, distanceSq.getReal(), 1.0e-12);
         Assert.assertEquals(10, distanceSq.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(-8, distanceSq.getPartialDerivative(0, 1, 0), 1.0e-12);
         Assert.assertEquals( 6, distanceSq.getPartialDerivative(0, 0, 1), 1.0e-12);
-        distanceSq = FieldVector3D.distanceSq(new Cartesian3D(-4, 2, 0), v1);
+        distanceSq = FieldVector3D.distanceSq(Vector3D.of(-4, 2, 0), v1);
         Assert.assertEquals(50.0, distanceSq.getReal(), 1.0e-12);
         Assert.assertEquals(10, distanceSq.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(-8, distanceSq.getPartialDerivative(0, 1, 0), 1.0e-12);
@@ -336,12 +335,12 @@
         Assert.assertEquals(0, distance.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(0, distance.getPartialDerivative(0, 1, 0), 1.0e-12);
         Assert.assertEquals(0, distance.getPartialDerivative(0, 0, 1), 1.0e-12);
-        distance = FieldVector3D.distanceInf(v1, new Cartesian3D(-4, 2, 0));
+        distance = FieldVector3D.distanceInf(v1, Vector3D.of(-4, 2, 0));
         Assert.assertEquals(5.0, distance.getReal(), 1.0e-12);
         Assert.assertEquals(1, distance.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(0, distance.getPartialDerivative(0, 1, 0), 1.0e-12);
         Assert.assertEquals(0, distance.getPartialDerivative(0, 0, 1), 1.0e-12);
-        distance = FieldVector3D.distanceInf(new Cartesian3D(-4, 2, 0), v1);
+        distance = FieldVector3D.distanceInf(Vector3D.of(-4, 2, 0), v1);
         Assert.assertEquals(5.0, distance.getReal(), 1.0e-12);
         Assert.assertEquals(1, distance.getPartialDerivative(1, 0, 0), 1.0e-12);
         Assert.assertEquals(0, distance.getPartialDerivative(0, 1, 0), 1.0e-12);
@@ -368,22 +367,22 @@
                             1.0e-12);
 
         Assert.assertEquals(5.0,
-                            FieldVector3D.distanceInf(createVector( 1, -2, 3, 3), new Cartesian3D(-4,  2, 0)).getReal(),
+                            FieldVector3D.distanceInf(createVector( 1, -2, 3, 3), Vector3D.of(-4,  2, 0)).getReal(),
                             1.0e-12);
         Assert.assertEquals(5.0,
-                            FieldVector3D.distanceInf(createVector( 1, 3, -2, 3), new Cartesian3D(-4, 0,  2)).getReal(),
+                            FieldVector3D.distanceInf(createVector( 1, 3, -2, 3), Vector3D.of(-4, 0,  2)).getReal(),
                             1.0e-12);
         Assert.assertEquals(5.0,
-                            FieldVector3D.distanceInf(createVector(-2,  1, 3, 3), new Cartesian3D( 2, -4, 0)).getReal(),
+                            FieldVector3D.distanceInf(createVector(-2,  1, 3, 3), Vector3D.of( 2, -4, 0)).getReal(),
                             1.0e-12);
         Assert.assertEquals(5.0,
-                            FieldVector3D.distanceInf(createVector(-2, 3,  1, 3), new Cartesian3D( 2, 0, -4)).getReal(),
+                            FieldVector3D.distanceInf(createVector(-2, 3,  1, 3), Vector3D.of( 2, 0, -4)).getReal(),
                             1.0e-12);
         Assert.assertEquals(5.0,
-                            FieldVector3D.distanceInf(createVector(3, -2,  1, 3), new Cartesian3D(0,  2, -4)).getReal(),
+                            FieldVector3D.distanceInf(createVector(3, -2,  1, 3), Vector3D.of(0,  2, -4)).getReal(),
                             1.0e-12);
         Assert.assertEquals(5.0,
-                            FieldVector3D.distanceInf(createVector(3,  1, -2, 3), new Cartesian3D(0, -4,  2)).getReal(),
+                            FieldVector3D.distanceInf(createVector(3,  1, -2, 3), Vector3D.of(0, -4,  2)).getReal(),
                             1.0e-12);
 
     }
@@ -396,10 +395,10 @@
         checkVector(v1, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
         checkVector(v2.subtract(v1), -7, -6, -5, 1, 0, 0, 0, 1, 0, 0, 0, 1);
-        checkVector(v2.subtract(new Cartesian3D(4, 4, 4)), -7, -6, -5, 1, 0, 0, 0, 1, 0, 0, 0, 1);
+        checkVector(v2.subtract(Vector3D.of(4, 4, 4)), -7, -6, -5, 1, 0, 0, 0, 1, 0, 0, 0, 1);
         checkVector(v2.subtract(3, v1), -15, -14, -13, 1, 0, 0, 0, 1, 0, 0, 0, 1);
-        checkVector(v2.subtract(3, new Cartesian3D(4, 4, 4)), -15, -14, -13, 1, 0, 0, 0, 1, 0, 0, 0, 1);
-        checkVector(v2.subtract(new DerivativeStructure(3, 1, 2, 3), new Cartesian3D(4, 4, 4)),
+        checkVector(v2.subtract(3, Vector3D.of(4, 4, 4)), -15, -14, -13, 1, 0, 0, 0, 1, 0, 0, 0, 1);
+        checkVector(v2.subtract(new DerivativeStructure(3, 1, 2, 3), Vector3D.of(4, 4, 4)),
                     -15, -14, -13, 1, 0, -4, 0, 1, -4, 0, 0, -3);
 
         checkVector(createVector(1, 2, 3, 4).subtract(new DerivativeStructure(4, 1, 3, 5.0),
@@ -419,10 +418,10 @@
         checkVector(v1, -2, 0, 2, 2, 0, 0, 0, 2, 0, 0, 0, 2);
 
         checkVector(v2.add(v1), -5, -2, 1, 3, 0, 0, 0, 3, 0, 0, 0, 3);
-        checkVector(v2.add(new Cartesian3D(-2, 0, 2)), -5, -2, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1);
+        checkVector(v2.add(Vector3D.of(-2, 0, 2)), -5, -2, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1);
         checkVector(v2.add(3, v1), -9, -2, 5, 7, 0, 0, 0, 7, 0, 0, 0, 7);
-        checkVector(v2.add(3, new Cartesian3D(-2, 0, 2)), -9, -2, 5, 1, 0, 0, 0, 1, 0, 0, 0, 1);
-        checkVector(v2.add(new DerivativeStructure(3, 1, 2, 3), new Cartesian3D(-2, 0, 2)),
+        checkVector(v2.add(3, Vector3D.of(-2, 0, 2)), -9, -2, 5, 1, 0, 0, 0, 1, 0, 0, 0, 1);
+        checkVector(v2.add(new DerivativeStructure(3, 1, 2, 3), Vector3D.of(-2, 0, 2)),
                     -9, -2, 5, 1, 0, -2, 0, 1, 0, 0, 0, 3);
 
         checkVector(createVector(1, 2, 3, 4).add(new DerivativeStructure(4, 1, 3, 5.0),
@@ -508,7 +507,7 @@
         Assert.assertTrue(FastMath.abs(FieldVector3D.angle(v1.toVector3D(), v2).getReal() - 1.2) < 1.0e-12);
 
         try {
-            FieldVector3D.angle(v1, Cartesian3D.ZERO);
+            FieldVector3D.angle(v1, Vector3D.ZERO);
             Assert.fail("an exception should have been thrown");
         } catch (MathArithmeticException mae) {
             // expected
@@ -605,7 +604,7 @@
 
             FieldVector3D<DerivativeStructure> uds = createVector(ux, uy, uz, 3);
             FieldVector3D<DerivativeStructure> vds = createVector(vx, vy, vz, 3);
-            Cartesian3D v = new Cartesian3D(vx, vy, vz);
+            Vector3D v = Vector3D.of(vx, vy, vz);
 
             DerivativeStructure sAccurate = FieldVector3D.dotProduct(uds, vds);
             Assert.assertEquals(sNaive, sAccurate.getReal(), 2.5e-16 * sNaive);
@@ -658,11 +657,11 @@
             double vx = random.nextDouble();
             double vy = random.nextDouble();
             double vz = random.nextDouble();
-            Cartesian3D cNaive = new Cartesian3D(uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx);
+            Vector3D cNaive = Vector3D.of(uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx);
 
             FieldVector3D<DerivativeStructure> uds = createVector(ux, uy, uz, 3);
             FieldVector3D<DerivativeStructure> vds = createVector(vx, vy, vz, 3);
-            Cartesian3D v = new Cartesian3D(vx, vy, vz);
+            Vector3D v = Vector3D.of(vx, vy, vz);
 
             checkVector(FieldVector3D.crossProduct(uds, vds),
                         cNaive.getX(), cNaive.getY(), cNaive.getZ(),
@@ -675,7 +674,6 @@
                           0,  vz, -vy,
                         -vz,   0,  vx,
                          vy, -vx,   0);
-
         }
     }
 
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FrenchVector3DFormatTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FrenchVector3DFormatTest.java
deleted file mode 100644
index 42dd7b6..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/FrenchVector3DFormatTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.util.Locale;
-
-
-public class FrenchVector3DFormatTest extends Vector3DFormatAbstractTest {
-
-    @Override
-    protected char getDecimalCharacter() {
-        return ',';
-    }
-
-    @Override
-    protected Locale getLocale() {
-        return Locale.FRENCH;
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/LineTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/LineTest.java
deleted file mode 100644
index 6cd4962..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/LineTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * 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 org.apache.commons.math4.exception.MathArithmeticException;
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.geometry.euclidean.threed.Line;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.util.FastMath;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class LineTest {
-
-    @Test
-    public void testContains() throws MathIllegalArgumentException, MathArithmeticException {
-        Cartesian3D p1 = new Cartesian3D(0, 0, 1);
-        Line l = new Line(p1, new Cartesian3D(0, 0, 2), 1.0e-10);
-        Assert.assertTrue(l.contains(p1));
-        Assert.assertTrue(l.contains(new Cartesian3D(1.0, p1, 0.3, l.getDirection())));
-        Cartesian3D u = l.getDirection().orthogonal();
-        Cartesian3D v = Cartesian3D.crossProduct(l.getDirection(), u);
-        for (double alpha = 0; alpha < 2 * FastMath.PI; alpha += 0.3) {
-            Assert.assertTrue(! l.contains(p1.add(new Cartesian3D(FastMath.cos(alpha), u,
-                                                               FastMath.sin(alpha), v))));
-        }
-    }
-
-    @Test
-    public void testSimilar() throws MathIllegalArgumentException, MathArithmeticException {
-        Cartesian3D p1  = new Cartesian3D (1.2, 3.4, -5.8);
-        Cartesian3D p2  = new Cartesian3D (3.4, -5.8, 1.2);
-        Line     lA  = new Line(p1, p2, 1.0e-10);
-        Line     lB  = new Line(p2, p1, 1.0e-10);
-        Assert.assertTrue(lA.isSimilarTo(lB));
-        Assert.assertTrue(! lA.isSimilarTo(new Line(p1, p1.add(lA.getDirection().orthogonal()), 1.0e-10)));
-    }
-
-    @Test
-    public void testPointDistance() throws MathIllegalArgumentException {
-        Line l = new Line(new Cartesian3D(0, 1, 1), new Cartesian3D(0, 2, 2), 1.0e-10);
-        Assert.assertEquals(FastMath.sqrt(3.0 / 2.0), l.distance(new Cartesian3D(1, 0, 1)), 1.0e-10);
-        Assert.assertEquals(0, l.distance(new Cartesian3D(0, -4, -4)), 1.0e-10);
-    }
-
-    @Test
-    public void testLineDistance() throws MathIllegalArgumentException {
-        Line l = new Line(new Cartesian3D(0, 1, 1), new Cartesian3D(0, 2, 2), 1.0e-10);
-        Assert.assertEquals(1.0,
-                            l.distance(new Line(new Cartesian3D(1, 0, 1), new Cartesian3D(1, 0, 2), 1.0e-10)),
-                            1.0e-10);
-        Assert.assertEquals(0.5,
-                            l.distance(new Line(new Cartesian3D(-0.5, 0, 0), new Cartesian3D(-0.5, -1, -1), 1.0e-10)),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.distance(l),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.distance(new Line(new Cartesian3D(0, -4, -4), new Cartesian3D(0, -5, -5), 1.0e-10)),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.distance(new Line(new Cartesian3D(0, -4, -4), new Cartesian3D(0, -3, -4), 1.0e-10)),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.distance(new Line(new Cartesian3D(0, -4, -4), new Cartesian3D(1, -4, -4), 1.0e-10)),
-                            1.0e-10);
-        Assert.assertEquals(FastMath.sqrt(8),
-                            l.distance(new Line(new Cartesian3D(0, -4, 0), new Cartesian3D(1, -4, 0), 1.0e-10)),
-                            1.0e-10);
-    }
-
-    @Test
-    public void testClosest() throws MathIllegalArgumentException {
-        Line l = new Line(new Cartesian3D(0, 1, 1), new Cartesian3D(0, 2, 2), 1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(new Cartesian3D(1, 0, 1), new Cartesian3D(1, 0, 2), 1.0e-10)).distance(new Cartesian3D(0, 0, 0)),
-                            1.0e-10);
-        Assert.assertEquals(0.5,
-                            l.closestPoint(new Line(new Cartesian3D(-0.5, 0, 0), new Cartesian3D(-0.5, -1, -1), 1.0e-10)).distance(new Cartesian3D(-0.5, 0, 0)),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.closestPoint(l).distance(new Cartesian3D(0, 0, 0)),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(new Cartesian3D(0, -4, -4), new Cartesian3D(0, -5, -5), 1.0e-10)).distance(new Cartesian3D(0, 0, 0)),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(new Cartesian3D(0, -4, -4), new Cartesian3D(0, -3, -4), 1.0e-10)).distance(new Cartesian3D(0, -4, -4)),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(new Cartesian3D(0, -4, -4), new Cartesian3D(1, -4, -4), 1.0e-10)).distance(new Cartesian3D(0, -4, -4)),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(new Cartesian3D(0, -4, 0), new Cartesian3D(1, -4, 0), 1.0e-10)).distance(new Cartesian3D(0, -2, -2)),
-                            1.0e-10);
-    }
-
-    @Test
-    public void testIntersection() throws MathIllegalArgumentException {
-        Line l = new Line(new Cartesian3D(0, 1, 1), new Cartesian3D(0, 2, 2), 1.0e-10);
-        Assert.assertNull(l.intersection(new Line(new Cartesian3D(1, 0, 1), new Cartesian3D(1, 0, 2), 1.0e-10)));
-        Assert.assertNull(l.intersection(new Line(new Cartesian3D(-0.5, 0, 0), new Cartesian3D(-0.5, -1, -1), 1.0e-10)));
-        Assert.assertEquals(0.0,
-                            l.intersection(l).distance(new Cartesian3D(0, 0, 0)),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.intersection(new Line(new Cartesian3D(0, -4, -4), new Cartesian3D(0, -5, -5), 1.0e-10)).distance(new Cartesian3D(0, 0, 0)),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.intersection(new Line(new Cartesian3D(0, -4, -4), new Cartesian3D(0, -3, -4), 1.0e-10)).distance(new Cartesian3D(0, -4, -4)),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            l.intersection(new Line(new Cartesian3D(0, -4, -4), new Cartesian3D(1, -4, -4), 1.0e-10)).distance(new Cartesian3D(0, -4, -4)),
-                            1.0e-10);
-        Assert.assertNull(l.intersection(new Line(new Cartesian3D(0, -4, 0), new Cartesian3D(1, -4, 0), 1.0e-10)));
-    }
-
-    @Test
-    public void testRevert() {
-
-        // setup
-        Line line = new Line(new Cartesian3D(1653345.6696423641, 6170370.041579291, 90000),
-                             new Cartesian3D(1650757.5050732433, 6160710.879908984, 0.9),
-                             1.0e-10);
-        Cartesian3D expected = line.getDirection().negate();
-
-        // action
-        Line reverted = line.revert();
-
-        // verify
-        Assert.assertArrayEquals(expected.toArray(), reverted.getDirection().toArray(), 0);
-
-    }
-
-}
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
deleted file mode 100644
index 4d13f0b..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/OBJWriter.java
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * 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] });
-            }
-        }
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PLYParser.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PLYParser.java
deleted file mode 100644
index a696a92..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PLYParser.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * 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.BufferedReader;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.StringTokenizer;
-
-import org.apache.commons.numbers.core.Precision;
-
-/** This class is a small and incomplete parser for PLY files.
- * <p>
- * This parser is only intended for test purposes, it does not
- * parse the full header, it does not handle all properties,
- * it has rudimentary error handling.
- * </p>
- * @since 3.5
- */
-public class PLYParser {
-
-    /** Parsed vertices. */
-    private Cartesian3D[] vertices;
-
-    /** Parsed faces. */
-    private int[][] faces;
-
-    /** Reader for PLY data. */
-    private BufferedReader br;
-
-    /** Last parsed line. */
-    private String line;
-
-    /** Simple constructor.
-     * @param stream stream to parse (closing it remains caller responsibility)
-     * @exception IOException if stream cannot be read
-     * @exception ParseException if stream content cannot be parsed
-     */
-    public PLYParser(final InputStream stream)
-        throws IOException, ParseException {
-
-        try {
-            br = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
-
-            // parse the header
-            List<Field> fields = parseNextLine();
-            if (fields.size() != 1 || fields.get(0).getToken() != Token.PLY) {
-                complain();
-            }
-
-            boolean parsing       = true;
-            int nbVertices        = -1;
-            int nbFaces           = -1;
-            int xIndex            = -1;
-            int yIndex            = -1;
-            int zIndex            = -1;
-            int vPropertiesNumber = -1;
-            boolean inVertexElt   = false;
-            boolean inFaceElt     = false;
-            while (parsing) {
-                fields = parseNextLine();
-                if (fields.size() < 1) {
-                    complain();
-                }
-                switch (fields.get(0).getToken()) {
-                    case FORMAT:
-                        if (fields.size() != 3 ||
-                        fields.get(1).getToken() != Token.ASCII ||
-                        fields.get(2).getToken() != Token.UNKNOWN ||
-                        !Precision.equals(Double.parseDouble(fields.get(2).getValue()), 1.0, 0.001)) {
-                            complain();
-                        }
-                        inVertexElt = false;
-                        inFaceElt   = false;
-                        break;
-                    case COMMENT:
-                        // we just ignore this line
-                        break;
-                    case ELEMENT:
-                        if (fields.size() != 3 ||
-                        (fields.get(1).getToken() != Token.VERTEX && fields.get(1).getToken() != Token.FACE) ||
-                        fields.get(2).getToken() != Token.UNKNOWN) {
-                            complain();
-                        }
-                        if (fields.get(1).getToken() == Token.VERTEX) {
-                            nbVertices  = Integer.parseInt(fields.get(2).getValue());
-                            inVertexElt = true;
-                            inFaceElt   = false;
-                        } else {
-                            nbFaces     = Integer.parseInt(fields.get(2).getValue());
-                            inVertexElt = false;
-                            inFaceElt   = true;
-                        }
-                        break;
-                    case PROPERTY:
-                        if (inVertexElt) {
-                            ++vPropertiesNumber;
-                            if (fields.size() != 3 ||
-                                (fields.get(1).getToken() != Token.CHAR   &&
-                                 fields.get(1).getToken() != Token.UCHAR  &&
-                                 fields.get(1).getToken() != Token.SHORT  &&
-                                 fields.get(1).getToken() != Token.USHORT &&
-                                 fields.get(1).getToken() != Token.INT    &&
-                                 fields.get(1).getToken() != Token.UINT   &&
-                                 fields.get(1).getToken() != Token.FLOAT  &&
-                                 fields.get(1).getToken() != Token.DOUBLE)) {
-                                complain();
-                            }
-                            if (fields.get(2).getToken() == Token.X) {
-                                xIndex = vPropertiesNumber;
-                            }else if (fields.get(2).getToken() == Token.Y) {
-                                yIndex = vPropertiesNumber;
-                            }else if (fields.get(2).getToken() == Token.Z) {
-                                zIndex = vPropertiesNumber;
-                            }
-                        } else if (inFaceElt) {
-                            if (fields.size() != 5 ||
-                                fields.get(1).getToken()  != Token.LIST   &&
-                                (fields.get(2).getToken() != Token.CHAR   &&
-                                 fields.get(2).getToken() != Token.UCHAR  &&
-                                 fields.get(2).getToken() != Token.SHORT  &&
-                                 fields.get(2).getToken() != Token.USHORT &&
-                                 fields.get(2).getToken() != Token.INT    &&
-                                 fields.get(2).getToken() != Token.UINT) ||
-                                (fields.get(3).getToken() != Token.CHAR   &&
-                                 fields.get(3).getToken() != Token.UCHAR  &&
-                                 fields.get(3).getToken() != Token.SHORT  &&
-                                 fields.get(3).getToken() != Token.USHORT &&
-                                 fields.get(3).getToken() != Token.INT    &&
-                                 fields.get(3).getToken() != Token.UINT) ||
-                                 fields.get(4).getToken() != Token.VERTEX_INDICES) {
-                                complain();
-                            }
-                        } else {
-                            complain();
-                        }
-                        break;
-                    case END_HEADER:
-                        inVertexElt = false;
-                        inFaceElt   = false;
-                        parsing     = false;
-                        break;
-                    default:
-                        throw new ParseException("unable to parse line: " + line, 0);
-                }
-            }
-            ++vPropertiesNumber;
-
-            // parse vertices
-            vertices = new Cartesian3D[nbVertices];
-            for (int i = 0; i < nbVertices; ++i) {
-                fields = parseNextLine();
-                if (fields.size() != vPropertiesNumber ||
-                    fields.get(xIndex).getToken() != Token.UNKNOWN ||
-                    fields.get(yIndex).getToken() != Token.UNKNOWN ||
-                    fields.get(zIndex).getToken() != Token.UNKNOWN) {
-                    complain();
-                }
-                vertices[i] = new Cartesian3D(Double.parseDouble(fields.get(xIndex).getValue()),
-                                           Double.parseDouble(fields.get(yIndex).getValue()),
-                                           Double.parseDouble(fields.get(zIndex).getValue()));
-            }
-
-            // parse faces
-            faces = new int[nbFaces][];
-            for (int i = 0; i < nbFaces; ++i) {
-                fields = parseNextLine();
-                if (fields.isEmpty() ||
-                    fields.size() != (Integer.parseInt(fields.get(0).getValue()) + 1)) {
-                    complain();
-                }
-                faces[i] = new int[fields.size() - 1];
-                for (int j = 0; j < faces[i].length; ++j) {
-                    faces[i][j] = Integer.parseInt(fields.get(j + 1).getValue());
-                }
-            }
-
-        } catch (NumberFormatException nfe) {
-            complain();
-        }
-    }
-
-    /** Complain about a bad line.
-     * @exception ParseException always thrown
-     */
-    private void complain() throws ParseException {
-        throw new ParseException("unable to parse line: " + line, 0);
-    }
-
-    /** Parse next line.
-     * @return parsed fields
-     * @exception IOException if stream cannot be read
-     * @exception ParseException if the line does not contain the expected number of fields
-     */
-    private List<Field> parseNextLine()
-        throws IOException, ParseException {
-        final List<Field> fields = new ArrayList<>();
-        line = br.readLine();
-        if (line == null) {
-            throw new EOFException();
-        }
-        final StringTokenizer tokenizer = new StringTokenizer(line);
-        while (tokenizer.hasMoreTokens()) {
-            fields.add(new Field(tokenizer.nextToken()));
-        }
-        return fields;
-    }
-
-    /** Get the parsed vertices.
-     * @return parsed vertices
-     */
-    public List<Cartesian3D> getVertices() {
-        return Arrays.asList(vertices);
-    }
-
-    /** Get the parsed faces.
-     * @return parsed faces
-     */
-    public List<int[]> getFaces() {
-        return Arrays.asList(faces);
-    }
-
-    /** Tokens from PLY files. */
-    private static enum Token {
-        PLY, FORMAT, ASCII, BINARY_BIG_ENDIAN, BINARY_LITTLE_ENDIAN,
-        COMMENT, ELEMENT, VERTEX, FACE, PROPERTY, LIST, OBJ_INFO,
-        CHAR, UCHAR, SHORT, USHORT, INT, UINT, FLOAT, DOUBLE,
-        X, Y, Z, VERTEX_INDICES, END_HEADER, UNKNOWN;
-    }
-
-    /** Parsed line fields. */
-    private static class Field {
-
-        /** Token. */
-        private final Token token;
-
-        /** Value. */
-        private final String value;
-
-        /** Simple constructor.
-         * @param value field value
-         */
-        public Field(final String value) {
-            Token parsedToken = null;
-            try {
-                parsedToken = Token.valueOf(value.toUpperCase());
-            } catch (IllegalArgumentException iae) {
-                parsedToken = Token.UNKNOWN;
-            }
-            this.token = parsedToken;
-            this.value = value;
-        }
-
-        /** Get the recognized token.
-         * @return recognized token
-         */
-        public Token getToken() {
-            return token;
-        }
-
-        /** Get the field value.
-         * @return field value
-         */
-        public String getValue() {
-            return value;
-        }
-
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PlaneTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PlaneTest.java
deleted file mode 100644
index 54c975e..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PlaneTest.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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 org.apache.commons.math4.exception.MathArithmeticException;
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.geometry.euclidean.threed.Line;
-import org.apache.commons.math4.geometry.euclidean.threed.Plane;
-import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class PlaneTest {
-
-    @Test
-    public void testContains() throws MathArithmeticException {
-        Plane p = new Plane(new Cartesian3D(0, 0, 1), new Cartesian3D(0, 0, 1), 1.0e-10);
-        Assert.assertTrue(p.contains(new Cartesian3D(0, 0, 1)));
-        Assert.assertTrue(p.contains(new Cartesian3D(17, -32, 1)));
-        Assert.assertTrue(! p.contains(new Cartesian3D(17, -32, 1.001)));
-    }
-
-    @Test
-    public void testOffset() throws MathArithmeticException {
-        Cartesian3D p1 = new Cartesian3D(1, 1, 1);
-        Plane p = new Plane(p1, new Cartesian3D(0.2, 0, 0), 1.0e-10);
-        Assert.assertEquals(-5.0, p.getOffset(new Cartesian3D(-4, 0, 0)), 1.0e-10);
-        Assert.assertEquals(+5.0, p.getOffset(new Cartesian3D(6, 10, -12)), 1.0e-10);
-        Assert.assertEquals(0.3,
-                            p.getOffset(new Cartesian3D(1.0, p1, 0.3, p.getNormal())),
-                            1.0e-10);
-        Assert.assertEquals(-0.3,
-                            p.getOffset(new Cartesian3D(1.0, p1, -0.3, p.getNormal())),
-                            1.0e-10);
-    }
-
-    @Test
-    public void testPoint() throws MathArithmeticException {
-        Plane p = new Plane(new Cartesian3D(2, -3, 1), new Cartesian3D(1, 4, 9), 1.0e-10);
-        Assert.assertTrue(p.contains(p.getOrigin()));
-    }
-
-    @Test
-    public void testThreePoints() throws MathArithmeticException {
-        Cartesian3D p1 = new Cartesian3D(1.2, 3.4, -5.8);
-        Cartesian3D p2 = new Cartesian3D(3.4, -5.8, 1.2);
-        Cartesian3D p3 = new Cartesian3D(-2.0, 4.3, 0.7);
-        Plane    p  = new Plane(p1, p2, p3, 1.0e-10);
-        Assert.assertTrue(p.contains(p1));
-        Assert.assertTrue(p.contains(p2));
-        Assert.assertTrue(p.contains(p3));
-    }
-
-    @Test
-    public void testRotate() throws MathArithmeticException, MathIllegalArgumentException {
-        Cartesian3D p1 = new Cartesian3D(1.2, 3.4, -5.8);
-        Cartesian3D p2 = new Cartesian3D(3.4, -5.8, 1.2);
-        Cartesian3D p3 = new Cartesian3D(-2.0, 4.3, 0.7);
-        Plane    p  = new Plane(p1, p2, p3, 1.0e-10);
-        Cartesian3D oldNormal = p.getNormal();
-
-        p = p.rotate(p2, new Rotation(p2.subtract(p1), 1.7, RotationConvention.VECTOR_OPERATOR));
-        Assert.assertTrue(p.contains(p1));
-        Assert.assertTrue(p.contains(p2));
-        Assert.assertTrue(! p.contains(p3));
-
-        p = p.rotate(p2, new Rotation(oldNormal, 0.1, RotationConvention.VECTOR_OPERATOR));
-        Assert.assertTrue(! p.contains(p1));
-        Assert.assertTrue(p.contains(p2));
-        Assert.assertTrue(! p.contains(p3));
-
-        p = p.rotate(p1, new Rotation(oldNormal, 0.1, RotationConvention.VECTOR_OPERATOR));
-        Assert.assertTrue(! p.contains(p1));
-        Assert.assertTrue(! p.contains(p2));
-        Assert.assertTrue(! p.contains(p3));
-
-    }
-
-    @Test
-    public void testTranslate() throws MathArithmeticException {
-        Cartesian3D p1 = new Cartesian3D(1.2, 3.4, -5.8);
-        Cartesian3D p2 = new Cartesian3D(3.4, -5.8, 1.2);
-        Cartesian3D p3 = new Cartesian3D(-2.0, 4.3, 0.7);
-        Plane    p  = new Plane(p1, p2, p3, 1.0e-10);
-
-        p = p.translate(new Cartesian3D(2.0, p.getU(), -1.5, p.getV()));
-        Assert.assertTrue(p.contains(p1));
-        Assert.assertTrue(p.contains(p2));
-        Assert.assertTrue(p.contains(p3));
-
-        p = p.translate(new Cartesian3D(-1.2, p.getNormal()));
-        Assert.assertTrue(! p.contains(p1));
-        Assert.assertTrue(! p.contains(p2));
-        Assert.assertTrue(! p.contains(p3));
-
-        p = p.translate(new Cartesian3D(+1.2, p.getNormal()));
-        Assert.assertTrue(p.contains(p1));
-        Assert.assertTrue(p.contains(p2));
-        Assert.assertTrue(p.contains(p3));
-
-    }
-
-    @Test
-    public void testIntersection() throws MathArithmeticException, MathIllegalArgumentException {
-        Plane p = new Plane(new Cartesian3D(1, 2, 3), new Cartesian3D(-4, 1, -5), 1.0e-10);
-        Line  l = new Line(new Cartesian3D(0.2, -3.5, 0.7), new Cartesian3D(1.2, -2.5, -0.3), 1.0e-10);
-        Cartesian3D point = p.intersection(l);
-        Assert.assertTrue(p.contains(point));
-        Assert.assertTrue(l.contains(point));
-        Assert.assertNull(p.intersection(new Line(new Cartesian3D(10, 10, 10),
-                                                  new Cartesian3D(10, 10, 10).add(p.getNormal().orthogonal()),
-                                                  1.0e-10)));
-    }
-
-    @Test
-    public void testIntersection2() throws MathArithmeticException {
-        Cartesian3D p1  = new Cartesian3D (1.2, 3.4, -5.8);
-        Cartesian3D p2  = new Cartesian3D (3.4, -5.8, 1.2);
-        Plane    pA  = new Plane(p1, p2, new Cartesian3D (-2.0, 4.3, 0.7), 1.0e-10);
-        Plane    pB  = new Plane(p1, new Cartesian3D (11.4, -3.8, 5.1), p2, 1.0e-10);
-        Line     l   = pA.intersection(pB);
-        Assert.assertTrue(l.contains(p1));
-        Assert.assertTrue(l.contains(p2));
-        Assert.assertNull(pA.intersection(pA));
-    }
-
-    @Test
-    public void testIntersection3() throws MathArithmeticException {
-        Cartesian3D reference = new Cartesian3D (1.2, 3.4, -5.8);
-        Plane p1 = new Plane(reference, new Cartesian3D(1, 3, 3), 1.0e-10);
-        Plane p2 = new Plane(reference, new Cartesian3D(-2, 4, 0), 1.0e-10);
-        Plane p3 = new Plane(reference, new Cartesian3D(7, 0, -4), 1.0e-10);
-        Cartesian3D p = Plane.intersection(p1, p2, p3);
-        Assert.assertEquals(reference.getX(), p.getX(), 1.0e-10);
-        Assert.assertEquals(reference.getY(), p.getY(), 1.0e-10);
-        Assert.assertEquals(reference.getZ(), p.getZ(), 1.0e-10);
-    }
-
-    @Test
-    public void testSimilar() throws MathArithmeticException {
-        Cartesian3D p1  = new Cartesian3D (1.2, 3.4, -5.8);
-        Cartesian3D p2  = new Cartesian3D (3.4, -5.8, 1.2);
-        Cartesian3D p3  = new Cartesian3D (-2.0, 4.3, 0.7);
-        Plane    pA  = new Plane(p1, p2, p3, 1.0e-10);
-        Plane    pB  = new Plane(p1, new Cartesian3D (11.4, -3.8, 5.1), p2, 1.0e-10);
-        Assert.assertTrue(! pA.isSimilarTo(pB));
-        Assert.assertTrue(pA.isSimilarTo(pA));
-        Assert.assertTrue(pA.isSimilarTo(new Plane(p1, p3, p2, 1.0e-10)));
-        Cartesian3D shift = new Cartesian3D(0.3, pA.getNormal());
-        Assert.assertTrue(! pA.isSimilarTo(new Plane(p1.add(shift),
-                                                     p3.add(shift),
-                                                     p2.add(shift),
-                                                     1.0e-10)));
-    }
-
-}
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
deleted file mode 100644
index 4c8d729..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSetTest.java
+++ /dev/null
@@ -1,1511 +0,0 @@
-/*
- * 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.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.lang.reflect.Field;
-import java.text.ParseException;
-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.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.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.junit.Assert;
-import org.junit.Test;
-
-public class PolyhedronsSetTest {
-
-    private static final double TEST_TOLERANCE = 1e-10;
-
-    @Test
-    public void testWholeSpace() {
-        // act
-        PolyhedronsSet polySet = new PolyhedronsSet(TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
-        GeometryTestUtils.assertPositiveInfinity(polySet.getSize());
-        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
-        Assert.assertFalse(polySet.isEmpty());
-        Assert.assertTrue(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(0, 0, 0),
-                new Cartesian3D(100, 100, 100),
-                new Cartesian3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
-    }
-
-    @Test
-    public void testEmptyRegion() {
-        // act
-        PolyhedronsSet polySet = new PolyhedronsSet(new BSPTree<Euclidean3D>(Boolean.FALSE), TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
-        Assert.assertEquals(0.0, polySet.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
-        Assert.assertTrue(polySet.isEmpty());
-        Assert.assertFalse(polySet.isFull());
-
-        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);
-        GeometryTestUtils.assertPositiveInfinity(polySet.getSize());
-        GeometryTestUtils.assertPositiveInfinity(polySet.getBoundarySize());
-        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
-        Assert.assertFalse(polySet.isEmpty());
-        Assert.assertFalse(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 testInvertedRegion() {
-        // arrange
-        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);
-        GeometryTestUtils.assertPositiveInfinity(polySet.getSize());
-        Assert.assertEquals(6, polySet.getBoundarySize(), TEST_TOLERANCE);
-        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
-        Assert.assertFalse(polySet.isEmpty());
-        Assert.assertFalse(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<>();
-
-        // act
-        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
-        GeometryTestUtils.assertPositiveInfinity(polySet.getSize());
-        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
-        Assert.assertFalse(polySet.isEmpty());
-        Assert.assertTrue(polySet.isFull());
-    }
-
-    @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.assertFalse(polySet.isEmpty());
-        Assert.assertFalse(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 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.assertFalse(polySet.isEmpty());
-        Assert.assertFalse(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.assertFalse(polySet.isEmpty());
-        Assert.assertFalse(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.assertFalse(polySet.isEmpty());
-        Assert.assertFalse(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.assertFalse(polySet.isEmpty());
-        Assert.assertFalse(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.assertFalse(polySet.isEmpty());
-        Assert.assertFalse(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) {
-                boolean yOK = (y >= 0.0) && (y <= 1.0);
-                for (double z = -0.25; z < 1.25; z += 0.1) {
-                    boolean zOK = (z >= 0.0) && (z <= 1.0);
-                    Region.Location expected =
-                        (xOK && yOK && zOK) ? Region.Location.INSIDE : Region.Location.OUTSIDE;
-                    Assert.assertEquals(expected, tree.checkPoint(new Cartesian3D(x, y, z)));
-                }
-            }
-        }
-        checkPoints(Region.Location.BOUNDARY, tree, new Cartesian3D[] {
-            new Cartesian3D(0.0, 0.5, 0.5),
-            new Cartesian3D(1.0, 0.5, 0.5),
-            new Cartesian3D(0.5, 0.0, 0.5),
-            new Cartesian3D(0.5, 1.0, 0.5),
-            new Cartesian3D(0.5, 0.5, 0.0),
-            new Cartesian3D(0.5, 0.5, 1.0)
-        });
-        checkPoints(Region.Location.OUTSIDE, tree, new Cartesian3D[] {
-            new Cartesian3D(0.0, 1.2, 1.2),
-            new Cartesian3D(1.0, 1.2, 1.2),
-            new Cartesian3D(1.2, 0.0, 1.2),
-            new Cartesian3D(1.2, 1.0, 1.2),
-            new Cartesian3D(1.2, 1.2, 0.0),
-            new Cartesian3D(1.2, 1.2, 1.0)
-        });
-    }
-
-    @Test
-    public void testInvertedBox() {
-        // arrange
-        PolyhedronsSet tree = new PolyhedronsSet(0, 1, 0, 1, 0, 1, 1.0e-10);
-
-        // act
-        tree = (PolyhedronsSet) new RegionFactory<Euclidean3D>().getComplement(tree);
-
-        // assert
-        GeometryTestUtils.assertPositiveInfinity(tree.getSize());
-        Assert.assertEquals(6.0, tree.getBoundarySize(), 1.0e-10);
-
-        Cartesian3D barycenter = (Cartesian3D) tree.getBarycenter();
-        Assert.assertTrue(Double.isNaN(barycenter.getX()));
-        Assert.assertTrue(Double.isNaN(barycenter.getY()));
-        Assert.assertTrue(Double.isNaN(barycenter.getZ()));
-
-        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) {
-                boolean yOK = (y < 0.0) || (y > 1.0);
-                for (double z = -0.25; z < 1.25; z += 0.1) {
-                    boolean zOK = (z < 0.0) || (z > 1.0);
-                    Region.Location expected =
-                        (xOK || yOK || zOK) ? Region.Location.INSIDE : Region.Location.OUTSIDE;
-                    Assert.assertEquals(expected, tree.checkPoint(new Cartesian3D(x, y, z)));
-                }
-            }
-        }
-        checkPoints(Region.Location.BOUNDARY, tree, new Cartesian3D[] {
-            new Cartesian3D(0.0, 0.5, 0.5),
-            new Cartesian3D(1.0, 0.5, 0.5),
-            new Cartesian3D(0.5, 0.0, 0.5),
-            new Cartesian3D(0.5, 1.0, 0.5),
-            new Cartesian3D(0.5, 0.5, 0.0),
-            new Cartesian3D(0.5, 0.5, 1.0)
-        });
-        checkPoints(Region.Location.INSIDE, tree, new Cartesian3D[] {
-            new Cartesian3D(0.0, 1.2, 1.2),
-            new Cartesian3D(1.0, 1.2, 1.2),
-            new Cartesian3D(1.2, 0.0, 1.2),
-            new Cartesian3D(1.2, 1.0, 1.2),
-            new Cartesian3D(1.2, 1.2, 0.0),
-            new Cartesian3D(1.2, 1.2, 1.0)
-        });
-    }
-
-    @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, 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,
-            new Cartesian3D(third, vertex1, third, vertex2, third, vertex3),
-            new Cartesian3D(third, vertex2, third, vertex3, third, vertex4),
-            new Cartesian3D(third, vertex3, third, vertex4, third, vertex1),
-            new Cartesian3D(third, vertex4, third, vertex1, third, vertex2)
-        });
-        checkPoints(Region.Location.OUTSIDE, tree, new Cartesian3D[] {
-            new Cartesian3D(1, 2, 4),
-            new Cartesian3D(2, 2, 3),
-            new Cartesian3D(2, 3, 4),
-            new Cartesian3D(1, 3, 3)
-        });
-    }
-
-    @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.assertFalse(polySet.isEmpty());
-        Assert.assertFalse(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, 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);
-        Rotation r = new Rotation(new Cartesian3D(6.2, -4.4, 2.1), 0.12, RotationConvention.VECTOR_OPERATOR);
-
-        tree = tree.rotate(c, r).translate(s);
-
-        Cartesian3D newB =
-            new Cartesian3D(1.0, s,
-                         1.0, c,
-                         1.0, r.applyTo(barycenter.subtract(c)));
-        Assert.assertEquals(0.0,
-                            newB.subtract((Cartesian3D) tree.getBarycenter()).getNorm(),
-                            TEST_TOLERANCE);
-
-        final Cartesian3D[] expectedV = new Cartesian3D[] {
-            new Cartesian3D(1.0, s,
-                         1.0, c,
-                         1.0, r.applyTo(vertex1.subtract(c))),
-                         new Cartesian3D(1.0, s,
-                                      1.0, c,
-                                      1.0, r.applyTo(vertex2.subtract(c))),
-                                      new Cartesian3D(1.0, s,
-                                                   1.0, c,
-                                                   1.0, r.applyTo(vertex3.subtract(c))),
-                                                   new Cartesian3D(1.0, s,
-                                                                1.0, c,
-                                                                1.0, r.applyTo(vertex4.subtract(c)))
-        };
-        tree.getTree(true).visit(new BSPTreeVisitor<Euclidean3D>() {
-
-            @Override
-            public Order visitOrder(BSPTree<Euclidean3D> node) {
-                return Order.MINUS_SUB_PLUS;
-            }
-
-            @Override
-            public void visitInternalNode(BSPTree<Euclidean3D> node) {
-                @SuppressWarnings("unchecked")
-                BoundaryAttribute<Euclidean3D> attribute =
-                    (BoundaryAttribute<Euclidean3D>) node.getAttribute();
-                if (attribute.getPlusOutside() != null) {
-                    checkFacet((SubPlane) attribute.getPlusOutside());
-                }
-                if (attribute.getPlusInside() != null) {
-                    checkFacet((SubPlane) attribute.getPlusInside());
-                }
-            }
-
-            @Override
-            public void visitLeafNode(BSPTree<Euclidean3D> node) {
-            }
-
-            private void checkFacet(SubPlane facet) {
-                Plane plane = (Plane) facet.getHyperplane();
-                Cartesian2D[][] vertices =
-                    ((PolygonsSet) facet.getRemainingRegion()).getVertices();
-                Assert.assertEquals(1, vertices.length);
-                for (int i = 0; i < vertices[0].length; ++i) {
-                    Cartesian3D v = plane.toSpace(vertices[0][i]);
-                    double d = Double.POSITIVE_INFINITY;
-                    for (int k = 0; k < expectedV.length; ++k) {
-                        d = FastMath.min(d, v.subtract(expectedV[k]).getNorm());
-                    }
-                    Assert.assertEquals(0, d, TEST_TOLERANCE);
-                }
-            }
-
-        });
-
-    }
-
-    @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, 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, TEST_TOLERANCE);
-        PolyhedronsSet yBeam =
-            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, TEST_TOLERANCE);
-        RegionFactory<Euclidean3D> factory = new RegionFactory<>();
-
-        // 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 testCreateFromBoundaries_handlesSmallBoundariesCreatedDuringConstruction() throws MathArithmeticException {
-        // arrange
-        float[] coords = {
-            1.000000f, -1.000000f, -1.000000f,
-            1.000000f, -1.000000f, 1.000000f,
-            -1.000000f, -1.000000f, 1.000000f,
-            -1.000000f, -1.000000f, -1.000000f,
-            1.000000f, 1.000000f, -1f,
-            0.999999f, 1.000000f, 1.000000f,   // 1.000000f, 1.000000f, 1.000000f,
-            -1.000000f, 1.000000f, 1.000000f,
-            -1.000000f, 1.000000f, -1.000000f};
-        int[] indices = {
-            0, 1, 2, 0, 2, 3,
-            4, 7, 6, 4, 6, 5,
-            0, 4, 5, 0, 5, 1,
-            1, 5, 6, 1, 6, 2,
-            2, 6, 7, 2, 7, 3,
-            4, 0, 3, 4, 3, 7};
-        ArrayList<SubHyperplane<Euclidean3D>> subHyperplaneList = new ArrayList<>();
-        for (int idx = 0; idx < indices.length; idx += 3) {
-            int idxA = indices[idx] * 3;
-            int idxB = indices[idx + 1] * 3;
-            int idxC = indices[idx + 2] * 3;
-            Cartesian3D v_1 = new Cartesian3D(coords[idxA], coords[idxA + 1], coords[idxA + 2]);
-            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, TEST_TOLERANCE);
-            ArrayList<SubHyperplane<Euclidean2D>> lines = new ArrayList<>();
-
-            Cartesian2D[] projPts = new Cartesian2D[vertices.length];
-            for (int ptIdx = 0; ptIdx < projPts.length; ptIdx++) {
-                projPts[ptIdx] = polyPlane.toSubSpace(vertices[ptIdx]);
-            }
-
-            SubLine lineInPlane = null;
-            for (int ptIdx = 0; ptIdx < projPts.length; ptIdx++) {
-                lineInPlane = new SubLine(projPts[ptIdx], projPts[(ptIdx + 1) % projPts.length], TEST_TOLERANCE);
-                lines.add(lineInPlane);
-            }
-            Region<Euclidean2D> polyRegion = new PolygonsSet(lines, TEST_TOLERANCE);
-            SubPlane polygon = new SubPlane(polyPlane, polyRegion);
-            subHyperplaneList.add(polygon);
-        }
-
-        // 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() {
-        // 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
-    public void testWrongUsage() {
-        // 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>(), TEST_TOLERANCE);
-        Assert.assertNotNull(ps);
-        try {
-            ps.checkPoint(Cartesian3D.ZERO);
-            Assert.fail("an exception should have been thrown");
-        } catch (NullPointerException npe) {
-            // this is expected
-        }
-    }
-
-    @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);
-
-        // 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(), TEST_TOLERANCE);
-        Assert.assertEquals( 5.0, polyhedron.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(22.0, polyhedron.getBoundarySize(), TEST_TOLERANCE);
-    }
-
-    @Test
-    public void testCreateFromBRep_verticesTooClose() throws IOException, ParseException {
-        checkError("pentomino-N-too-close.ply", LocalizedFormats.CLOSE_VERTICES);
-    }
-
-    @Test
-    public void testCreateFromBRep_hole() throws IOException, ParseException {
-        checkError("pentomino-N-hole.ply", LocalizedFormats.EDGE_CONNECTED_TO_ONE_FACET);
-    }
-
-    @Test
-    public void testCreateFromBRep_nonPlanar() throws IOException, ParseException {
-        checkError("pentomino-N-out-of-plane.ply", LocalizedFormats.OUT_OF_PLANE);
-    }
-
-    @Test
-    public void testCreateFromBRep_badOrientation() throws IOException, ParseException {
-        checkError("pentomino-N-bad-orientation.ply", LocalizedFormats.FACET_ORIENTATION_MISMATCH);
-    }
-
-    @Test
-    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)) {
-            PLYParser   parser = new PLYParser(stream);
-            checkError(parser.getVertices(), parser.getFaces(), expected);
-        } catch (IOException ioe) {
-            Assert.fail(ioe.getLocalizedMessage());
-        } catch (ParseException pe) {
-            Assert.fail(pe.getLocalizedMessage());
-        }
-    }
-
-    private void checkError(final List<Cartesian3D> vertices, final List<int[]> facets,
-                            final LocalizedFormats expected) {
-        try {
-            new PolyhedronsSet(vertices, facets, TEST_TOLERANCE);
-            Assert.fail("an exception should have been thrown");
-        } catch (MathIllegalArgumentException miae) {
-            try {
-                Field msgPatterns = ExceptionContext.class.getDeclaredField("msgPatterns");
-                msgPatterns.setAccessible(true);
-                @SuppressWarnings("unchecked")
-                List<Localizable> list = (List<Localizable>) msgPatterns.get(miae.getContext());
-                Assert.assertEquals(expected, list.get(0));
-            } catch (NoSuchFieldException nsfe) {
-                Assert.fail(nsfe.getLocalizedMessage());
-            } catch (IllegalAccessException iae) {
-                Assert.fail(iae.getLocalizedMessage());
-            }
-        }
-    }
-
-    @Test
-    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;
-            Cartesian3D direction = new Cartesian3D(2 * random.nextDouble() - 1,
-                                              2 * random.nextDouble() - 1,
-                                              2 * random.nextDouble() - 1).normalize();
-            Line line = new Line(origin, origin.add(direction), polyset.getTolerance());
-            SubHyperplane<Euclidean3D> plane = polyset.firstIntersection(origin, line);
-            if (plane != null) {
-                Cartesian3D intersectionPoint = ((Plane)plane.getHyperplane()).intersection(line);
-                double dotProduct = direction.dotProduct(intersectionPoint.subtract(origin));
-                Assert.assertTrue(dotProduct > 0);
-            }
-        }
-    }
-
-    @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.assertFalse(result.isEmpty());
-        Assert.assertFalse(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.assertFalse(result.isEmpty());
-        Assert.assertFalse(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.assertFalse(result.isEmpty());
-        Assert.assertFalse(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.assertFalse(result.isEmpty());
-        Assert.assertFalse(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.assertFalse(result.isEmpty());
-        Assert.assertFalse(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.assertFalse(result.isEmpty());
-        Assert.assertFalse(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.assertTrue(result.isEmpty());
-        Assert.assertFalse(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.assertFalse(result.isEmpty());
-        Assert.assertFalse(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.assertTrue(result.isEmpty());
-        Assert.assertFalse(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.assertFalse(result.isEmpty());
-        Assert.assertFalse(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 {
-        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 poly, Cartesian3D ... points) {
-        for (int i = 0; i < points.length; ++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;
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/RotationTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/RotationTest.java
deleted file mode 100644
index e754a51..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/RotationTest.java
+++ /dev/null
@@ -1,823 +0,0 @@
-/*
- * 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 org.apache.commons.numbers.angle.PlaneAngleRadians;
-import org.apache.commons.math4.exception.MathArithmeticException;
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.geometry.euclidean.threed.CardanEulerSingularityException;
-import org.apache.commons.math4.geometry.euclidean.threed.NotARotationMatrixException;
-import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
-import org.apache.commons.math4.geometry.euclidean.threed.RotationOrder;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.util.FastMath;
-import org.junit.Assert;
-import org.junit.Test;
-
-
-public class RotationTest {
-
-  @Test
-  public void testIdentity() {
-
-    Rotation r = Rotation.IDENTITY;
-    checkVector(r.applyTo(Cartesian3D.PLUS_I), Cartesian3D.PLUS_I);
-    checkVector(r.applyTo(Cartesian3D.PLUS_J), Cartesian3D.PLUS_J);
-    checkVector(r.applyTo(Cartesian3D.PLUS_K), Cartesian3D.PLUS_K);
-    checkAngle(r.getAngle(), 0);
-
-    r = new Rotation(-1, 0, 0, 0, false);
-    checkVector(r.applyTo(Cartesian3D.PLUS_I), Cartesian3D.PLUS_I);
-    checkVector(r.applyTo(Cartesian3D.PLUS_J), Cartesian3D.PLUS_J);
-    checkVector(r.applyTo(Cartesian3D.PLUS_K), Cartesian3D.PLUS_K);
-    checkAngle(r.getAngle(), 0);
-
-    r = new Rotation(42, 0, 0, 0, true);
-    checkVector(r.applyTo(Cartesian3D.PLUS_I), Cartesian3D.PLUS_I);
-    checkVector(r.applyTo(Cartesian3D.PLUS_J), Cartesian3D.PLUS_J);
-    checkVector(r.applyTo(Cartesian3D.PLUS_K), Cartesian3D.PLUS_K);
-    checkAngle(r.getAngle(), 0);
-
-  }
-
-  @Test
-  @Deprecated
-  public void testAxisAngleDeprecated() throws MathIllegalArgumentException {
-
-    Rotation r = new Rotation(new Cartesian3D(10, 10, 10), 2 * FastMath.PI / 3);
-    checkVector(r.applyTo(Cartesian3D.PLUS_I), Cartesian3D.PLUS_J);
-    checkVector(r.applyTo(Cartesian3D.PLUS_J), Cartesian3D.PLUS_K);
-    checkVector(r.applyTo(Cartesian3D.PLUS_K), Cartesian3D.PLUS_I);
-    double s = 1 / FastMath.sqrt(3);
-    checkVector(r.getAxis(), new Cartesian3D(s, s, s));
-    checkAngle(r.getAngle(), 2 * FastMath.PI / 3);
-
-    try {
-      new Rotation(new Cartesian3D(0, 0, 0), 2 * FastMath.PI / 3);
-      Assert.fail("an exception should have been thrown");
-    } catch (MathIllegalArgumentException e) {
-    }
-
-    r = new Rotation(Cartesian3D.PLUS_K, 1.5 * FastMath.PI);
-    checkVector(r.getAxis(), new Cartesian3D(0, 0, -1));
-    checkAngle(r.getAngle(), 0.5 * FastMath.PI);
-
-    r = new Rotation(Cartesian3D.PLUS_J, FastMath.PI);
-    checkVector(r.getAxis(), Cartesian3D.PLUS_J);
-    checkAngle(r.getAngle(), FastMath.PI);
-
-    checkVector(Rotation.IDENTITY.getAxis(), Cartesian3D.PLUS_I);
-
-  }
-
-  @Test
-  public void testAxisAngleVectorOperator() throws MathIllegalArgumentException {
-
-    Rotation r = new Rotation(new Cartesian3D(10, 10, 10), 2 * FastMath.PI / 3, RotationConvention.VECTOR_OPERATOR);
-    checkVector(r.applyTo(Cartesian3D.PLUS_I), Cartesian3D.PLUS_J);
-    checkVector(r.applyTo(Cartesian3D.PLUS_J), Cartesian3D.PLUS_K);
-    checkVector(r.applyTo(Cartesian3D.PLUS_K), Cartesian3D.PLUS_I);
-    double s = 1 / FastMath.sqrt(3);
-    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), new Cartesian3D( s,  s,  s));
-    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), new Cartesian3D(-s, -s, -s));
-    checkAngle(r.getAngle(), 2 * FastMath.PI / 3);
-
-    try {
-      new Rotation(new Cartesian3D(0, 0, 0), 2 * FastMath.PI / 3, RotationConvention.VECTOR_OPERATOR);
-      Assert.fail("an exception should have been thrown");
-    } catch (MathIllegalArgumentException e) {
-    }
-
-    r = new Rotation(Cartesian3D.PLUS_K, 1.5 * FastMath.PI, RotationConvention.VECTOR_OPERATOR);
-    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), new Cartesian3D(0, 0, -1));
-    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), new Cartesian3D(0, 0, +1));
-    checkAngle(r.getAngle(), 0.5 * FastMath.PI);
-
-    r = new Rotation(Cartesian3D.PLUS_J, FastMath.PI, RotationConvention.VECTOR_OPERATOR);
-    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), Cartesian3D.PLUS_J);
-    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), Cartesian3D.MINUS_J);
-    checkAngle(r.getAngle(), FastMath.PI);
-
-    checkVector(Rotation.IDENTITY.getAxis(RotationConvention.VECTOR_OPERATOR), Cartesian3D.PLUS_I);
-    checkVector(Rotation.IDENTITY.getAxis(RotationConvention.FRAME_TRANSFORM), Cartesian3D.MINUS_I);
-
-  }
-
-  @Test
-  public void testAxisAngleFrameTransform() throws MathIllegalArgumentException {
-
-    Rotation r = new Rotation(new Cartesian3D(10, 10, 10), 2 * FastMath.PI / 3, RotationConvention.FRAME_TRANSFORM);
-    checkVector(r.applyTo(Cartesian3D.PLUS_I), Cartesian3D.PLUS_K);
-    checkVector(r.applyTo(Cartesian3D.PLUS_J), Cartesian3D.PLUS_I);
-    checkVector(r.applyTo(Cartesian3D.PLUS_K), Cartesian3D.PLUS_J);
-    double s = 1 / FastMath.sqrt(3);
-    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), new Cartesian3D( s,  s,  s));
-    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), new Cartesian3D(-s, -s, -s));
-    checkAngle(r.getAngle(), 2 * FastMath.PI / 3);
-
-    try {
-      new Rotation(new Cartesian3D(0, 0, 0), 2 * FastMath.PI / 3, RotationConvention.FRAME_TRANSFORM);
-      Assert.fail("an exception should have been thrown");
-    } catch (MathIllegalArgumentException e) {
-    }
-
-    r = new Rotation(Cartesian3D.PLUS_K, 1.5 * FastMath.PI, RotationConvention.FRAME_TRANSFORM);
-    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), new Cartesian3D(0, 0, -1));
-    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), new Cartesian3D(0, 0, +1));
-    checkAngle(r.getAngle(), 0.5 * FastMath.PI);
-
-    r = new Rotation(Cartesian3D.PLUS_J, FastMath.PI, RotationConvention.FRAME_TRANSFORM);
-    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), Cartesian3D.PLUS_J);
-    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), Cartesian3D.MINUS_J);
-    checkAngle(r.getAngle(), FastMath.PI);
-
-    checkVector(Rotation.IDENTITY.getAxis(RotationConvention.FRAME_TRANSFORM), Cartesian3D.MINUS_I);
-    checkVector(Rotation.IDENTITY.getAxis(RotationConvention.VECTOR_OPERATOR), Cartesian3D.PLUS_I);
-
-  }
-
-  @Test
-  public void testRevertDeprecated() {
-    Rotation r = new Rotation(0.001, 0.36, 0.48, 0.8, true);
-    Rotation reverted = r.revert();
-    checkRotation(r.applyTo(reverted), 1, 0, 0, 0);
-    checkRotation(reverted.applyTo(r), 1, 0, 0, 0);
-    Assert.assertEquals(r.getAngle(), reverted.getAngle(), 1.0e-12);
-    Assert.assertEquals(-1,
-                        Cartesian3D.dotProduct(r.getAxis(RotationConvention.VECTOR_OPERATOR),
-                                           reverted.getAxis(RotationConvention.VECTOR_OPERATOR)),
-                        1.0e-12);
-  }
-
-  @Test
-  public void testRevertVectorOperator() {
-    Rotation r = new Rotation(0.001, 0.36, 0.48, 0.8, true);
-    Rotation reverted = r.revert();
-    checkRotation(r.compose(reverted, RotationConvention.VECTOR_OPERATOR), 1, 0, 0, 0);
-    checkRotation(reverted.compose(r, RotationConvention.VECTOR_OPERATOR), 1, 0, 0, 0);
-    Assert.assertEquals(r.getAngle(), reverted.getAngle(), 1.0e-12);
-    Assert.assertEquals(-1,
-                        Cartesian3D.dotProduct(r.getAxis(RotationConvention.VECTOR_OPERATOR),
-                                           reverted.getAxis(RotationConvention.VECTOR_OPERATOR)),
-                        1.0e-12);
-  }
-
-  @Test
-  public void testRevertFrameTransform() {
-    Rotation r = new Rotation(0.001, 0.36, 0.48, 0.8, true);
-    Rotation reverted = r.revert();
-    checkRotation(r.compose(reverted, RotationConvention.FRAME_TRANSFORM), 1, 0, 0, 0);
-    checkRotation(reverted.compose(r, RotationConvention.FRAME_TRANSFORM), 1, 0, 0, 0);
-    Assert.assertEquals(r.getAngle(), reverted.getAngle(), 1.0e-12);
-    Assert.assertEquals(-1,
-                        Cartesian3D.dotProduct(r.getAxis(RotationConvention.FRAME_TRANSFORM),
-                                           reverted.getAxis(RotationConvention.FRAME_TRANSFORM)),
-                        1.0e-12);
-  }
-
-  @Test
-  public void testVectorOnePair() throws MathArithmeticException {
-
-    Cartesian3D u = new Cartesian3D(3, 2, 1);
-    Cartesian3D v = new Cartesian3D(-4, 2, 2);
-    Rotation r = new Rotation(u, v);
-    checkVector(r.applyTo(u.scalarMultiply(v.getNorm())), v.scalarMultiply(u.getNorm()));
-
-    checkAngle(new Rotation(u, u.negate()).getAngle(), FastMath.PI);
-
-    try {
-        new Rotation(u, Cartesian3D.ZERO);
-        Assert.fail("an exception should have been thrown");
-    } catch (MathArithmeticException e) {
-        // expected behavior
-    }
-
-  }
-
-  @Test
-  public void testVectorTwoPairs() throws MathArithmeticException {
-
-    Cartesian3D u1 = new Cartesian3D(3, 0, 0);
-    Cartesian3D u2 = new Cartesian3D(0, 5, 0);
-    Cartesian3D v1 = new Cartesian3D(0, 0, 2);
-    Cartesian3D v2 = new Cartesian3D(-2, 0, 2);
-    Rotation r = new Rotation(u1, u2, v1, v2);
-    checkVector(r.applyTo(Cartesian3D.PLUS_I), Cartesian3D.PLUS_K);
-    checkVector(r.applyTo(Cartesian3D.PLUS_J), Cartesian3D.MINUS_I);
-
-    r = new Rotation(u1, u2, u1.negate(), u2.negate());
-    Cartesian3D axis = r.getAxis(RotationConvention.VECTOR_OPERATOR);
-    if (Cartesian3D.dotProduct(axis, Cartesian3D.PLUS_K) > 0) {
-      checkVector(axis, Cartesian3D.PLUS_K);
-    } else {
-      checkVector(axis, Cartesian3D.MINUS_K);
-    }
-    checkAngle(r.getAngle(), FastMath.PI);
-
-    double sqrt = FastMath.sqrt(2) / 2;
-    r = new Rotation(Cartesian3D.PLUS_I,  Cartesian3D.PLUS_J,
-                     new Cartesian3D(0.5, 0.5,  sqrt),
-                     new Cartesian3D(0.5, 0.5, -sqrt));
-    checkRotation(r, sqrt, 0.5, 0.5, 0);
-
-    r = new Rotation(u1, u2, u1, Cartesian3D.crossProduct(u1, u2));
-    checkRotation(r, sqrt, -sqrt, 0, 0);
-
-    checkRotation(new Rotation(u1, u2, u1, u2), 1, 0, 0, 0);
-
-    try {
-        new Rotation(u1, u2, Cartesian3D.ZERO, v2);
-        Assert.fail("an exception should have been thrown");
-    } catch (MathArithmeticException e) {
-      // expected behavior
-    }
-
-  }
-
-  @Test
-  public void testMatrix()
-    throws NotARotationMatrixException {
-
-    try {
-      new Rotation(new double[][] {
-                     { 0.0, 1.0, 0.0 },
-                     { 1.0, 0.0, 0.0 }
-                   }, 1.0e-7);
-      Assert.fail("Expecting NotARotationMatrixException");
-    } catch (NotARotationMatrixException nrme) {
-      // expected behavior
-    }
-
-    try {
-      new Rotation(new double[][] {
-                     {  0.445888,  0.797184, -0.407040 },
-                     {  0.821760, -0.184320,  0.539200 },
-                     { -0.354816,  0.574912,  0.737280 }
-                   }, 1.0e-7);
-      Assert.fail("Expecting NotARotationMatrixException");
-    } catch (NotARotationMatrixException nrme) {
-      // expected behavior
-    }
-
-    try {
-        new Rotation(new double[][] {
-                       {  0.4,  0.8, -0.4 },
-                       { -0.4,  0.6,  0.7 },
-                       {  0.8, -0.2,  0.5 }
-                     }, 1.0e-15);
-        Assert.fail("Expecting NotARotationMatrixException");
-      } catch (NotARotationMatrixException nrme) {
-        // expected behavior
-      }
-
-    checkRotation(new Rotation(new double[][] {
-                                 {  0.445888,  0.797184, -0.407040 },
-                                 { -0.354816,  0.574912,  0.737280 },
-                                 {  0.821760, -0.184320,  0.539200 }
-                               }, 1.0e-10),
-                  0.8, 0.288, 0.384, 0.36);
-
-    checkRotation(new Rotation(new double[][] {
-                                 {  0.539200,  0.737280,  0.407040 },
-                                 {  0.184320, -0.574912,  0.797184 },
-                                 {  0.821760, -0.354816, -0.445888 }
-                              }, 1.0e-10),
-                  0.36, 0.8, 0.288, 0.384);
-
-    checkRotation(new Rotation(new double[][] {
-                                 { -0.445888,  0.797184, -0.407040 },
-                                 {  0.354816,  0.574912,  0.737280 },
-                                 {  0.821760,  0.184320, -0.539200 }
-                               }, 1.0e-10),
-                  0.384, 0.36, 0.8, 0.288);
-
-    checkRotation(new Rotation(new double[][] {
-                                 { -0.539200,  0.737280,  0.407040 },
-                                 { -0.184320, -0.574912,  0.797184 },
-                                 {  0.821760,  0.354816,  0.445888 }
-                               }, 1.0e-10),
-                  0.288, 0.384, 0.36, 0.8);
-
-    double[][] m1 = { { 0.0, 1.0, 0.0 },
-                      { 0.0, 0.0, 1.0 },
-                      { 1.0, 0.0, 0.0 } };
-    Rotation r = new Rotation(m1, 1.0e-7);
-    checkVector(r.applyTo(Cartesian3D.PLUS_I), Cartesian3D.PLUS_K);
-    checkVector(r.applyTo(Cartesian3D.PLUS_J), Cartesian3D.PLUS_I);
-    checkVector(r.applyTo(Cartesian3D.PLUS_K), Cartesian3D.PLUS_J);
-
-    double[][] m2 = { { 0.83203, -0.55012, -0.07139 },
-                      { 0.48293,  0.78164, -0.39474 },
-                      { 0.27296,  0.29396,  0.91602 } };
-    r = new Rotation(m2, 1.0e-12);
-
-    double[][] m3 = r.getMatrix();
-    double d00 = m2[0][0] - m3[0][0];
-    double d01 = m2[0][1] - m3[0][1];
-    double d02 = m2[0][2] - m3[0][2];
-    double d10 = m2[1][0] - m3[1][0];
-    double d11 = m2[1][1] - m3[1][1];
-    double d12 = m2[1][2] - m3[1][2];
-    double d20 = m2[2][0] - m3[2][0];
-    double d21 = m2[2][1] - m3[2][1];
-    double d22 = m2[2][2] - m3[2][2];
-
-    Assert.assertTrue(FastMath.abs(d00) < 6.0e-6);
-    Assert.assertTrue(FastMath.abs(d01) < 6.0e-6);
-    Assert.assertTrue(FastMath.abs(d02) < 6.0e-6);
-    Assert.assertTrue(FastMath.abs(d10) < 6.0e-6);
-    Assert.assertTrue(FastMath.abs(d11) < 6.0e-6);
-    Assert.assertTrue(FastMath.abs(d12) < 6.0e-6);
-    Assert.assertTrue(FastMath.abs(d20) < 6.0e-6);
-    Assert.assertTrue(FastMath.abs(d21) < 6.0e-6);
-    Assert.assertTrue(FastMath.abs(d22) < 6.0e-6);
-
-    Assert.assertTrue(FastMath.abs(d00) > 4.0e-7);
-    Assert.assertTrue(FastMath.abs(d01) > 4.0e-7);
-    Assert.assertTrue(FastMath.abs(d02) > 4.0e-7);
-    Assert.assertTrue(FastMath.abs(d10) > 4.0e-7);
-    Assert.assertTrue(FastMath.abs(d11) > 4.0e-7);
-    Assert.assertTrue(FastMath.abs(d12) > 4.0e-7);
-    Assert.assertTrue(FastMath.abs(d20) > 4.0e-7);
-    Assert.assertTrue(FastMath.abs(d21) > 4.0e-7);
-    Assert.assertTrue(FastMath.abs(d22) > 4.0e-7);
-
-    for (int i = 0; i < 3; ++i) {
-      for (int j = 0; j < 3; ++j) {
-        double m3tm3 = m3[i][0] * m3[j][0]
-                     + m3[i][1] * m3[j][1]
-                     + m3[i][2] * m3[j][2];
-        if (i == j) {
-          Assert.assertTrue(FastMath.abs(m3tm3 - 1.0) < 1.0e-10);
-        } else {
-          Assert.assertTrue(FastMath.abs(m3tm3) < 1.0e-10);
-        }
-      }
-    }
-
-    checkVector(r.applyTo(Cartesian3D.PLUS_I),
-                new Cartesian3D(m3[0][0], m3[1][0], m3[2][0]));
-    checkVector(r.applyTo(Cartesian3D.PLUS_J),
-                new Cartesian3D(m3[0][1], m3[1][1], m3[2][1]));
-    checkVector(r.applyTo(Cartesian3D.PLUS_K),
-                new Cartesian3D(m3[0][2], m3[1][2], m3[2][2]));
-
-    double[][] m4 = { { 1.0,  0.0,  0.0 },
-                      { 0.0, -1.0,  0.0 },
-                      { 0.0,  0.0, -1.0 } };
-    r = new Rotation(m4, 1.0e-7);
-    checkAngle(r.getAngle(), FastMath.PI);
-
-    try {
-      double[][] m5 = { { 0.0, 0.0, 1.0 },
-                        { 0.0, 1.0, 0.0 },
-                        { 1.0, 0.0, 0.0 } };
-      r = new Rotation(m5, 1.0e-7);
-      Assert.fail("got " + r + ", should have caught an exception");
-    } catch (NotARotationMatrixException e) {
-      // expected
-    }
-
-  }
-
-  @Test
-  @Deprecated
-  public void testAnglesDeprecated()
-    throws CardanEulerSingularityException {
-
-    RotationOrder[] CardanOrders = {
-      RotationOrder.XYZ, RotationOrder.XZY, RotationOrder.YXZ,
-      RotationOrder.YZX, RotationOrder.ZXY, RotationOrder.ZYX
-    };
-
-    for (int i = 0; i < CardanOrders.length; ++i) {
-      for (double alpha1 = 0.1; alpha1 < 6.2; alpha1 += 0.3) {
-        for (double alpha2 = -1.55; alpha2 < 1.55; alpha2 += 0.3) {
-          for (double alpha3 = 0.1; alpha3 < 6.2; alpha3 += 0.3) {
-            Rotation r = new Rotation(CardanOrders[i], alpha1, alpha2, alpha3);
-            double[] angles = r.getAngles(CardanOrders[i]);
-            checkAngle(angles[0], alpha1);
-            checkAngle(angles[1], alpha2);
-            checkAngle(angles[2], alpha3);
-          }
-        }
-      }
-    }
-
-    RotationOrder[] EulerOrders = {
-            RotationOrder.XYX, RotationOrder.XZX, RotationOrder.YXY,
-            RotationOrder.YZY, RotationOrder.ZXZ, RotationOrder.ZYZ
-    };
-
-    for (int i = 0; i < EulerOrders.length; ++i) {
-      for (double alpha1 = 0.1; alpha1 < 6.2; alpha1 += 0.3) {
-        for (double alpha2 = 0.05; alpha2 < 3.1; alpha2 += 0.3) {
-          for (double alpha3 = 0.1; alpha3 < 6.2; alpha3 += 0.3) {
-            Rotation r = new Rotation(EulerOrders[i],
-                                      alpha1, alpha2, alpha3);
-            double[] angles = r.getAngles(EulerOrders[i]);
-            checkAngle(angles[0], alpha1);
-            checkAngle(angles[1], alpha2);
-            checkAngle(angles[2], alpha3);
-          }
-        }
-      }
-    }
-
-  }
-
-  @Test
-  public void testAngles()
-      throws CardanEulerSingularityException {
-
-      for (RotationConvention convention : RotationConvention.values()) {
-          RotationOrder[] CardanOrders = {
-              RotationOrder.XYZ, RotationOrder.XZY, RotationOrder.YXZ,
-              RotationOrder.YZX, RotationOrder.ZXY, RotationOrder.ZYX
-          };
-
-          for (int i = 0; i < CardanOrders.length; ++i) {
-              for (double alpha1 = 0.1; alpha1 < 6.2; alpha1 += 0.3) {
-                  for (double alpha2 = -1.55; alpha2 < 1.55; alpha2 += 0.3) {
-                      for (double alpha3 = 0.1; alpha3 < 6.2; alpha3 += 0.3) {
-                          Rotation r = new Rotation(CardanOrders[i], convention, alpha1, alpha2, alpha3);
-                          double[] angles = r.getAngles(CardanOrders[i], convention);
-                          checkAngle(angles[0], alpha1);
-                          checkAngle(angles[1], alpha2);
-                          checkAngle(angles[2], alpha3);
-                      }
-                  }
-              }
-          }
-
-          RotationOrder[] EulerOrders = {
-              RotationOrder.XYX, RotationOrder.XZX, RotationOrder.YXY,
-              RotationOrder.YZY, RotationOrder.ZXZ, RotationOrder.ZYZ
-          };
-
-          for (int i = 0; i < EulerOrders.length; ++i) {
-              for (double alpha1 = 0.1; alpha1 < 6.2; alpha1 += 0.3) {
-                  for (double alpha2 = 0.05; alpha2 < 3.1; alpha2 += 0.3) {
-                      for (double alpha3 = 0.1; alpha3 < 6.2; alpha3 += 0.3) {
-                          Rotation r = new Rotation(EulerOrders[i], convention,
-                                                    alpha1, alpha2, alpha3);
-                          double[] angles = r.getAngles(EulerOrders[i], convention);
-                          checkAngle(angles[0], alpha1);
-                          checkAngle(angles[1], alpha2);
-                          checkAngle(angles[2], alpha3);
-                      }
-                  }
-              }
-          }
-      }
-
-  }
-
-  @Test
-  public void testSingularities() {
-
-      for (RotationConvention convention : RotationConvention.values()) {
-          RotationOrder[] CardanOrders = {
-              RotationOrder.XYZ, RotationOrder.XZY, RotationOrder.YXZ,
-              RotationOrder.YZX, RotationOrder.ZXY, RotationOrder.ZYX
-          };
-
-          double[] singularCardanAngle = { FastMath.PI / 2, -FastMath.PI / 2 };
-          for (int i = 0; i < CardanOrders.length; ++i) {
-              for (int j = 0; j < singularCardanAngle.length; ++j) {
-                  Rotation r = new Rotation(CardanOrders[i], convention, 0.1, singularCardanAngle[j], 0.3);
-                  try {
-                      r.getAngles(CardanOrders[i], convention);
-                      Assert.fail("an exception should have been caught");
-                  } catch (CardanEulerSingularityException cese) {
-                      // expected behavior
-                  }
-              }
-          }
-
-          RotationOrder[] EulerOrders = {
-              RotationOrder.XYX, RotationOrder.XZX, RotationOrder.YXY,
-              RotationOrder.YZY, RotationOrder.ZXZ, RotationOrder.ZYZ
-          };
-
-          double[] singularEulerAngle = { 0, FastMath.PI };
-          for (int i = 0; i < EulerOrders.length; ++i) {
-              for (int j = 0; j < singularEulerAngle.length; ++j) {
-                  Rotation r = new Rotation(EulerOrders[i], convention, 0.1, singularEulerAngle[j], 0.3);
-                  try {
-                      r.getAngles(EulerOrders[i], convention);
-                      Assert.fail("an exception should have been caught");
-                  } catch (CardanEulerSingularityException cese) {
-                      // expected behavior
-                  }
-              }
-          }
-      }
-
-
-  }
-
-  @Test
-  public void testQuaternion() throws MathIllegalArgumentException {
-
-    Rotation r1 = new Rotation(new Cartesian3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
-    double n = 23.5;
-    Rotation r2 = new Rotation(n * r1.getQ0(), n * r1.getQ1(),
-                               n * r1.getQ2(), n * r1.getQ3(),
-                               true);
-    for (double x = -0.9; x < 0.9; x += 0.2) {
-      for (double y = -0.9; y < 0.9; y += 0.2) {
-        for (double z = -0.9; z < 0.9; z += 0.2) {
-          Cartesian3D u = new Cartesian3D(x, y, z);
-          checkVector(r2.applyTo(u), r1.applyTo(u));
-        }
-      }
-    }
-
-    r1 = new Rotation( 0.288,  0.384,  0.36,  0.8, false);
-    checkRotation(r1, -r1.getQ0(), -r1.getQ1(), -r1.getQ2(), -r1.getQ3());
-
-  }
-
-  @Test
-  public void testApplyTo() throws MathIllegalArgumentException {
-
-    Rotation r1 = new Rotation(new Cartesian3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
-    Rotation r2 = new Rotation(new Cartesian3D(-1, 3, 2), 0.3, RotationConvention.VECTOR_OPERATOR);
-    Rotation r3 = r2.applyTo(r1);
-
-    for (double x = -0.9; x < 0.9; x += 0.2) {
-      for (double y = -0.9; y < 0.9; y += 0.2) {
-        for (double z = -0.9; z < 0.9; z += 0.2) {
-          Cartesian3D u = new Cartesian3D(x, y, z);
-          checkVector(r2.applyTo(r1.applyTo(u)), r3.applyTo(u));
-        }
-      }
-    }
-
-  }
-
-  @Test
-  public void testComposeVectorOperator() throws MathIllegalArgumentException {
-
-    Rotation r1 = new Rotation(new Cartesian3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
-    Rotation r2 = new Rotation(new Cartesian3D(-1, 3, 2), 0.3, RotationConvention.VECTOR_OPERATOR);
-    Rotation r3 = r2.compose(r1, RotationConvention.VECTOR_OPERATOR);
-
-    for (double x = -0.9; x < 0.9; x += 0.2) {
-      for (double y = -0.9; y < 0.9; y += 0.2) {
-        for (double z = -0.9; z < 0.9; z += 0.2) {
-          Cartesian3D u = new Cartesian3D(x, y, z);
-          checkVector(r2.applyTo(r1.applyTo(u)), r3.applyTo(u));
-        }
-      }
-    }
-
-  }
-
-  @Test
-  public void testComposeFrameTransform() throws MathIllegalArgumentException {
-
-    Rotation r1 = new Rotation(new Cartesian3D(2, -3, 5), 1.7, RotationConvention.FRAME_TRANSFORM);
-    Rotation r2 = new Rotation(new Cartesian3D(-1, 3, 2), 0.3, RotationConvention.FRAME_TRANSFORM);
-    Rotation r3 = r2.compose(r1, RotationConvention.FRAME_TRANSFORM);
-    Rotation r4 = r1.compose(r2, RotationConvention.VECTOR_OPERATOR);
-    Assert.assertEquals(0.0, Rotation.distance(r3, r4), 1.0e-15);
-
-    for (double x = -0.9; x < 0.9; x += 0.2) {
-      for (double y = -0.9; y < 0.9; y += 0.2) {
-        for (double z = -0.9; z < 0.9; z += 0.2) {
-          Cartesian3D u = new Cartesian3D(x, y, z);
-          checkVector(r1.applyTo(r2.applyTo(u)), r3.applyTo(u));
-        }
-      }
-    }
-
-  }
-
-  @Test
-  public void testApplyInverseToRotation() throws MathIllegalArgumentException {
-
-    Rotation r1 = new Rotation(new Cartesian3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
-    Rotation r2 = new Rotation(new Cartesian3D(-1, 3, 2), 0.3, RotationConvention.VECTOR_OPERATOR);
-    Rotation r3 = r2.applyInverseTo(r1);
-
-    for (double x = -0.9; x < 0.9; x += 0.2) {
-      for (double y = -0.9; y < 0.9; y += 0.2) {
-        for (double z = -0.9; z < 0.9; z += 0.2) {
-          Cartesian3D u = new Cartesian3D(x, y, z);
-          checkVector(r2.applyInverseTo(r1.applyTo(u)), r3.applyTo(u));
-        }
-      }
-    }
-
-  }
-
-  @Test
-  public void testComposeInverseVectorOperator() throws MathIllegalArgumentException {
-
-    Rotation r1 = new Rotation(new Cartesian3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
-    Rotation r2 = new Rotation(new Cartesian3D(-1, 3, 2), 0.3, RotationConvention.VECTOR_OPERATOR);
-    Rotation r3 = r2.composeInverse(r1, RotationConvention.VECTOR_OPERATOR);
-
-    for (double x = -0.9; x < 0.9; x += 0.2) {
-      for (double y = -0.9; y < 0.9; y += 0.2) {
-        for (double z = -0.9; z < 0.9; z += 0.2) {
-          Cartesian3D u = new Cartesian3D(x, y, z);
-          checkVector(r2.applyInverseTo(r1.applyTo(u)), r3.applyTo(u));
-        }
-      }
-    }
-
-  }
-
-  @Test
-  public void testComposeInverseFrameTransform() throws MathIllegalArgumentException {
-
-    Rotation r1 = new Rotation(new Cartesian3D(2, -3, 5), 1.7, RotationConvention.FRAME_TRANSFORM);
-    Rotation r2 = new Rotation(new Cartesian3D(-1, 3, 2), 0.3, RotationConvention.FRAME_TRANSFORM);
-    Rotation r3 = r2.composeInverse(r1, RotationConvention.FRAME_TRANSFORM);
-    Rotation r4 = r1.revert().composeInverse(r2.revert(), RotationConvention.VECTOR_OPERATOR);
-    Assert.assertEquals(0.0, Rotation.distance(r3, r4), 1.0e-15);
-
-    for (double x = -0.9; x < 0.9; x += 0.2) {
-      for (double y = -0.9; y < 0.9; y += 0.2) {
-        for (double z = -0.9; z < 0.9; z += 0.2) {
-          Cartesian3D u = new Cartesian3D(x, y, z);
-          checkVector(r1.applyTo(r2.applyInverseTo(u)), r3.applyTo(u));
-        }
-      }
-    }
-
-  }
-
-  @Test
-  public void testArray() throws MathIllegalArgumentException {
-
-      Rotation r = new Rotation(new Cartesian3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
-
-      for (double x = -0.9; x < 0.9; x += 0.2) {
-          for (double y = -0.9; y < 0.9; y += 0.2) {
-              for (double z = -0.9; z < 0.9; z += 0.2) {
-                  Cartesian3D u = new Cartesian3D(x, y, z);
-                  Cartesian3D v = r.applyTo(u);
-                  double[] inOut = new double[] { x, y, z };
-                  r.applyTo(inOut, inOut);
-                  Assert.assertEquals(v.getX(), inOut[0], 1.0e-10);
-                  Assert.assertEquals(v.getY(), inOut[1], 1.0e-10);
-                  Assert.assertEquals(v.getZ(), inOut[2], 1.0e-10);
-                  r.applyInverseTo(inOut, inOut);
-                  Assert.assertEquals(u.getX(), inOut[0], 1.0e-10);
-                  Assert.assertEquals(u.getY(), inOut[1], 1.0e-10);
-                  Assert.assertEquals(u.getZ(), inOut[2], 1.0e-10);
-              }
-          }
-      }
-
-  }
-
-  @Test
-  public void testApplyInverseTo() throws MathIllegalArgumentException {
-
-    Rotation r = new Rotation(new Cartesian3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
-    for (double lambda = 0; lambda < 6.2; lambda += 0.2) {
-      for (double phi = -1.55; phi < 1.55; phi += 0.2) {
-          Cartesian3D u = new Cartesian3D(FastMath.cos(lambda) * FastMath.cos(phi),
-                                    FastMath.sin(lambda) * FastMath.cos(phi),
-                                    FastMath.sin(phi));
-          r.applyInverseTo(r.applyTo(u));
-          checkVector(u, r.applyInverseTo(r.applyTo(u)));
-          checkVector(u, r.applyTo(r.applyInverseTo(u)));
-      }
-    }
-
-    r = Rotation.IDENTITY;
-    for (double lambda = 0; lambda < 6.2; lambda += 0.2) {
-      for (double phi = -1.55; phi < 1.55; phi += 0.2) {
-          Cartesian3D u = new Cartesian3D(FastMath.cos(lambda) * FastMath.cos(phi),
-                                    FastMath.sin(lambda) * FastMath.cos(phi),
-                                    FastMath.sin(phi));
-          checkVector(u, r.applyInverseTo(r.applyTo(u)));
-          checkVector(u, r.applyTo(r.applyInverseTo(u)));
-      }
-    }
-
-    r = new Rotation(Cartesian3D.PLUS_K, FastMath.PI, RotationConvention.VECTOR_OPERATOR);
-    for (double lambda = 0; lambda < 6.2; lambda += 0.2) {
-      for (double phi = -1.55; phi < 1.55; phi += 0.2) {
-          Cartesian3D u = new Cartesian3D(FastMath.cos(lambda) * FastMath.cos(phi),
-                                    FastMath.sin(lambda) * FastMath.cos(phi),
-                                    FastMath.sin(phi));
-          checkVector(u, r.applyInverseTo(r.applyTo(u)));
-          checkVector(u, r.applyTo(r.applyInverseTo(u)));
-      }
-    }
-
-  }
-
-  @Test
-  public void testIssue639() throws MathArithmeticException{
-      Cartesian3D u1 = new Cartesian3D(-1321008684645961.0 /  268435456.0,
-                                 -5774608829631843.0 /  268435456.0,
-                                 -3822921525525679.0 / 4294967296.0);
-      Cartesian3D u2 =new Cartesian3D( -5712344449280879.0 /    2097152.0,
-                                 -2275058564560979.0 /    1048576.0,
-                                  4423475992255071.0 /      65536.0);
-      Rotation rot = new Rotation(u1, u2, Cartesian3D.PLUS_I,Cartesian3D.PLUS_K);
-      Assert.assertEquals( 0.6228370359608200639829222, rot.getQ0(), 1.0e-15);
-      Assert.assertEquals( 0.0257707621456498790029987, rot.getQ1(), 1.0e-15);
-      Assert.assertEquals(-0.0000000002503012255839931, rot.getQ2(), 1.0e-15);
-      Assert.assertEquals(-0.7819270390861109450724902, rot.getQ3(), 1.0e-15);
-  }
-
-  @Test
-  public void testIssue801() throws MathArithmeticException {
-      Cartesian3D u1 = new Cartesian3D(0.9999988431610581, -0.0015210774290851095, 0.0);
-      Cartesian3D u2 = new Cartesian3D(0.0, 0.0, 1.0);
-
-      Cartesian3D v1 = new Cartesian3D(0.9999999999999999, 0.0, 0.0);
-      Cartesian3D v2 = new Cartesian3D(0.0, 0.0, -1.0);
-
-      Rotation quat = new Rotation(u1, u2, v1, v2);
-      double q2 = quat.getQ0() * quat.getQ0() +
-                  quat.getQ1() * quat.getQ1() +
-                  quat.getQ2() * quat.getQ2() +
-                  quat.getQ3() * quat.getQ3();
-      Assert.assertEquals(1.0, q2, 1.0e-14);
-      Assert.assertEquals(0.0, Cartesian3D.angle(v1, quat.applyTo(u1)), 1.0e-14);
-      Assert.assertEquals(0.0, Cartesian3D.angle(v2, quat.applyTo(u2)), 1.0e-14);
-
-  }
-
-  @Test
-  public void testGithubPullRequest22A() {
-      final RotationOrder order = RotationOrder.ZYX;
-      final double xRotation = FastMath.toDegrees(30);
-      final double yRotation = FastMath.toDegrees(20);
-      final double zRotation = FastMath.toDegrees(10);
-      final Cartesian3D startingVector = Cartesian3D.PLUS_I;
-      Cartesian3D appliedIndividually = startingVector;
-      appliedIndividually = new Rotation(order, RotationConvention.FRAME_TRANSFORM, zRotation, 0, 0).applyTo(appliedIndividually);
-      appliedIndividually = new Rotation(order, RotationConvention.FRAME_TRANSFORM, 0, yRotation, 0).applyTo(appliedIndividually);
-      appliedIndividually = new Rotation(order, RotationConvention.FRAME_TRANSFORM, 0, 0, xRotation).applyTo(appliedIndividually);
-
-      final Cartesian3D bad = new Rotation(order, RotationConvention.FRAME_TRANSFORM, zRotation, yRotation, xRotation).applyTo(startingVector);
-
-      Assert.assertEquals(bad.getX(), appliedIndividually.getX(), 1e-12);
-      Assert.assertEquals(bad.getY(), appliedIndividually.getY(), 1e-12);
-      Assert.assertEquals(bad.getZ(), appliedIndividually.getZ(), 1e-12);
-  }
-
-  @Test
-  public void testGithubPullRequest22B() {
-      final RotationOrder order = RotationOrder.ZYX;
-      final double xRotation = FastMath.toDegrees(30);
-      final double yRotation = FastMath.toDegrees(20);
-      final double zRotation = FastMath.toDegrees(10);
-      final Cartesian3D startingVector = Cartesian3D.PLUS_I;
-      Cartesian3D appliedIndividually = startingVector;
-      appliedIndividually = new Rotation(order, RotationConvention.FRAME_TRANSFORM, zRotation, 0, 0).applyTo(appliedIndividually);
-      appliedIndividually = new Rotation(order, RotationConvention.FRAME_TRANSFORM, 0, yRotation, 0).applyTo(appliedIndividually);
-      appliedIndividually = new Rotation(order, RotationConvention.FRAME_TRANSFORM, 0, 0, xRotation).applyTo(appliedIndividually);
-
-      final Rotation r1 = new Rotation(order.getA1(), zRotation, RotationConvention.FRAME_TRANSFORM);
-      final Rotation r2 = new Rotation(order.getA2(), yRotation, RotationConvention.FRAME_TRANSFORM);
-      final Rotation r3 = new Rotation(order.getA3(), xRotation, RotationConvention.FRAME_TRANSFORM);
-      final Rotation composite = r1.compose(r2.compose(r3,
-                                                       RotationConvention.FRAME_TRANSFORM),
-                                            RotationConvention.FRAME_TRANSFORM);
-      final Cartesian3D good = composite.applyTo(startingVector);
-
-      Assert.assertEquals(good.getX(), appliedIndividually.getX(), 1e-12);
-      Assert.assertEquals(good.getY(), appliedIndividually.getY(), 1e-12);
-      Assert.assertEquals(good.getZ(), appliedIndividually.getZ(), 1e-12);
-  }
-
-  private void checkVector(Cartesian3D v1, Cartesian3D v2) {
-    Assert.assertTrue(v1.subtract(v2).getNorm() < 1.0e-10);
-  }
-
-  private void checkAngle(double a1, double a2) {
-    Assert.assertEquals(a1, PlaneAngleRadians.normalize(a2, a1), 1.0e-10);
-  }
-
-  private void checkRotation(Rotation r, double q0, double q1, double q2, double q3) {
-    Assert.assertEquals(0, Rotation.distance(r, new Rotation(q0, q1, q2, q3, false)), 1.0e-12);
-  }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/SphereGeneratorTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/SphereGeneratorTest.java
deleted file mode 100644
index 1d0a913..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/SphereGeneratorTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import org.junit.Assert;
-import org.junit.Test;
-import org.apache.commons.rng.UniformRandomProvider;
-import org.apache.commons.rng.simple.RandomSource;
-import org.apache.commons.rng.sampling.UnitSphereSampler;
-import org.apache.commons.math4.geometry.enclosing.EnclosingBall;
-import org.apache.commons.math4.geometry.euclidean.threed.Euclidean3D;
-import org.apache.commons.math4.geometry.euclidean.threed.SphereGenerator;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.util.FastMath;
-
-public class SphereGeneratorTest {
-
-    @Test
-    public void testSupport0Point() {
-        List<Cartesian3D> support = Arrays.asList(new Cartesian3D[0]);
-        EnclosingBall<Euclidean3D, Cartesian3D> sphere = new SphereGenerator().ballOnSupport(support);
-        Assert.assertTrue(sphere.getRadius() < 0);
-        Assert.assertEquals(0, sphere.getSupportSize());
-        Assert.assertEquals(0, sphere.getSupport().length);
-    }
-
-    @Test
-    public void testSupport1Point() {
-        List<Cartesian3D> support = Arrays.asList(new Cartesian3D(1, 2, 3));
-        EnclosingBall<Euclidean3D, Cartesian3D> sphere = new SphereGenerator().ballOnSupport(support);
-        Assert.assertEquals(0.0, sphere.getRadius(), 1.0e-10);
-        Assert.assertTrue(sphere.contains(support.get(0)));
-        Assert.assertTrue(sphere.contains(support.get(0), 0.5));
-        Assert.assertFalse(sphere.contains(new Cartesian3D(support.get(0).getX() + 0.1,
-                                                        support.get(0).getY() + 0.1,
-                                                        support.get(0).getZ() + 0.1),
-                                           0.001));
-        Assert.assertTrue(sphere.contains(new Cartesian3D(support.get(0).getX() + 0.1,
-                                                       support.get(0).getY() + 0.1,
-                                                       support.get(0).getZ() + 0.1),
-                                          0.5));
-        Assert.assertEquals(0, support.get(0).distance(sphere.getCenter()), 1.0e-10);
-        Assert.assertEquals(1, sphere.getSupportSize());
-        Assert.assertTrue(support.get(0) == sphere.getSupport()[0]);
-    }
-
-    @Test
-    public void testSupport2Points() {
-        List<Cartesian3D> support = Arrays.asList(new Cartesian3D(1, 0, 0),
-                                               new Cartesian3D(3, 0, 0));
-        EnclosingBall<Euclidean3D, Cartesian3D> sphere = new SphereGenerator().ballOnSupport(support);
-        Assert.assertEquals(1.0, sphere.getRadius(), 1.0e-10);
-        int i = 0;
-        for (Cartesian3D v : support) {
-            Assert.assertTrue(sphere.contains(v));
-            Assert.assertEquals(1.0, v.distance(sphere.getCenter()), 1.0e-10);
-            Assert.assertTrue(v == sphere.getSupport()[i++]);
-        }
-        Assert.assertTrue(sphere.contains(new Cartesian3D(2, 0.9, 0)));
-        Assert.assertFalse(sphere.contains(Cartesian3D.ZERO));
-        Assert.assertEquals(0.0, new Cartesian3D(2, 0, 0).distance(sphere.getCenter()), 1.0e-10);
-        Assert.assertEquals(2, sphere.getSupportSize());
-    }
-
-    @Test
-    public void testSupport3Points() {
-        List<Cartesian3D> support = Arrays.asList(new Cartesian3D(1, 0, 0),
-                                               new Cartesian3D(3, 0, 0),
-                                               new Cartesian3D(2, 2, 0));
-        EnclosingBall<Euclidean3D, Cartesian3D> sphere = new SphereGenerator().ballOnSupport(support);
-        Assert.assertEquals(5.0 / 4.0, sphere.getRadius(), 1.0e-10);
-        int i = 0;
-        for (Cartesian3D v : support) {
-            Assert.assertTrue(sphere.contains(v));
-            Assert.assertEquals(5.0 / 4.0, v.distance(sphere.getCenter()), 1.0e-10);
-            Assert.assertTrue(v == sphere.getSupport()[i++]);
-        }
-        Assert.assertTrue(sphere.contains(new Cartesian3D(2, 0.9, 0)));
-        Assert.assertFalse(sphere.contains(new Cartesian3D(0.9,  0, 0)));
-        Assert.assertFalse(sphere.contains(new Cartesian3D(3.1,  0, 0)));
-        Assert.assertTrue(sphere.contains(new Cartesian3D(2.0, -0.499, 0)));
-        Assert.assertFalse(sphere.contains(new Cartesian3D(2.0, -0.501, 0)));
-        Assert.assertTrue(sphere.contains(new Cartesian3D(2.0, 3.0 / 4.0, -1.249)));
-        Assert.assertFalse(sphere.contains(new Cartesian3D(2.0, 3.0 / 4.0, -1.251)));
-        Assert.assertEquals(0.0, new Cartesian3D(2.0, 3.0 / 4.0, 0).distance(sphere.getCenter()), 1.0e-10);
-        Assert.assertEquals(3, sphere.getSupportSize());
-    }
-
-    @Test
-    public void testSupport4Points() {
-        List<Cartesian3D> support = Arrays.asList(new Cartesian3D(17, 14,  18),
-                                               new Cartesian3D(11, 14,  22),
-                                               new Cartesian3D( 2, 22,  17),
-                                               new Cartesian3D(22, 11, -10));
-        EnclosingBall<Euclidean3D, Cartesian3D> sphere = new SphereGenerator().ballOnSupport(support);
-        Assert.assertEquals(25.0, sphere.getRadius(), 1.0e-10);
-        int i = 0;
-        for (Cartesian3D v : support) {
-            Assert.assertTrue(sphere.contains(v));
-            Assert.assertEquals(25.0, v.distance(sphere.getCenter()), 1.0e-10);
-            Assert.assertTrue(v == sphere.getSupport()[i++]);
-        }
-        Assert.assertTrue(sphere.contains (new Cartesian3D(-22.999, 2, 2)));
-        Assert.assertFalse(sphere.contains(new Cartesian3D(-23.001, 2, 2)));
-        Assert.assertTrue(sphere.contains (new Cartesian3D( 26.999, 2, 2)));
-        Assert.assertFalse(sphere.contains(new Cartesian3D( 27.001, 2, 2)));
-        Assert.assertTrue(sphere.contains (new Cartesian3D(2, -22.999, 2)));
-        Assert.assertFalse(sphere.contains(new Cartesian3D(2, -23.001, 2)));
-        Assert.assertTrue(sphere.contains (new Cartesian3D(2,  26.999, 2)));
-        Assert.assertFalse(sphere.contains(new Cartesian3D(2,  27.001, 2)));
-        Assert.assertTrue(sphere.contains (new Cartesian3D(2, 2, -22.999)));
-        Assert.assertFalse(sphere.contains(new Cartesian3D(2, 2, -23.001)));
-        Assert.assertTrue(sphere.contains (new Cartesian3D(2, 2,  26.999)));
-        Assert.assertFalse(sphere.contains(new Cartesian3D(2, 2,  27.001)));
-        Assert.assertEquals(0.0, new Cartesian3D(2.0, 2.0, 2.0).distance(sphere.getCenter()), 1.0e-10);
-        Assert.assertEquals(4, sphere.getSupportSize());
-    }
-
-    @Test
-    public void testRandom() {
-        final UniformRandomProvider random = RandomSource.create(RandomSource.WELL_1024_A,
-                                                                 0xd015982e9f31ee04l);
-        final UnitSphereSampler sr = new UnitSphereSampler(3, random);
-        for (int i = 0; i < 100; ++i) {
-            double d = 25 * random.nextDouble();
-            double refRadius = 10 * random.nextDouble();
-            Cartesian3D refCenter = new Cartesian3D(d, new Cartesian3D(sr.nextVector()));
-            List<Cartesian3D> support = new ArrayList<>();
-            for (int j = 0; j < 5; ++j) {
-                support.add(new Cartesian3D(1.0, refCenter, refRadius, new Cartesian3D(sr.nextVector())));
-            }
-            EnclosingBall<Euclidean3D, Cartesian3D> sphere = new SphereGenerator().ballOnSupport(support);
-            Assert.assertEquals(0.0, refCenter.distance(sphere.getCenter()), 4e-7 * refRadius);
-            Assert.assertEquals(refRadius, sphere.getRadius(), 1e-7 * refRadius);
-        }
-    }
-
-    @Test
-    public void testDegeneratedCase() {
-       final List<Cartesian3D> support =
-               Arrays.asList(new Cartesian3D(FastMath.scalb(-8039905610797991.0, -50),   //   -7.140870659936730
-                                          FastMath.scalb(-4663475464714142.0, -48),   //  -16.567993074240455
-                                          FastMath.scalb( 6592658872616184.0, -49)),  //   11.710914678204503
-                             new Cartesian3D(FastMath.scalb(-8036658568968473.0, -50),   //   -7.137986707455888
-                                          FastMath.scalb(-4664256346424880.0, -48),   //  -16.570767323375720
-                                          FastMath.scalb( 6591357011730307.0, -49)),  //  11.708602108715928)
-                             new Cartesian3D(FastMath.scalb(-8037820142977230.0, -50),   //   -7.139018392423351
-                                          FastMath.scalb(-4665280434237813.0, -48),   //  -16.574405614157020
-                                          FastMath.scalb( 6592435966112099.0, -49)),  //   11.710518716711425
-                             new Cartesian3D(FastMath.scalb(-8038007803611611.0, -50),   //   -7.139185068549035
-                                          FastMath.scalb(-4664291215918380.0, -48),   //  -16.570891204702250
-                                          FastMath.scalb( 6595270610894208.0, -49))); //   11.715554057357394
-        EnclosingBall<Euclidean3D, Cartesian3D> sphere = new SphereGenerator().ballOnSupport(support);
-
-        // the following values have been computed using Emacs calc with exact arithmetic from the
-        // rational representation corresponding to the scalb calls (i.e. -8039905610797991/2^50, ...)
-        // The results were converted to decimal representation rounded to 1.0e-30 when writing the reference
-        // values in this test
-        Assert.assertEquals(  0.003616820213530053297575846168, sphere.getRadius(),        1.0e-20);
-        Assert.assertEquals( -7.139325643360503322823511839511, sphere.getCenter().getX(), 1.0e-20);
-        Assert.assertEquals(-16.571096474251747245361467833760, sphere.getCenter().getY(), 1.0e-20);
-        Assert.assertEquals( 11.711945804096960876521111630800, sphere.getCenter().getZ(), 1.0e-20);
-
-        for (Cartesian3D v : support) {
-            Assert.assertTrue(sphere.contains(v, 1.0e-14));
-        }
-
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/SphericalCoordinatesTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/SphericalCoordinatesTest.java
deleted file mode 100644
index 6b72072..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/SphericalCoordinatesTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * 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 org.apache.commons.math4.TestUtils;
-import org.apache.commons.math4.analysis.differentiation.DerivativeStructure;
-import org.apache.commons.math4.exception.DimensionMismatchException;
-import org.apache.commons.math4.geometry.euclidean.threed.SphericalCoordinates;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.util.FastMath;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SphericalCoordinatesTest {
-
-    @Test
-    public void testCoordinatesStoC() throws DimensionMismatchException {
-        double piO2 = 0.5 * FastMath.PI;
-        SphericalCoordinates sc1 = new SphericalCoordinates(2.0, 0, piO2);
-        Assert.assertEquals(0, sc1.getCartesian().distance(new Cartesian3D(2, 0, 0)), 1.0e-10);
-        SphericalCoordinates sc2 = new SphericalCoordinates(2.0, piO2, piO2);
-        Assert.assertEquals(0, sc2.getCartesian().distance(new Cartesian3D(0, 2, 0)), 1.0e-10);
-        SphericalCoordinates sc3 = new SphericalCoordinates(2.0, FastMath.PI, piO2);
-        Assert.assertEquals(0, sc3.getCartesian().distance(new Cartesian3D(-2, 0, 0)), 1.0e-10);
-        SphericalCoordinates sc4 = new SphericalCoordinates(2.0, -piO2, piO2);
-        Assert.assertEquals(0, sc4.getCartesian().distance(new Cartesian3D(0, -2, 0)), 1.0e-10);
-        SphericalCoordinates sc5 = new SphericalCoordinates(2.0, 1.23456, 0);
-        Assert.assertEquals(0, sc5.getCartesian().distance(new Cartesian3D(0, 0, 2)), 1.0e-10);
-        SphericalCoordinates sc6 = new SphericalCoordinates(2.0, 6.54321, FastMath.PI);
-        Assert.assertEquals(0, sc6.getCartesian().distance(new Cartesian3D(0, 0, -2)), 1.0e-10);
-    }
-
-    @Test
-    public void testCoordinatesCtoS() throws DimensionMismatchException {
-        double piO2 = 0.5 * FastMath.PI;
-        SphericalCoordinates sc1 = new SphericalCoordinates(new Cartesian3D(2, 0, 0));
-        Assert.assertEquals(2,           sc1.getR(),     1.0e-10);
-        Assert.assertEquals(0,           sc1.getTheta(), 1.0e-10);
-        Assert.assertEquals(piO2,        sc1.getPhi(),   1.0e-10);
-        SphericalCoordinates sc2 = new SphericalCoordinates(new Cartesian3D(0, 2, 0));
-        Assert.assertEquals(2,           sc2.getR(),     1.0e-10);
-        Assert.assertEquals(piO2,        sc2.getTheta(), 1.0e-10);
-        Assert.assertEquals(piO2,        sc2.getPhi(),   1.0e-10);
-        SphericalCoordinates sc3 = new SphericalCoordinates(new Cartesian3D(-2, 0, 0));
-        Assert.assertEquals(2,           sc3.getR(),     1.0e-10);
-        Assert.assertEquals(FastMath.PI, sc3.getTheta(), 1.0e-10);
-        Assert.assertEquals(piO2,        sc3.getPhi(),   1.0e-10);
-        SphericalCoordinates sc4 = new SphericalCoordinates(new Cartesian3D(0, -2, 0));
-        Assert.assertEquals(2,           sc4.getR(),     1.0e-10);
-        Assert.assertEquals(-piO2,       sc4.getTheta(), 1.0e-10);
-        Assert.assertEquals(piO2,        sc4.getPhi(),   1.0e-10);
-        SphericalCoordinates sc5 = new SphericalCoordinates(new Cartesian3D(0, 0, 2));
-        Assert.assertEquals(2,           sc5.getR(),     1.0e-10);
-        //  don't check theta on poles, as it is singular
-        Assert.assertEquals(0,           sc5.getPhi(),   1.0e-10);
-        SphericalCoordinates sc6 = new SphericalCoordinates(new Cartesian3D(0, 0, -2));
-        Assert.assertEquals(2,           sc6.getR(),     1.0e-10);
-        //  don't check theta on poles, as it is singular
-        Assert.assertEquals(FastMath.PI, sc6.getPhi(),   1.0e-10);
-    }
-
-    @Test
-    public void testGradient() {
-        for (double r = 0.2; r < 10; r += 0.5) {
-            for (double theta = 0; theta < 2 * FastMath.PI; theta += 0.1) {
-                for (double phi = 0.1; phi < FastMath.PI; phi += 0.1) {
-                    SphericalCoordinates sc = new SphericalCoordinates(r, theta, phi);
-
-                    DerivativeStructure svalue = valueSpherical(new DerivativeStructure(3, 1, 0, r),
-                                                                new DerivativeStructure(3, 1, 1, theta),
-                                                                new DerivativeStructure(3, 1, 2, phi));
-                    double[] sGradient = new double[] {
-                        svalue.getPartialDerivative(1, 0, 0),
-                        svalue.getPartialDerivative(0, 1, 0),
-                        svalue.getPartialDerivative(0, 0, 1),
-                    };
-
-                    DerivativeStructure cvalue = valueCartesian(new DerivativeStructure(3, 1, 0, sc.getCartesian().getX()),
-                                                                new DerivativeStructure(3, 1, 1, sc.getCartesian().getY()),
-                                                                new DerivativeStructure(3, 1, 2, sc.getCartesian().getZ()));
-                    Cartesian3D refCGradient = new Cartesian3D(cvalue.getPartialDerivative(1, 0, 0),
-                                                         cvalue.getPartialDerivative(0, 1, 0),
-                                                         cvalue.getPartialDerivative(0, 0, 1));
-
-                    Cartesian3D testCGradient = new Cartesian3D(sc.toCartesianGradient(sGradient));
-
-                    Assert.assertEquals(0, testCGradient.distance(refCGradient) / refCGradient.getNorm(), 5.0e-14);
-
-                }
-            }
-        }
-    }
-
-    @Test
-    public void testHessian() {
-        for (double r = 0.2; r < 10; r += 0.5) {
-            for (double theta = 0; theta < 2 * FastMath.PI; theta += 0.2) {
-                for (double phi = 0.1; phi < FastMath.PI; phi += 0.2) {
-                    SphericalCoordinates sc = new SphericalCoordinates(r, theta, phi);
-
-                    DerivativeStructure svalue = valueSpherical(new DerivativeStructure(3, 2, 0, r),
-                                                                new DerivativeStructure(3, 2, 1, theta),
-                                                                new DerivativeStructure(3, 2, 2, phi));
-                    double[] sGradient = new double[] {
-                        svalue.getPartialDerivative(1, 0, 0),
-                        svalue.getPartialDerivative(0, 1, 0),
-                        svalue.getPartialDerivative(0, 0, 1),
-                    };
-                    double[][] sHessian = new double[3][3];
-                    sHessian[0][0] = svalue.getPartialDerivative(2, 0, 0); // d2F/dR2
-                    sHessian[1][0] = svalue.getPartialDerivative(1, 1, 0); // d2F/dRdTheta
-                    sHessian[2][0] = svalue.getPartialDerivative(1, 0, 1); // d2F/dRdPhi
-                    sHessian[0][1] = Double.NaN; // just to check upper-right part is not used
-                    sHessian[1][1] = svalue.getPartialDerivative(0, 2, 0); // d2F/dTheta2
-                    sHessian[2][1] = svalue.getPartialDerivative(0, 1, 1); // d2F/dThetadPhi
-                    sHessian[0][2] = Double.NaN; // just to check upper-right part is not used
-                    sHessian[1][2] = Double.NaN; // just to check upper-right part is not used
-                    sHessian[2][2] = svalue.getPartialDerivative(0, 0, 2); // d2F/dPhi2
-
-                    DerivativeStructure cvalue = valueCartesian(new DerivativeStructure(3, 2, 0, sc.getCartesian().getX()),
-                                                                new DerivativeStructure(3, 2, 1, sc.getCartesian().getY()),
-                                                                new DerivativeStructure(3, 2, 2, sc.getCartesian().getZ()));
-                    double[][] refCHessian = new double[3][3];
-                    refCHessian[0][0] = cvalue.getPartialDerivative(2, 0, 0); // d2F/dX2
-                    refCHessian[1][0] = cvalue.getPartialDerivative(1, 1, 0); // d2F/dXdY
-                    refCHessian[2][0] = cvalue.getPartialDerivative(1, 0, 1); // d2F/dXdZ
-                    refCHessian[0][1] = refCHessian[1][0];
-                    refCHessian[1][1] = cvalue.getPartialDerivative(0, 2, 0); // d2F/dY2
-                    refCHessian[2][1] = cvalue.getPartialDerivative(0, 1, 1); // d2F/dYdZ
-                    refCHessian[0][2] = refCHessian[2][0];
-                    refCHessian[1][2] = refCHessian[2][1];
-                    refCHessian[2][2] = cvalue.getPartialDerivative(0, 0, 2); // d2F/dZ2
-                    double norm =  0;
-                    for (int i = 0; i < 3; ++i) {
-                        for (int j = 0; j < 3; ++j) {
-                            norm = FastMath.max(norm, FastMath.abs(refCHessian[i][j]));
-                        }
-                    }
-
-                    double[][] testCHessian = sc.toCartesianHessian(sHessian, sGradient);
-                    for (int i = 0; i < 3; ++i) {
-                        for (int j = 0; j < 3; ++j) {
-                            Assert.assertEquals("" + FastMath.abs((refCHessian[i][j] - testCHessian[i][j]) / norm),
-                                                refCHessian[i][j], testCHessian[i][j], 1.0e-14 * norm);
-                        }
-                    }
-
-                }
-            }
-        }
-    }
-
-    public DerivativeStructure valueCartesian(DerivativeStructure x, DerivativeStructure y, DerivativeStructure z) {
-        return x.divide(y.multiply(5).add(10)).multiply(z.pow(3));
-    }
-
-    public DerivativeStructure valueSpherical(DerivativeStructure r, DerivativeStructure theta, DerivativeStructure phi) {
-        return valueCartesian(r.multiply(theta.cos()).multiply(phi.sin()),
-                              r.multiply(theta.sin()).multiply(phi.sin()),
-                              r.multiply(phi.cos()));
-    }
-
-    @Test
-    public void testSerialization() {
-        SphericalCoordinates a = new SphericalCoordinates(3, 2, 1);
-        SphericalCoordinates b = (SphericalCoordinates) TestUtils.serializeAndRecover(a);
-        Assert.assertEquals(0, a.getCartesian().distance(b.getCartesian()), 1.0e-10);
-        Assert.assertEquals(a.getR(),     b.getR(),     1.0e-10);
-        Assert.assertEquals(a.getTheta(), b.getTheta(), 1.0e-10);
-        Assert.assertEquals(a.getPhi(),   b.getPhi(),   1.0e-10);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/SubLineTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/SubLineTest.java
deleted file mode 100644
index aab6398..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/SubLineTest.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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.util.List;
-
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-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.threed.Line;
-import org.apache.commons.math4.geometry.euclidean.threed.Segment;
-import org.apache.commons.math4.geometry.euclidean.threed.SubLine;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.geometry.partitioning.RegionFactory;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SubLineTest {
-
-    @Test
-    public void testEndPoints() throws MathIllegalArgumentException {
-        Cartesian3D p1 = new Cartesian3D(-1, -7, 2);
-        Cartesian3D p2 = new Cartesian3D(7, -1, 0);
-        Segment segment = new Segment(p1, p2, new Line(p1, p2, 1.0e-10));
-        SubLine sub = new SubLine(segment);
-        List<Segment> segments = sub.getSegments();
-        Assert.assertEquals(1, segments.size());
-        Assert.assertEquals(0.0, new Cartesian3D(-1, -7, 2).distance(segments.get(0).getStart()), 1.0e-10);
-        Assert.assertEquals(0.0, new Cartesian3D( 7, -1, 0).distance(segments.get(0).getEnd()), 1.0e-10);
-    }
-
-    @Test
-    public void testNoEndPoints() throws MathIllegalArgumentException {
-        SubLine wholeLine = new Line(new Cartesian3D(-1, 7, 2), new Cartesian3D(7, 1, 0), 1.0e-10).wholeLine();
-        List<Segment> segments = wholeLine.getSegments();
-        Assert.assertEquals(1, segments.size());
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getX()) &&
-                          segments.get(0).getStart().getX() < 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getY()) &&
-                          segments.get(0).getStart().getY() > 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getZ()) &&
-                          segments.get(0).getStart().getZ() > 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getX()) &&
-                          segments.get(0).getEnd().getX() > 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getY()) &&
-                          segments.get(0).getEnd().getY() < 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getZ()) &&
-                          segments.get(0).getEnd().getZ() < 0);
-    }
-
-    @Test
-    public void testNoSegments() throws MathIllegalArgumentException {
-        SubLine empty = new SubLine(new Line(new Cartesian3D(-1, -7, 2), new Cartesian3D(7, -1, 0), 1.0e-10),
-                                    (IntervalsSet) new RegionFactory<Euclidean1D>().getComplement(new IntervalsSet(1.0e-10)));
-        List<Segment> segments = empty.getSegments();
-        Assert.assertEquals(0, segments.size());
-    }
-
-    @Test
-    public void testSeveralSegments() throws MathIllegalArgumentException {
-        SubLine twoSubs = new SubLine(new Line(new Cartesian3D(-1, -7, 2), new Cartesian3D(7, -1, 0), 1.0e-10),
-                                      (IntervalsSet) new RegionFactory<Euclidean1D>().union(new IntervalsSet(1, 2, 1.0e-10),
-                                                                                            new IntervalsSet(3, 4, 1.0e-10)));
-        List<Segment> segments = twoSubs.getSegments();
-        Assert.assertEquals(2, segments.size());
-    }
-
-    @Test
-    public void testHalfInfiniteNeg() throws MathIllegalArgumentException {
-        SubLine empty = new SubLine(new Line(new Cartesian3D(-1, -7, 2), new Cartesian3D(7, -1, -2), 1.0e-10),
-                                    new IntervalsSet(Double.NEGATIVE_INFINITY, 0.0, 1.0e-10));
-        List<Segment> segments = empty.getSegments();
-        Assert.assertEquals(1, segments.size());
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getX()) &&
-                          segments.get(0).getStart().getX() < 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getY()) &&
-                          segments.get(0).getStart().getY() < 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getZ()) &&
-                          segments.get(0).getStart().getZ() > 0);
-        Assert.assertEquals(0.0, new Cartesian3D(3, -4, 0).distance(segments.get(0).getEnd()), 1.0e-10);
-    }
-
-    @Test
-    public void testHalfInfinitePos() throws MathIllegalArgumentException {
-        SubLine empty = new SubLine(new Line(new Cartesian3D(-1, -7, 2), new Cartesian3D(7, -1, -2), 1.0e-10),
-                                    new IntervalsSet(0.0, Double.POSITIVE_INFINITY, 1.0e-10));
-        List<Segment> segments = empty.getSegments();
-        Assert.assertEquals(1, segments.size());
-        Assert.assertEquals(0.0, new Cartesian3D(3, -4, 0).distance(segments.get(0).getStart()), 1.0e-10);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getX()) &&
-                          segments.get(0).getEnd().getX() > 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getY()) &&
-                          segments.get(0).getEnd().getY() > 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getZ()) &&
-                          segments.get(0).getEnd().getZ() < 0);
-    }
-
-    @Test
-    public void testIntersectionInsideInside() throws MathIllegalArgumentException {
-        SubLine sub1 = new SubLine(new Cartesian3D(1, 1, 1), new Cartesian3D(3, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian3D(2, 0, 0), new Cartesian3D(2, 2, 2), 1.0e-10);
-        Assert.assertEquals(0.0, new Cartesian3D(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
-        Assert.assertEquals(0.0, new Cartesian3D(2, 1, 1).distance(sub1.intersection(sub2, false)), 1.0e-12);
-    }
-
-    @Test
-    public void testIntersectionInsideBoundary() throws MathIllegalArgumentException {
-        SubLine sub1 = new SubLine(new Cartesian3D(1, 1, 1), new Cartesian3D(3, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian3D(2, 0, 0), new Cartesian3D(2, 1, 1), 1.0e-10);
-        Assert.assertEquals(0.0, new Cartesian3D(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-    @Test
-    public void testIntersectionInsideOutside() throws MathIllegalArgumentException {
-        SubLine sub1 = new SubLine(new Cartesian3D(1, 1, 1), new Cartesian3D(3, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian3D(2, 0, 0), new Cartesian3D(2, 0.5, 0.5), 1.0e-10);
-        Assert.assertNull(sub1.intersection(sub2, true));
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-    @Test
-    public void testIntersectionBoundaryBoundary() throws MathIllegalArgumentException {
-        SubLine sub1 = new SubLine(new Cartesian3D(1, 1, 1), new Cartesian3D(2, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian3D(2, 0, 0), new Cartesian3D(2, 1, 1), 1.0e-10);
-        Assert.assertEquals(0.0, new Cartesian3D(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-    @Test
-    public void testIntersectionBoundaryOutside() throws MathIllegalArgumentException {
-        SubLine sub1 = new SubLine(new Cartesian3D(1, 1, 1), new Cartesian3D(2, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian3D(2, 0, 0), new Cartesian3D(2, 0.5, 0.5), 1.0e-10);
-        Assert.assertNull(sub1.intersection(sub2, true));
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-    @Test
-    public void testIntersectionOutsideOutside() throws MathIllegalArgumentException {
-        SubLine sub1 = new SubLine(new Cartesian3D(1, 1, 1), new Cartesian3D(1.5, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian3D(2, 0, 0), new Cartesian3D(2, 0.5, 0.5), 1.0e-10);
-        Assert.assertNull(sub1.intersection(sub2, true));
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-    @Test
-    public void testIntersectionNotIntersecting() throws MathIllegalArgumentException {
-        SubLine sub1 = new SubLine(new Cartesian3D(1, 1, 1), new Cartesian3D(1.5, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian3D(2, 3, 0), new Cartesian3D(2, 3, 0.5), 1.0e-10);
-        Assert.assertNull(sub1.intersection(sub2, true));
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DFormatAbstractTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DFormatAbstractTest.java
deleted file mode 100644
index 5d03373..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DFormatAbstractTest.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * 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.text.NumberFormat;
-import java.text.ParsePosition;
-import java.util.Locale;
-
-import org.apache.commons.math4.exception.MathParseException;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.geometry.euclidean.threed.Vector3DFormat;
-import org.junit.Test;
-import org.junit.Assert;
-
-public abstract class Vector3DFormatAbstractTest {
-
-    Vector3DFormat vector3DFormat = null;
-    Vector3DFormat vector3DFormatSquare = null;
-
-    protected abstract Locale getLocale();
-
-    protected abstract char getDecimalCharacter();
-
-    protected Vector3DFormatAbstractTest() {
-        vector3DFormat = Vector3DFormat.getInstance(getLocale());
-        final NumberFormat nf = NumberFormat.getInstance(getLocale());
-        nf.setMaximumFractionDigits(2);
-        vector3DFormatSquare = new Vector3DFormat("[", "]", " : ", nf);
-    }
-
-    @Test
-    public void testSimpleNoDecimals() {
-        Cartesian3D c = new Cartesian3D(1, 1, 1);
-        String expected = "{1; 1; 1}";
-        String actual = vector3DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testSimpleWithDecimals() {
-        Cartesian3D c = new Cartesian3D(1.23, 1.43, 1.63);
-        String expected =
-            "{1"    + getDecimalCharacter() +
-            "23; 1" + getDecimalCharacter() +
-            "43; 1" + getDecimalCharacter() +
-            "63}";
-        String actual = vector3DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testSimpleWithDecimalsTrunc() {
-        Cartesian3D c = new Cartesian3D(1.232323232323, 1.434343434343, 1.633333333333);
-        String expected =
-            "{1"    + getDecimalCharacter() +
-            "2323232323; 1" + getDecimalCharacter() +
-            "4343434343; 1" + getDecimalCharacter() +
-            "6333333333}";
-        String actual = vector3DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testNegativeX() {
-        Cartesian3D c = new Cartesian3D(-1.232323232323, 1.43, 1.63);
-        String expected =
-            "{-1"    + getDecimalCharacter() +
-            "2323232323; 1" + getDecimalCharacter() +
-            "43; 1" + getDecimalCharacter() +
-            "63}";
-        String actual = vector3DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testNegativeY() {
-        Cartesian3D c = new Cartesian3D(1.23, -1.434343434343, 1.63);
-        String expected =
-            "{1"    + getDecimalCharacter() +
-            "23; -1" + getDecimalCharacter() +
-            "4343434343; 1" + getDecimalCharacter() +
-            "63}";
-        String actual = vector3DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testNegativeZ() {
-        Cartesian3D c = new Cartesian3D(1.23, 1.43, -1.633333333333);
-        String expected =
-            "{1"    + getDecimalCharacter() +
-            "23; 1" + getDecimalCharacter() +
-            "43; -1" + getDecimalCharacter() +
-            "6333333333}";
-        String actual = vector3DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testNonDefaultSetting() {
-        Cartesian3D c = new Cartesian3D(1, 1, 1);
-        String expected = "[1 : 1 : 1]";
-        String actual = vector3DFormatSquare.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testDefaultFormatVector3D() {
-        Locale defaultLocal = Locale.getDefault();
-        Locale.setDefault(getLocale());
-
-        Cartesian3D c = new Cartesian3D(232.22222222222, -342.3333333333, 432.44444444444);
-        String expected =
-            "{232"    + getDecimalCharacter() +
-            "2222222222; -342" + getDecimalCharacter() +
-            "3333333333; 432" + getDecimalCharacter() +
-            "4444444444}";
-        String actual = (new Vector3DFormat()).format(c);
-        Assert.assertEquals(expected, actual);
-
-        Locale.setDefault(defaultLocal);
-    }
-
-    @Test
-    public void testNan() {
-        Cartesian3D c = Cartesian3D.NaN;
-        String expected = "{(NaN); (NaN); (NaN)}";
-        String actual = vector3DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testPositiveInfinity() {
-        Cartesian3D c = Cartesian3D.POSITIVE_INFINITY;
-        String expected = "{(Infinity); (Infinity); (Infinity)}";
-        String actual = vector3DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void tesNegativeInfinity() {
-        Cartesian3D c = Cartesian3D.NEGATIVE_INFINITY;
-        String expected = "{(-Infinity); (-Infinity); (-Infinity)}";
-        String actual = vector3DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseSimpleNoDecimals() throws MathParseException {
-        String source = "{1; 1; 1}";
-        Vector3D expected = new Cartesian3D(1, 1, 1);
-        Vector3D actual = vector3DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseIgnoredWhitespace() {
-        Cartesian3D expected = new Cartesian3D(1, 1, 1);
-        ParsePosition pos1 = new ParsePosition(0);
-        String source1 = "{1;1;1}";
-        Assert.assertEquals(expected, vector3DFormat.parse(source1, pos1));
-        Assert.assertEquals(source1.length(), pos1.getIndex());
-        ParsePosition pos2 = new ParsePosition(0);
-        String source2 = " { 1 ; 1 ; 1 } ";
-        Assert.assertEquals(expected, vector3DFormat.parse(source2, pos2));
-        Assert.assertEquals(source2.length() - 1, pos2.getIndex());
-    }
-
-    @Test
-    public void testParseSimpleWithDecimals() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "23; 1" + getDecimalCharacter() +
-            "43; 1" + getDecimalCharacter() +
-            "63}";
-        Vector3D expected = new Cartesian3D(1.23, 1.43, 1.63);
-        Vector3D actual = vector3DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseSimpleWithDecimalsTrunc() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "2323; 1" + getDecimalCharacter() +
-            "4343; 1" + getDecimalCharacter() +
-            "6333}";
-        Vector3D expected = new Cartesian3D(1.2323, 1.4343, 1.6333);
-        Vector3D actual = vector3DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeX() throws MathParseException {
-        String source =
-            "{-1" + getDecimalCharacter() +
-            "2323; 1" + getDecimalCharacter() +
-            "4343; 1" + getDecimalCharacter() +
-            "6333}";
-        Vector3D expected = new Cartesian3D(-1.2323, 1.4343, 1.6333);
-        Vector3D actual = vector3DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeY() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "2323; -1" + getDecimalCharacter() +
-            "4343; 1" + getDecimalCharacter() +
-            "6333}";
-        Vector3D expected = new Cartesian3D(1.2323, -1.4343, 1.6333);
-        Vector3D actual = vector3DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeZ() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "2323; 1" + getDecimalCharacter() +
-            "4343; -1" + getDecimalCharacter() +
-            "6333}";
-        Vector3D expected = new Cartesian3D(1.2323, 1.4343, -1.6333);
-        Vector3D actual = vector3DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeAll() throws MathParseException {
-        String source =
-            "{-1" + getDecimalCharacter() +
-            "2323; -1" + getDecimalCharacter() +
-            "4343; -1" + getDecimalCharacter() +
-            "6333}";
-        Vector3D expected = new Cartesian3D(-1.2323, -1.4343, -1.6333);
-        Vector3D actual = vector3DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseZeroX() throws MathParseException {
-        String source =
-            "{0" + getDecimalCharacter() +
-            "0; -1" + getDecimalCharacter() +
-            "4343; 1" + getDecimalCharacter() +
-            "6333}";
-        Vector3D expected = new Cartesian3D(0.0, -1.4343, 1.6333);
-        Vector3D actual = vector3DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNonDefaultSetting() throws MathParseException {
-        String source =
-            "[1" + getDecimalCharacter() +
-            "2323 : 1" + getDecimalCharacter() +
-            "4343 : 1" + getDecimalCharacter() +
-            "6333]";
-        Vector3D expected = new Cartesian3D(1.2323, 1.4343, 1.6333);
-        Vector3D actual = vector3DFormatSquare.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNan() throws MathParseException {
-        String source = "{(NaN); (NaN); (NaN)}";
-        Vector3D actual = vector3DFormat.parse(source);
-        Assert.assertEquals(Cartesian3D.NaN, actual);
-    }
-
-    @Test
-    public void testParsePositiveInfinity() throws MathParseException {
-        String source = "{(Infinity); (Infinity); (Infinity)}";
-        Vector3D actual = vector3DFormat.parse(source);
-        Assert.assertEquals(Cartesian3D.POSITIVE_INFINITY, actual);
-    }
-
-    @Test
-    public void testParseNegativeInfinity() throws MathParseException {
-        String source = "{(-Infinity); (-Infinity); (-Infinity)}";
-        Vector3D actual = vector3DFormat.parse(source);
-        Assert.assertEquals(Cartesian3D.NEGATIVE_INFINITY, actual);
-    }
-
-    @Test
-    public void testConstructorSingleFormat() {
-        NumberFormat nf = NumberFormat.getInstance();
-        Vector3DFormat cf = new Vector3DFormat(nf);
-        Assert.assertNotNull(cf);
-        Assert.assertEquals(nf, cf.getFormat());
-    }
-
-    @Test
-    public void testForgottenPrefix() {
-        ParsePosition pos = new ParsePosition(0);
-        Assert.assertNull(new Vector3DFormat().parse("1; 1; 1}", pos));
-        Assert.assertEquals(0, pos.getErrorIndex());
-    }
-
-    @Test
-    public void testForgottenSeparator() {
-        ParsePosition pos = new ParsePosition(0);
-        Assert.assertNull(new Vector3DFormat().parse("{1; 1 1}", pos));
-        Assert.assertEquals(6, pos.getErrorIndex());
-    }
-
-    @Test
-    public void testForgottenSuffix() {
-        ParsePosition pos = new ParsePosition(0);
-        Assert.assertNull(new Vector3DFormat().parse("{1; 1; 1 ", pos));
-        Assert.assertEquals(8, pos.getErrorIndex());
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DFormatTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DFormatTest.java
deleted file mode 100644
index a316d34..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DFormatTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.util.Locale;
-
-
-public class Vector3DFormatTest extends Vector3DFormatAbstractTest {
-
-    @Override
-    protected char getDecimalCharacter() {
-        return '.';
-    }
-
-    @Override
-    protected Locale getLocale() {
-        return Locale.US;
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DTest.java
deleted file mode 100644
index 0f466b7..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/Vector3DTest.java
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * 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.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.NumberFormat;
-import java.util.Locale;
-
-import org.apache.commons.math4.TestUtils;
-import org.apache.commons.math4.exception.DimensionMismatchException;
-import org.apache.commons.math4.exception.MathArithmeticException;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.rng.UniformRandomProvider;
-import org.apache.commons.rng.simple.RandomSource;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.numbers.core.Precision;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class Vector3DTest {
-    @Test
-    public void testConstructors() throws DimensionMismatchException {
-        double r = FastMath.sqrt(2) /2;
-        checkVector(new Cartesian3D(2, new Cartesian3D(FastMath.PI / 3, -FastMath.PI / 4)),
-                    r, r * FastMath.sqrt(3), -2 * r);
-        checkVector(new Cartesian3D(2, Cartesian3D.PLUS_I,
-                                 -3, Cartesian3D.MINUS_K),
-                    2, 0, 3);
-        checkVector(new Cartesian3D(2, Cartesian3D.PLUS_I,
-                                 5, Cartesian3D.PLUS_J,
-                                 -3, Cartesian3D.MINUS_K),
-                    2, 5, 3);
-        checkVector(new Cartesian3D(2, Cartesian3D.PLUS_I,
-                                 5, Cartesian3D.PLUS_J,
-                                 5, Cartesian3D.MINUS_J,
-                                 -3, Cartesian3D.MINUS_K),
-                    2, 0, 3);
-        checkVector(new Cartesian3D(new double[] { 2,  5,  -3 }),
-                    2, 5, -3);
-    }
-
-    @Test
-    public void testSpace() {
-        Space space = new Cartesian3D(1, 2, 2).getSpace();
-        Assert.assertEquals(3, space.getDimension());
-        Assert.assertEquals(2, space.getSubSpace().getDimension());
-        Space deserialized = (Space) TestUtils.serializeAndRecover(space);
-        Assert.assertTrue(space == deserialized);
-    }
-
-    @Test
-    public void testZero() {
-        Assert.assertEquals(0, new Cartesian3D(1, 2, 2).getZero().getNorm(), 1.0e-15);
-    }
-
-    @Test
-    public void testEquals() {
-        Cartesian3D u1 = new Cartesian3D(1, 2, 3);
-        Cartesian3D u2 = new Cartesian3D(1, 2, 3);
-        Assert.assertTrue(u1.equals(u1));
-        Assert.assertTrue(u1.equals(u2));
-        Assert.assertFalse(u1.equals(new Rotation(1, 0, 0, 0, false)));
-        Assert.assertFalse(u1.equals(new Cartesian3D(1, 2, 3 + 10 * Precision.EPSILON)));
-        Assert.assertFalse(u1.equals(new Cartesian3D(1, 2 + 10 * Precision.EPSILON, 3)));
-        Assert.assertFalse(u1.equals(new Cartesian3D(1 + 10 * Precision.EPSILON, 2, 3)));
-        Assert.assertTrue(new Cartesian3D(0, Double.NaN, 0).equals(new Cartesian3D(0, 0, Double.NaN)));
-    }
-
-    @Test
-    public void testHash() {
-        Assert.assertEquals(new Cartesian3D(0, Double.NaN, 0).hashCode(), new Cartesian3D(0, 0, Double.NaN).hashCode());
-        Cartesian3D u = new Cartesian3D(1, 2, 3);
-        Cartesian3D v = new Cartesian3D(1, 2, 3 + 10 * Precision.EPSILON);
-        Assert.assertTrue(u.hashCode() != v.hashCode());
-    }
-
-    @Test
-    public void testInfinite() {
-        Assert.assertTrue(new Cartesian3D(1, 1, Double.NEGATIVE_INFINITY).isInfinite());
-        Assert.assertTrue(new Cartesian3D(1, Double.NEGATIVE_INFINITY, 1).isInfinite());
-        Assert.assertTrue(new Cartesian3D(Double.NEGATIVE_INFINITY, 1, 1).isInfinite());
-        Assert.assertFalse(new Cartesian3D(1, 1, 2).isInfinite());
-        Assert.assertFalse(new Cartesian3D(1, Double.NaN, Double.NEGATIVE_INFINITY).isInfinite());
-    }
-
-    @Test
-    public void testNaN() {
-        Assert.assertTrue(new Cartesian3D(1, 1, Double.NaN).isNaN());
-        Assert.assertTrue(new Cartesian3D(1, Double.NaN, 1).isNaN());
-        Assert.assertTrue(new Cartesian3D(Double.NaN, 1, 1).isNaN());
-        Assert.assertFalse(new Cartesian3D(1, 1, 2).isNaN());
-        Assert.assertFalse(new Cartesian3D(1, 1, Double.NEGATIVE_INFINITY).isNaN());
-    }
-
-    @Test
-    public void testToString() {
-        Assert.assertEquals("{3; 2; 1}", new Cartesian3D(3, 2, 1).toString());
-        NumberFormat format = new DecimalFormat("0.000", new DecimalFormatSymbols(Locale.US));
-        Assert.assertEquals("{3.000; 2.000; 1.000}", new Cartesian3D(3, 2, 1).toString(format));
-    }
-
-    @Test(expected=DimensionMismatchException.class)
-    public void testWrongDimension() throws DimensionMismatchException {
-        new Cartesian3D(new double[] { 2,  5 });
-    }
-
-    @Test
-    public void testCoordinates() {
-        Cartesian3D v = new Cartesian3D(1, 2, 3);
-        Assert.assertTrue(FastMath.abs(v.getX() - 1) < 1.0e-12);
-        Assert.assertTrue(FastMath.abs(v.getY() - 2) < 1.0e-12);
-        Assert.assertTrue(FastMath.abs(v.getZ() - 3) < 1.0e-12);
-        double[] coordinates = v.toArray();
-        Assert.assertTrue(FastMath.abs(coordinates[0] - 1) < 1.0e-12);
-        Assert.assertTrue(FastMath.abs(coordinates[1] - 2) < 1.0e-12);
-        Assert.assertTrue(FastMath.abs(coordinates[2] - 3) < 1.0e-12);
-    }
-
-    @Test
-    public void testNorm1() {
-        Assert.assertEquals(0.0, Cartesian3D.ZERO.getNorm1(), 0);
-        Assert.assertEquals(6.0, new Cartesian3D(1, -2, 3).getNorm1(), 0);
-    }
-
-    @Test
-    public void testNorm() {
-        Assert.assertEquals(0.0, Cartesian3D.ZERO.getNorm(), 0);
-        Assert.assertEquals(FastMath.sqrt(14), new Cartesian3D(1, 2, 3).getNorm(), 1.0e-12);
-    }
-
-    @Test
-    public void testNormSq() {
-        Assert.assertEquals(0.0, new Cartesian3D(0, 0, 0).getNormSq(), 0);
-        Assert.assertEquals(14, new Cartesian3D(1, 2, 3).getNormSq(), 1.0e-12);
-    }
-
-    @Test
-    public void testNormInf() {
-        Assert.assertEquals(0.0, Cartesian3D.ZERO.getNormInf(), 0);
-        Assert.assertEquals(3.0, new Cartesian3D(1, -2, 3).getNormInf(), 0);
-    }
-
-    @Test
-    public void testDistance1() {
-        Cartesian3D v1 = new Cartesian3D(1, -2, 3);
-        Cartesian3D v2 = new Cartesian3D(-4, 2, 0);
-        Assert.assertEquals(0.0, Cartesian3D.distance1(Cartesian3D.MINUS_I, Cartesian3D.MINUS_I), 0);
-        Assert.assertEquals(12.0, Cartesian3D.distance1(v1, v2), 1.0e-12);
-        Assert.assertEquals(v1.subtract(v2).getNorm1(), Cartesian3D.distance1(v1, v2), 1.0e-12);
-    }
-
-    @Test
-    public void testDistance() {
-        Cartesian3D v1 = new Cartesian3D(1, -2, 3);
-        Cartesian3D v2 = new Cartesian3D(-4, 2, 0);
-        Assert.assertEquals(0.0, Cartesian3D.distance(Cartesian3D.MINUS_I, Cartesian3D.MINUS_I), 0);
-        Assert.assertEquals(FastMath.sqrt(50), Cartesian3D.distance(v1, v2), 1.0e-12);
-        Assert.assertEquals(v1.subtract(v2).getNorm(), Cartesian3D.distance(v1, v2), 1.0e-12);
-    }
-
-    @Test
-    public void testDistanceSq() {
-        Cartesian3D v1 = new Cartesian3D(1, -2, 3);
-        Cartesian3D v2 = new Cartesian3D(-4, 2, 0);
-        Assert.assertEquals(0.0, Cartesian3D.distanceSq(Cartesian3D.MINUS_I, Cartesian3D.MINUS_I), 0);
-        Assert.assertEquals(50.0, Cartesian3D.distanceSq(v1, v2), 1.0e-12);
-        Assert.assertEquals(Cartesian3D.distance(v1, v2) * Cartesian3D.distance(v1, v2),
-                            Cartesian3D.distanceSq(v1, v2), 1.0e-12);
-  }
-
-    @Test
-    public void testDistanceInf() {
-        Cartesian3D v1 = new Cartesian3D(1, -2, 3);
-        Cartesian3D v2 = new Cartesian3D(-4, 2, 0);
-        Assert.assertEquals(0.0, Cartesian3D.distanceInf(Cartesian3D.MINUS_I, Cartesian3D.MINUS_I), 0);
-        Assert.assertEquals(5.0, Cartesian3D.distanceInf(v1, v2), 1.0e-12);
-        Assert.assertEquals(v1.subtract(v2).getNormInf(), Cartesian3D.distanceInf(v1, v2), 1.0e-12);
-    }
-
-    @Test
-    public void testSubtract() {
-        Cartesian3D v1 = new Cartesian3D(1, 2, 3);
-        Cartesian3D v2 = new Cartesian3D(-3, -2, -1);
-        v1 = v1.subtract(v2);
-        checkVector(v1, 4, 4, 4);
-
-        checkVector(v2.subtract(v1), -7, -6, -5);
-        checkVector(v2.subtract(3, v1), -15, -14, -13);
-    }
-
-    @Test
-    public void testAdd() {
-        Cartesian3D v1 = new Cartesian3D(1, 2, 3);
-        Cartesian3D v2 = new Cartesian3D(-3, -2, -1);
-        v1 = v1.add(v2);
-        checkVector(v1, -2, 0, 2);
-
-        checkVector(v2.add(v1), -5, -2, 1);
-        checkVector(v2.add(3, v1), -9, -2, 5);
-    }
-
-    @Test
-    public void testScalarProduct() {
-        Cartesian3D v = new Cartesian3D(1, 2, 3);
-        v = v.scalarMultiply(3);
-        checkVector(v, 3, 6, 9);
-
-        checkVector(v.scalarMultiply(0.5), 1.5, 3, 4.5);
-    }
-
-    @Test
-    public void testVectorialProducts() {
-        Cartesian3D v1 = new Cartesian3D(2, 1, -4);
-        Cartesian3D v2 = new Cartesian3D(3, 1, -1);
-
-        Assert.assertTrue(FastMath.abs(Cartesian3D.dotProduct(v1, v2) - 11) < 1.0e-12);
-
-        Cartesian3D v3 = Cartesian3D.crossProduct(v1, v2);
-        checkVector(v3, 3, -10, -1);
-
-        Assert.assertTrue(FastMath.abs(Cartesian3D.dotProduct(v1, v3)) < 1.0e-12);
-        Assert.assertTrue(FastMath.abs(Cartesian3D.dotProduct(v2, v3)) < 1.0e-12);
-    }
-
-    @Test
-    public void testCrossProductCancellation() {
-        Cartesian3D v1 = new Cartesian3D(9070467121.0, 4535233560.0, 1);
-        Cartesian3D v2 = new Cartesian3D(9070467123.0, 4535233561.0, 1);
-        checkVector(Cartesian3D.crossProduct(v1, v2), -1, 2, 1);
-
-        double scale    = FastMath.scalb(1.0, 100);
-        Cartesian3D big1   = new Cartesian3D(scale, v1);
-        Cartesian3D small2 = new Cartesian3D(1 / scale, v2);
-        checkVector(Cartesian3D.crossProduct(big1, small2), -1, 2, 1);
-
-    }
-
-    @Test
-    public void testAngular() {
-        Assert.assertEquals(0,           Cartesian3D.PLUS_I.getAlpha(), 1.0e-10);
-        Assert.assertEquals(0,           Cartesian3D.PLUS_I.getDelta(), 1.0e-10);
-        Assert.assertEquals(FastMath.PI / 2, Cartesian3D.PLUS_J.getAlpha(), 1.0e-10);
-        Assert.assertEquals(0,           Cartesian3D.PLUS_J.getDelta(), 1.0e-10);
-        Assert.assertEquals(0,           Cartesian3D.PLUS_K.getAlpha(), 1.0e-10);
-        Assert.assertEquals(FastMath.PI / 2, Cartesian3D.PLUS_K.getDelta(), 1.0e-10);
-
-        Cartesian3D u = new Cartesian3D(-1, 1, -1);
-        Assert.assertEquals(3 * FastMath.PI /4, u.getAlpha(), 1.0e-10);
-        Assert.assertEquals(-1.0 / FastMath.sqrt(3), FastMath.sin(u.getDelta()), 1.0e-10);
-    }
-
-    @Test
-    public void testAngularSeparation() throws MathArithmeticException {
-        Cartesian3D v1 = new Cartesian3D(2, -1, 4);
-
-        Cartesian3D  k = v1.normalize();
-        Cartesian3D  i = k.orthogonal();
-        Cartesian3D v2 = k.scalarMultiply(FastMath.cos(1.2)).add(i.scalarMultiply(FastMath.sin(1.2)));
-
-        Assert.assertTrue(FastMath.abs(Cartesian3D.angle(v1, v2) - 1.2) < 1.0e-12);
-  }
-
-    @Test
-    public void testNormalize() throws MathArithmeticException {
-        Assert.assertEquals(1.0, new Cartesian3D(5, -4, 2).normalize().getNorm(), 1.0e-12);
-        try {
-            Cartesian3D.ZERO.normalize();
-            Assert.fail("an exception should have been thrown");
-        } catch (MathArithmeticException ae) {
-            // expected behavior
-        }
-    }
-
-    @Test
-    public void testNegate() {
-        checkVector(new Cartesian3D(0.1, 2.5, 1.3).negate(), -0.1, -2.5, -1.3);
-    }
-
-    @Test
-    public void testOrthogonal() throws MathArithmeticException {
-        Cartesian3D v1 = new Cartesian3D(0.1, 2.5, 1.3);
-        Assert.assertEquals(0.0, Cartesian3D.dotProduct(v1, v1.orthogonal()), 1.0e-12);
-        Cartesian3D v2 = new Cartesian3D(2.3, -0.003, 7.6);
-        Assert.assertEquals(0.0, Cartesian3D.dotProduct(v2, v2.orthogonal()), 1.0e-12);
-        Cartesian3D v3 = new Cartesian3D(-1.7, 1.4, 0.2);
-        Assert.assertEquals(0.0, Cartesian3D.dotProduct(v3, v3.orthogonal()), 1.0e-12);
-        Cartesian3D v4 = new Cartesian3D(4.2, 0.1, -1.8);
-        Assert.assertEquals(0.0, Cartesian3D.dotProduct(v4, v4.orthogonal()), 1.0e-12);
-        try {
-            new Cartesian3D(0, 0, 0).orthogonal();
-            Assert.fail("an exception should have been thrown");
-        } catch (MathArithmeticException ae) {
-            // expected behavior
-        }
-    }
-    @Test
-    public void testAngle() throws MathArithmeticException {
-        Assert.assertEquals(0.22572612855273393616,
-                            Cartesian3D.angle(new Cartesian3D(1, 2, 3), new Cartesian3D(4, 5, 6)),
-                            1.0e-12);
-        Assert.assertEquals(7.98595620686106654517199e-8,
-                            Cartesian3D.angle(new Cartesian3D(1, 2, 3), new Cartesian3D(2, 4, 6.000001)),
-                            1.0e-12);
-        Assert.assertEquals(3.14159257373023116985197793156,
-                            Cartesian3D.angle(new Cartesian3D(1, 2, 3), new Cartesian3D(-2, -4, -6.000001)),
-                            1.0e-12);
-        try {
-            Cartesian3D.angle(Cartesian3D.ZERO, Cartesian3D.PLUS_I);
-            Assert.fail("an exception should have been thrown");
-        } catch (MathArithmeticException ae) {
-            // expected behavior
-        }
-    }
-
-    @Test
-    public void testAccurateDotProduct() {
-        // the following two vectors are nearly but not exactly orthogonal
-        // naive dot product (i.e. computing u1.x * u2.x + u1.y * u2.y + u1.z * u2.z
-        // leads to a result of 0.0, instead of the correct -1.855129...
-        Cartesian3D u1 = new Cartesian3D(-1321008684645961.0 /  268435456.0,
-                                   -5774608829631843.0 /  268435456.0,
-                                   -7645843051051357.0 / 8589934592.0);
-        Cartesian3D u2 = new Cartesian3D(-5712344449280879.0 /    2097152.0,
-                                   -4550117129121957.0 /    2097152.0,
-                                    8846951984510141.0 /     131072.0);
-        double sNaive = u1.getX() * u2.getX() + u1.getY() * u2.getY() + u1.getZ() * u2.getZ();
-        double sAccurate = u1.dotProduct(u2);
-        Assert.assertEquals(0.0, sNaive, 1.0e-30);
-        Assert.assertEquals(-2088690039198397.0 / 1125899906842624.0, sAccurate, 1.0e-15);
-    }
-
-    @Test
-    public void testDotProduct() {
-        // we compare accurate versus naive dot product implementations
-        // on regular vectors (i.e. not extreme cases like in the previous test)
-        UniformRandomProvider random = RandomSource.create(RandomSource.WELL_1024_A, 553267312521321237l);
-        for (int i = 0; i < 10000; ++i) {
-            double ux = 10000 * random.nextDouble();
-            double uy = 10000 * random.nextDouble();
-            double uz = 10000 * random.nextDouble();
-            double vx = 10000 * random.nextDouble();
-            double vy = 10000 * random.nextDouble();
-            double vz = 10000 * random.nextDouble();
-            double sNaive = ux * vx + uy * vy + uz * vz;
-            double sAccurate = new Cartesian3D(ux, uy, uz).dotProduct(new Cartesian3D(vx, vy, vz));
-            Assert.assertEquals(sNaive, sAccurate, 2.5e-16 * sAccurate);
-        }
-    }
-
-    @Test
-    public void testAccurateCrossProduct() {
-        // the vectors u1 and u2 are nearly but not exactly anti-parallel
-        // (7.31e-16 degrees from 180 degrees) naive cross product (i.e.
-        // computing u1.x * u2.x + u1.y * u2.y + u1.z * u2.z
-        // leads to a result of   [0.0009765, -0.0001220, -0.0039062],
-        // instead of the correct [0.0006913, -0.0001254, -0.0007909]
-        final Cartesian3D u1 = new Cartesian3D(-1321008684645961.0 /   268435456.0,
-                                         -5774608829631843.0 /   268435456.0,
-                                         -7645843051051357.0 /  8589934592.0);
-        final Cartesian3D u2 = new Cartesian3D( 1796571811118507.0 /  2147483648.0,
-                                          7853468008299307.0 /  2147483648.0,
-                                          2599586637357461.0 / 17179869184.0);
-        final Cartesian3D u3 = new Cartesian3D(12753243807587107.0 / 18446744073709551616.0,
-                                         -2313766922703915.0 / 18446744073709551616.0,
-                                          -227970081415313.0 /   288230376151711744.0);
-        Cartesian3D cNaive = new Cartesian3D(u1.getY() * u2.getZ() - u1.getZ() * u2.getY(),
-                                       u1.getZ() * u2.getX() - u1.getX() * u2.getZ(),
-                                       u1.getX() * u2.getY() - u1.getY() * u2.getX());
-        Cartesian3D cAccurate = u1.crossProduct(u2);
-        Assert.assertTrue(u3.distance(cNaive) > 2.9 * u3.getNorm());
-        Assert.assertEquals(0.0, u3.distance(cAccurate), 1.0e-30 * cAccurate.getNorm());
-    }
-
-    @Test
-    public void testCrossProduct() {
-        // we compare accurate versus naive cross product implementations
-        // on regular vectors (i.e. not extreme cases like in the previous test)
-        UniformRandomProvider random = RandomSource.create(RandomSource.WELL_1024_A, 885362227452043215l);
-        for (int i = 0; i < 10000; ++i) {
-            double ux = 10000 * random.nextDouble();
-            double uy = 10000 * random.nextDouble();
-            double uz = 10000 * random.nextDouble();
-            double vx = 10000 * random.nextDouble();
-            double vy = 10000 * random.nextDouble();
-            double vz = 10000 * random.nextDouble();
-            Cartesian3D cNaive = new Cartesian3D(uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx);
-            Cartesian3D cAccurate = new Cartesian3D(ux, uy, uz).crossProduct(new Cartesian3D(vx, vy, vz));
-            Assert.assertEquals(0.0, cAccurate.distance(cNaive), 6.0e-15 * cAccurate.getNorm());
-        }
-    }
-
-    private void checkVector(Cartesian3D v, double x, double y, double z) {
-        Assert.assertEquals(x, v.getX(), 1.0e-12);
-        Assert.assertEquals(y, v.getY(), 1.0e-12);
-        Assert.assertEquals(z, v.getZ(), 1.0e-12);
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Cartesian2DTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Cartesian2DTest.java
deleted file mode 100644
index 924a4ef..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Cartesian2DTest.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * 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.twod;
-
-import org.apache.commons.math4.exception.DimensionMismatchException;
-import org.apache.commons.math4.exception.MathArithmeticException;
-import org.apache.commons.math4.util.FastMath;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class Cartesian2DTest {
-
-    private static final double EPS = Math.ulp(1d);
-
-    @Test
-    public void testScaledVectorTripleConstructor() {
-        Cartesian2D oneOne = new Cartesian2D(1.0,1.0);
-        Cartesian2D oneTwo = new Cartesian2D(1.0,2.0);
-        Cartesian2D oneThree = new Cartesian2D(1.0,3.0);
-
-        Cartesian2D tripleCombo = new Cartesian2D(3.0, oneOne, 1.0, oneTwo, 2.5, oneThree);
-
-        Assert.assertEquals(3.0 * 1 + 1.0 * 1 + 2.5 * 1,tripleCombo.getX(), EPS);
-        Assert.assertEquals(3.0 * 1 + 1.0 * 2 + 2.5 * 3,tripleCombo.getY(), EPS);
-    }
-
-    @Test
-    public void testScaledVectorQuadrupleConstructor() {
-        Cartesian2D oneOne = new Cartesian2D(1.0, 1.0);
-        Cartesian2D oneTwo = new Cartesian2D(1.0, 2.0);
-        Cartesian2D oneThree = new Cartesian2D(1.0, 3.0);
-        Cartesian2D oneFour = new Cartesian2D(1.0, 4.0);
-
-        Cartesian2D tripleCombo = new Cartesian2D(3.0, oneOne, 1.0, oneTwo, 2.5, oneThree, 2.0, oneFour);
-
-        Assert.assertEquals(3.0 * 1.0 + 1.0 * 1.0 + 2.5 * 1.0 + 2.0 * 1.0,tripleCombo.getX(), EPS);
-        Assert.assertEquals(3.0 * 1.0 + 1.0 * 2.0 + 2.5 * 3.0 + 2.0 * 4.0,tripleCombo.getY(), EPS);
-    }
-
-    @Test
-    public void testConstructorExceptions() {
-        double[] v = new double[] {0.0, 1.0, 2.0};
-        try {
-            new Cartesian2D(v);
-        }
-        catch (Exception e) {
-            Assert.assertTrue(e instanceof DimensionMismatchException);
-        }
-    }
-
-    @Test
-    public void testToArray() {
-        Cartesian2D oneTwo = new Cartesian2D(1.0, 2.0);
-        double[] array = oneTwo.toArray();
-        Assert.assertEquals(1.0, array[0], EPS);
-        Assert.assertEquals(2.0, array[1], EPS);
-    }
-
-    @Test
-    public void testGetZero() {
-        Cartesian2D zero = (new Cartesian2D(1.0, 1.0)).getZero();
-        Assert.assertEquals(0.0, zero.getX(), EPS);
-        Assert.assertEquals(0.0, zero.getY(), EPS);
-    }
-
-    @Test
-    public void testNorm1() {
-        Cartesian2D oneTwo = new Cartesian2D(-1.0, 2.0);
-        Assert.assertEquals(3.0, oneTwo.getNorm1(), EPS);
-    }
-
-    @Test
-    public void testNormSq() {
-        Cartesian2D oneTwo = new Cartesian2D(-1.0, 2.0);
-        Assert.assertEquals(5.0, oneTwo.getNormSq(), EPS);
-    }
-
-    @Test
-    public void testNormInf() {
-        Cartesian2D oneTwo = new Cartesian2D(-1.0, 2.0);
-        Assert.assertEquals(2.0, oneTwo.getNormInf(), EPS);
-    }
-
-    @Test
-    public void testVectorAddition() {
-        Cartesian2D minusOneTwo = new Cartesian2D(-1.0,2.0);
-        Cartesian2D threeFive = new Cartesian2D(3.0,5.0);
-        Cartesian2D addition = minusOneTwo.add(threeFive);
-        Assert.assertEquals(2.0, addition.getX(), EPS);
-        Assert.assertEquals(7.0, addition.getY(), EPS);
-    }
-
-    @Test
-    public void testScaledVectorAddition() {
-        Cartesian2D minusOneTwo = new Cartesian2D(-1.0,2.0);
-        Cartesian2D threeFive = new Cartesian2D(3.0,5.0);
-        Cartesian2D addition = minusOneTwo.add(2.0, threeFive);
-        Assert.assertEquals(5.0, addition.getX(), EPS);
-        Assert.assertEquals(12.0, addition.getY(), EPS);
-    }
-
-    @Test
-    public void testVectorSubtraction() {
-        Cartesian2D minusOneTwo = new Cartesian2D(-1.0,2.0);
-        Cartesian2D threeFive = new Cartesian2D(3.0,5.0);
-        Cartesian2D addition = minusOneTwo.subtract(threeFive);
-        Assert.assertEquals(-4.0, addition.getX(), EPS);
-        Assert.assertEquals(-3.0, addition.getY(), EPS);
-    }
-
-    @Test
-    public void testScaledVectorSubtraction() {
-        Cartesian2D minusOneTwo = new Cartesian2D(-1.0,2.0);
-        Cartesian2D threeFive = new Cartesian2D(3.0,5.0);
-        Cartesian2D addition = minusOneTwo.subtract(2.0, threeFive);
-        Assert.assertEquals(-7.0, addition.getX(), EPS);
-        Assert.assertEquals(-8.0, addition.getY(), EPS);
-    }
-
-    @Test
-    public void testNormalize() {
-        Cartesian2D minusOneTwo = new Cartesian2D(-1.0,2.0);
-        Cartesian2D normalizedMinusOneTwo = minusOneTwo.normalize();
-        Assert.assertEquals(-1.0/FastMath.sqrt(5), normalizedMinusOneTwo.getX(), EPS);
-        Assert.assertEquals(2.0/FastMath.sqrt(5), normalizedMinusOneTwo.getY(), EPS);
-        Cartesian2D zero = minusOneTwo.getZero();
-        try {
-            zero.normalize();
-        }
-        catch (Exception e) {
-            Assert.assertTrue(e instanceof MathArithmeticException);
-        }
-    }
-
-    @Test
-    public void testAngle() {
-        Cartesian2D oneOne = new Cartesian2D(1.0, 1.0);
-        try {
-            Cartesian2D.angle(oneOne.getZero(), oneOne.getZero());
-        }
-        catch (Exception e) {
-            Assert.assertTrue(e instanceof MathArithmeticException);
-        }
-        Cartesian2D oneZero = new Cartesian2D(1.0,0.0);
-        double angle = Cartesian2D.angle(oneOne, oneZero);
-        Assert.assertEquals(FastMath.PI/4, angle, EPS);
-        Assert.assertEquals(0.004999958333958323, Cartesian2D.angle(new Cartesian2D(20.0,0.0), new Cartesian2D(20.0,0.1)), EPS);
-    }
-
-    @Test
-    public void testNegate() {
-        Cartesian2D oneOne = new Cartesian2D(1.0,1.0);
-        Cartesian2D negated = oneOne.negate();
-        Assert.assertEquals(-1.0, negated.getX(), EPS);
-        Assert.assertEquals(-1.0, negated.getY(), EPS);
-    }
-
-    @Test
-    public void testIsInfinite() {
-        Cartesian2D oneOne = new Cartesian2D(1.0, 1.0);
-        Cartesian2D infiniteVector = new Cartesian2D(Double.POSITIVE_INFINITY, 0.0);
-        Assert.assertFalse(oneOne.isInfinite());
-        Assert.assertTrue(infiniteVector.isInfinite());
-    }
-
-    @Test
-    public void testDistance1() {
-        Cartesian2D oneOne = new Cartesian2D(1.0,1.0);
-        Cartesian2D fiveEleven = new Cartesian2D(5.0,11.0);
-        double distance1 = oneOne.distance1(fiveEleven);
-        Assert.assertEquals(14.0, distance1, EPS);
-    }
-
-    @Test
-    public void testDistanceInf() {
-        Cartesian2D oneOne = new Cartesian2D(1.0,1.0);
-        Cartesian2D fiveEleven = new Cartesian2D(5.0,11.0);
-        double distanceInf = oneOne.distanceInf(fiveEleven);
-        double staticDistanceInf = Cartesian2D.distanceInf(oneOne, fiveEleven);
-        Assert.assertEquals(10.0, distanceInf, EPS);
-        Assert.assertEquals(distanceInf, staticDistanceInf, EPS);
-    }
-
-    @Test
-    public void testDistanceSq() {
-        Cartesian2D oneFive = new Cartesian2D(1.0, 5.0);
-        Cartesian2D fourOne = new Cartesian2D(4.0, 1.0);
-        double distanceSq = oneFive.distanceSq(fourOne);
-        double staticDistanceSq = Cartesian2D.distanceSq(oneFive, fourOne);
-        Assert.assertEquals(25.0, distanceSq, EPS);
-        Assert.assertEquals(distanceSq, staticDistanceSq, EPS);
-    }
-
-    @Test
-    public void testHashCode() {
-        int hashCode = (new Cartesian2D(1.0,1.0)).hashCode();
-        Assert.assertEquals(887095296, hashCode);
-        Assert.assertEquals(542, (new Cartesian2D(Double.NaN, Double.NaN)).hashCode());
-    }
-
-
-    @Test
-    public void testToString() {
-        Assert.assertEquals("{1; 2}", (new Cartesian2D(1.0,2.0)).toString());
-    }
-
-    @Test
-    public void testCrossProduct() {
-        Cartesian2D p1 = new Cartesian2D(1, 1);
-        Cartesian2D p2 = new Cartesian2D(2, 2);
-
-        Cartesian2D p3 = new Cartesian2D(3, 3);
-        Assert.assertEquals(0.0, p3.crossProduct(p1, p2), EPS);
-
-        Cartesian2D p4 = new Cartesian2D(1, 2);
-        Assert.assertEquals(1.0, p4.crossProduct(p1, p2), EPS);
-
-        Cartesian2D p5 = new Cartesian2D(2, 1);
-        Assert.assertEquals(-1.0, p5.crossProduct(p1, p2), EPS);
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/DiskGeneratorTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/DiskGeneratorTest.java
deleted file mode 100644
index 2da1191..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/DiskGeneratorTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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.twod;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import org.junit.Assert;
-import org.junit.Test;
-import org.apache.commons.rng.UniformRandomProvider;
-import org.apache.commons.rng.simple.RandomSource;
-import org.apache.commons.rng.sampling.UnitSphereSampler;
-import org.apache.commons.math4.geometry.enclosing.EnclosingBall;
-import org.apache.commons.math4.geometry.euclidean.twod.DiskGenerator;
-import org.apache.commons.math4.geometry.euclidean.twod.Euclidean2D;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-
-
-public class DiskGeneratorTest {
-
-    @Test
-    public void testSupport0Point() {
-        List<Cartesian2D> support = Arrays.asList(new Cartesian2D[0]);
-        EnclosingBall<Euclidean2D, Cartesian2D> disk = new DiskGenerator().ballOnSupport(support);
-        Assert.assertTrue(disk.getRadius() < 0);
-        Assert.assertEquals(0, disk.getSupportSize());
-        Assert.assertEquals(0, disk.getSupport().length);
-    }
-
-    @Test
-    public void testSupport1Point() {
-        List<Cartesian2D> support = Arrays.asList(new Cartesian2D(1, 2));
-        EnclosingBall<Euclidean2D, Cartesian2D> disk = new DiskGenerator().ballOnSupport(support);
-        Assert.assertEquals(0.0, disk.getRadius(), 1.0e-10);
-        Assert.assertTrue(disk.contains(support.get(0)));
-        Assert.assertTrue(disk.contains(support.get(0), 0.5));
-        Assert.assertFalse(disk.contains(new Cartesian2D(support.get(0).getX() + 0.1,
-                                                      support.get(0).getY() - 0.1),
-                                         0.001));
-        Assert.assertTrue(disk.contains(new Cartesian2D(support.get(0).getX() + 0.1,
-                                                     support.get(0).getY() - 0.1),
-                                        0.5));
-        Assert.assertEquals(0, support.get(0).distance(disk.getCenter()), 1.0e-10);
-        Assert.assertEquals(1, disk.getSupportSize());
-        Assert.assertTrue(support.get(0) == disk.getSupport()[0]);
-    }
-
-    @Test
-    public void testSupport2Points() {
-        List<Cartesian2D> support = Arrays.asList(new Cartesian2D(1, 0),
-                                               new Cartesian2D(3, 0));
-        EnclosingBall<Euclidean2D, Cartesian2D> disk = new DiskGenerator().ballOnSupport(support);
-        Assert.assertEquals(1.0, disk.getRadius(), 1.0e-10);
-        int i = 0;
-        for (Cartesian2D v : support) {
-            Assert.assertTrue(disk.contains(v));
-            Assert.assertEquals(1.0, v.distance(disk.getCenter()), 1.0e-10);
-            Assert.assertTrue(v == disk.getSupport()[i++]);
-        }
-        Assert.assertTrue(disk.contains(new Cartesian2D(2, 0.9)));
-        Assert.assertFalse(disk.contains(Cartesian2D.ZERO));
-        Assert.assertEquals(0.0, new Cartesian2D(2, 0).distance(disk.getCenter()), 1.0e-10);
-        Assert.assertEquals(2, disk.getSupportSize());
-    }
-
-    @Test
-    public void testSupport3Points() {
-        List<Cartesian2D> support = Arrays.asList(new Cartesian2D(1, 0),
-                                               new Cartesian2D(3, 0),
-                                               new Cartesian2D(2, 2));
-        EnclosingBall<Euclidean2D, Cartesian2D> disk = new DiskGenerator().ballOnSupport(support);
-        Assert.assertEquals(5.0 / 4.0, disk.getRadius(), 1.0e-10);
-        int i = 0;
-        for (Cartesian2D v : support) {
-            Assert.assertTrue(disk.contains(v));
-            Assert.assertEquals(5.0 / 4.0, v.distance(disk.getCenter()), 1.0e-10);
-            Assert.assertTrue(v == disk.getSupport()[i++]);
-        }
-        Assert.assertTrue(disk.contains(new Cartesian2D(2, 0.9)));
-        Assert.assertFalse(disk.contains(new Cartesian2D(0.9,  0)));
-        Assert.assertFalse(disk.contains(new Cartesian2D(3.1,  0)));
-        Assert.assertTrue(disk.contains(new Cartesian2D(2.0, -0.499)));
-        Assert.assertFalse(disk.contains(new Cartesian2D(2.0, -0.501)));
-        Assert.assertEquals(0.0, new Cartesian2D(2.0, 3.0 / 4.0).distance(disk.getCenter()), 1.0e-10);
-        Assert.assertEquals(3, disk.getSupportSize());
-    }
-
-    @Test
-    public void testRandom() {
-        final UniformRandomProvider random = RandomSource.create(RandomSource.WELL_1024_A,
-                                                                 0x12faa818373ffe90l);
-        final UnitSphereSampler sr = new UnitSphereSampler(2, random);
-        for (int i = 0; i < 500; ++i) {
-            double d = 25 * random.nextDouble();
-            double refRadius = 10 * random.nextDouble();
-            Cartesian2D refCenter = new Cartesian2D(d, new Cartesian2D(sr.nextVector()));
-            List<Cartesian2D> support = new ArrayList<>();
-            for (int j = 0; j < 3; ++j) {
-                support.add(new Cartesian2D(1.0, refCenter, refRadius, new Cartesian2D(sr.nextVector())));
-            }
-            EnclosingBall<Euclidean2D, Cartesian2D> disk = new DiskGenerator().ballOnSupport(support);
-            Assert.assertEquals(0.0, refCenter.distance(disk.getCenter()), 3e-9 * refRadius);
-            Assert.assertEquals(refRadius, disk.getRadius(), 7e-10 * refRadius);
-        }
-
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Euclidean2DTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Euclidean2DTest.java
deleted file mode 100644
index a1c82b9..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Euclidean2DTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.twod;
-
-import org.apache.commons.math4.TestUtils;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.euclidean.oned.Euclidean1D;
-import org.apache.commons.math4.geometry.euclidean.twod.Euclidean2D;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class Euclidean2DTest {
-
-    @Test
-    public void testDimension() {
-        Assert.assertEquals(2, Euclidean2D.getInstance().getDimension());
-    }
-
-    @Test
-    public void testSubSpace() {
-        Assert.assertTrue(Euclidean1D.getInstance() == Euclidean2D.getInstance().getSubSpace());
-    }
-
-    @Test
-    public void testSerialization() {
-        Space e2 = Euclidean2D.getInstance();
-        Space deserialized = (Space) TestUtils.serializeAndRecover(e2);
-        Assert.assertTrue(e2 == deserialized);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/FrenchVector2DFormatTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/FrenchVector2DFormatTest.java
deleted file mode 100644
index 188c815..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/FrenchVector2DFormatTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.twod;
-
-import java.util.Locale;
-
-
-public class FrenchVector2DFormatTest extends Vector2DFormatAbstractTest {
-
-    @Override
-    protected char getDecimalCharacter() {
-        return ',';
-    }
-
-    @Override
-    protected Locale getLocale() {
-        return Locale.FRENCH;
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/LineTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/LineTest.java
deleted file mode 100644
index 9f1beef..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/LineTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.twod;
-
-import org.apache.commons.math4.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.geometry.Point;
-import org.apache.commons.math4.geometry.euclidean.oned.Euclidean1D;
-import org.apache.commons.math4.geometry.euclidean.oned.Cartesian1D;
-import org.apache.commons.math4.geometry.partitioning.Transform;
-import org.apache.commons.math4.util.FastMath;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class LineTest {
-
-    @Test
-    public void testContains() {
-        Line l = new Line(new Cartesian2D(0, 1), new Cartesian2D(1, 2), 1.0e-10);
-        Assert.assertTrue(l.contains(new Cartesian2D(0, 1)));
-        Assert.assertTrue(l.contains(new Cartesian2D(1, 2)));
-        Assert.assertTrue(l.contains(new Cartesian2D(7, 8)));
-        Assert.assertTrue(! l.contains(new Cartesian2D(8, 7)));
-    }
-
-    @Test
-    public void testAbscissa() {
-        Line l = new Line(new Cartesian2D(2, 1), new Cartesian2D(-2, -2), 1.0e-10);
-        Assert.assertEquals(0.0,
-                            (l.toSubSpace(new Cartesian2D(-3,  4))).getX(),
-                            1.0e-10);
-        Assert.assertEquals(0.0,
-                            (l.toSubSpace(new Cartesian2D( 3, -4))).getX(),
-                            1.0e-10);
-        Assert.assertEquals(-5.0,
-                            (l.toSubSpace(new Cartesian2D( 7, -1))).getX(),
-                            1.0e-10);
-        Assert.assertEquals(5.0,
-                             (l.toSubSpace(new Cartesian2D(-1, -7))).getX(),
-                             1.0e-10);
-    }
-
-    @Test
-    public void testOffset() {
-        Line l = new Line(new Cartesian2D(2, 1), new Cartesian2D(-2, -2), 1.0e-10);
-        Assert.assertEquals(-5.0, l.getOffset(new Cartesian2D(5, -3)), 1.0e-10);
-        Assert.assertEquals(+5.0, l.getOffset(new Cartesian2D(-5, 2)), 1.0e-10);
-    }
-
-    @Test
-    public void testDistance() {
-        Line l = new Line(new Cartesian2D(2, 1), new Cartesian2D(-2, -2), 1.0e-10);
-        Assert.assertEquals(+5.0, l.distance(new Cartesian2D(5, -3)), 1.0e-10);
-        Assert.assertEquals(+5.0, l.distance(new Cartesian2D(-5, 2)), 1.0e-10);
-    }
-
-    @Test
-    public void testPointAt() {
-        Line l = new Line(new Cartesian2D(2, 1), new Cartesian2D(-2, -2), 1.0e-10);
-        for (double a = -2.0; a < 2.0; a += 0.2) {
-            Point<Euclidean1D> pA = new Cartesian1D(a);
-            Point<Euclidean2D> point = l.toSpace(pA);
-            Assert.assertEquals(a, (l.toSubSpace(point)).getX(), 1.0e-10);
-            Assert.assertEquals(0.0, l.getOffset(point),   1.0e-10);
-            for (double o = -2.0; o < 2.0; o += 0.2) {
-                point = l.getPointAt((Cartesian1D) pA, o);
-                Assert.assertEquals(a, (l.toSubSpace(point)).getX(), 1.0e-10);
-                Assert.assertEquals(o, l.getOffset(point),   1.0e-10);
-            }
-        }
-    }
-
-    @Test
-    public void testOriginOffset() {
-        Line l1 = new Line(new Cartesian2D(0, 1), new Cartesian2D(1, 2), 1.0e-10);
-        Assert.assertEquals(FastMath.sqrt(0.5), l1.getOriginOffset(), 1.0e-10);
-        Line l2 = new Line(new Cartesian2D(1, 2), new Cartesian2D(0, 1), 1.0e-10);
-        Assert.assertEquals(-FastMath.sqrt(0.5), l2.getOriginOffset(), 1.0e-10);
-    }
-
-    @Test
-    public void testParallel() {
-        Line l1 = new Line(new Cartesian2D(0, 1), new Cartesian2D(1, 2), 1.0e-10);
-        Line l2 = new Line(new Cartesian2D(2, 2), new Cartesian2D(3, 3), 1.0e-10);
-        Assert.assertTrue(l1.isParallelTo(l2));
-        Line l3 = new Line(new Cartesian2D(1, 0), new Cartesian2D(0.5, -0.5), 1.0e-10);
-        Assert.assertTrue(l1.isParallelTo(l3));
-        Line l4 = new Line(new Cartesian2D(1, 0), new Cartesian2D(0.5, -0.51), 1.0e-10);
-        Assert.assertTrue(! l1.isParallelTo(l4));
-    }
-
-    @Test
-    public void testTransform() throws MathIllegalArgumentException {
-
-        Line l1 = new Line(new Cartesian2D(1.0 ,1.0), new Cartesian2D(4.0 ,1.0), 1.0e-10);
-        Transform<Euclidean2D, Euclidean1D> t1 =
-            Line.getTransform(0.0, 0.5, -1.0, 0.0, 1.0, 1.5);
-        Assert.assertEquals(0.5 * FastMath.PI,
-                            ((Line) t1.apply(l1)).getAngle(),
-                            1.0e-10);
-
-        Line l2 = new Line(new Cartesian2D(0.0, 0.0), new Cartesian2D(1.0, 1.0), 1.0e-10);
-        Transform<Euclidean2D, Euclidean1D> t2 =
-            Line.getTransform(0.0, 0.5, -1.0, 0.0, 1.0, 1.5);
-        Assert.assertEquals(FastMath.atan2(1.0, -2.0),
-                            ((Line) t2.apply(l2)).getAngle(),
-                            1.0e-10);
-
-    }
-
-    @Test
-    public void testIntersection() {
-        Line    l1 = new Line(new Cartesian2D( 0, 1), new Cartesian2D(1, 2), 1.0e-10);
-        Line    l2 = new Line(new Cartesian2D(-1, 2), new Cartesian2D(2, 1), 1.0e-10);
-        Cartesian2D p  = l1.intersection(l2);
-        Assert.assertEquals(0.5, p.getX(), 1.0e-10);
-        Assert.assertEquals(1.5, p.getY(), 1.0e-10);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/NestedLoopsTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/NestedLoopsTest.java
deleted file mode 100644
index 912c4a5..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/NestedLoopsTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.twod;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-public class NestedLoopsTest {
-
-    private static final double EPS = Math.ulp(1d);
-
-    @Test
-    public void testNestedLoops() throws Exception {
-        Cartesian2D oneOne = new Cartesian2D(1.0, 1.0);
-        Cartesian2D oneNegativeOne = new Cartesian2D(1.0, -1.0);
-        Cartesian2D negativeOneNegativeOne = new Cartesian2D(-1.0, -1.0);
-        Cartesian2D negativeOneOne = new Cartesian2D(-1.0, 1.0);
-        Cartesian2D origin = new Cartesian2D(0, 0);
-
-        Cartesian2D [] vertices = new Cartesian2D[]{
-                oneOne,
-                oneNegativeOne,
-                negativeOneNegativeOne,
-                negativeOneOne,
-                origin
-        };
-
-        NestedLoops nestedLoops = new NestedLoops(0.00000001);
-        nestedLoops.add(vertices);
-        nestedLoops.correctOrientation();
-
-        Field surroundedField = nestedLoops.getClass().getDeclaredField("surrounded");
-        Field loopField = nestedLoops.getClass().getDeclaredField("loop");
-        surroundedField.setAccessible(Boolean.TRUE);
-        loopField.setAccessible(Boolean.TRUE);
-        List<NestedLoops> surrounded = (List<NestedLoops>) surroundedField.get(nestedLoops);
-        Cartesian2D[] loop = (Cartesian2D []) loopField.get(surrounded.get(0));
-        Set<Cartesian2D> vertexSet = new HashSet<>(Arrays.asList(loop));
-        Assert.assertTrue(vertexSet.contains(oneOne));
-        Assert.assertTrue(vertexSet.contains(oneNegativeOne));
-        Assert.assertTrue(vertexSet.contains(negativeOneNegativeOne));
-        Assert.assertTrue(vertexSet.contains(negativeOneOne));
-        Assert.assertTrue(vertexSet.contains(origin));
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/PolygonsSetTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/PolygonsSetTest.java
deleted file mode 100644
index 408614b..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/PolygonsSetTest.java
+++ /dev/null
@@ -1,1844 +0,0 @@
-/*
- * 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.twod;
-
-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.MathIllegalArgumentException;
-import org.apache.commons.math4.geometry.GeometryTestUtils;
-import org.apache.commons.math4.geometry.euclidean.oned.Cartesian1D;
-import org.apache.commons.math4.geometry.euclidean.oned.Interval;
-import org.apache.commons.math4.geometry.euclidean.oned.IntervalsSet;
-import org.apache.commons.math4.geometry.partitioning.BSPTree;
-import org.apache.commons.math4.geometry.partitioning.BSPTreeVisitor;
-import org.apache.commons.math4.geometry.partitioning.BoundaryProjection;
-import org.apache.commons.math4.geometry.partitioning.Hyperplane;
-import org.apache.commons.math4.geometry.partitioning.Region;
-import org.apache.commons.math4.geometry.partitioning.Region.Location;
-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.junit.Assert;
-import org.junit.Test;
-
-public class PolygonsSetTest {
-
-    private static final double TEST_TOLERANCE = 1e-10;
-
-    @Test
-    public void testFull() {
-        // act
-        PolygonsSet poly = new PolygonsSet(TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
-        GeometryTestUtils.assertPositiveInfinity(poly.getSize());
-        Assert.assertEquals(0.0, poly.getBoundarySize(), TEST_TOLERANCE);
-        Assert.assertEquals(0, poly.getVertices().length);
-        Assert.assertFalse(poly.isEmpty());
-        Assert.assertTrue(poly.isFull());
-        GeometryTestUtils.assertVectorEquals(Cartesian2D.NaN, (Cartesian2D) poly.getBarycenter(), TEST_TOLERANCE);
-
-        checkPoints(Region.Location.INSIDE, poly,
-                new Cartesian2D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY),
-                Cartesian2D.ZERO,
-                new Cartesian2D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
-
-        for (double y = -1; y < 1; y += 0.1) {
-            for (double x = -1; x < 1; x += 0.1) {
-                GeometryTestUtils.assertNegativeInfinity(poly.projectToBoundary(new Cartesian2D(x, y)).getOffset());
-            }
-        }
-    }
-
-    @Test
-    public void testEmpty() {
-        // act
-        PolygonsSet poly = (PolygonsSet) new RegionFactory<Euclidean2D>().getComplement(new PolygonsSet(TEST_TOLERANCE));
-
-        // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
-        Assert.assertEquals(0.0, poly.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(0.0, poly.getBoundarySize(), TEST_TOLERANCE);
-        Assert.assertEquals(0, poly.getVertices().length);
-        Assert.assertTrue(poly.isEmpty());
-        Assert.assertFalse(poly.isFull());
-        GeometryTestUtils.assertVectorEquals(Cartesian2D.NaN, (Cartesian2D) poly.getBarycenter(), TEST_TOLERANCE);
-
-        checkPoints(Region.Location.OUTSIDE, poly,
-                new Cartesian2D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY),
-                Cartesian2D.ZERO,
-                new Cartesian2D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
-
-
-        for (double y = -1; y < 1; y += 0.1) {
-            for (double x = -1; x < 1; x += 0.1) {
-                GeometryTestUtils.assertPositiveInfinity(poly.projectToBoundary(new Cartesian2D(x, y)).getOffset());
-            }
-        }
-    }
-
-    @Test
-    public void testInfiniteLines_single() {
-        // arrange
-        Line line = new Line(new Cartesian2D(0, 0), new Cartesian2D(1, 1), TEST_TOLERANCE);
-
-        List<SubHyperplane<Euclidean2D>> boundaries = new ArrayList<SubHyperplane<Euclidean2D>>();
-        boundaries.add(line.wholeHyperplane());
-
-        // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
-        GeometryTestUtils.assertPositiveInfinity(poly.getSize());
-        GeometryTestUtils.assertPositiveInfinity(poly.getBoundarySize());
-        Assert.assertFalse(poly.isEmpty());
-        Assert.assertFalse(poly.isFull());
-        GeometryTestUtils.assertVectorEquals(Cartesian2D.NaN, (Cartesian2D) poly.getBarycenter(), TEST_TOLERANCE);
-
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            {
-                null,
-                line.toSpace(new Cartesian1D(-Float.MAX_VALUE)),
-                line.toSpace(new Cartesian1D(Float.MAX_VALUE))
-            }
-        }, poly.getVertices());
-
-        checkPoints(Region.Location.OUTSIDE, poly,
-                new Cartesian2D(1, -1),
-                new Cartesian2D(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY));
-        checkPoints(Region.Location.INSIDE, poly,
-                new Cartesian2D(-1, 1),
-                new Cartesian2D(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
-        checkPoints(Region.Location.BOUNDARY, poly, Cartesian2D.ZERO);
-    }
-
-    @Test
-    public void testInfiniteLines_twoIntersecting() {
-        // arrange
-        Line line1 = new Line(new Cartesian2D(0, 0), new Cartesian2D(1, 1), TEST_TOLERANCE);
-        Line line2 = new Line(new Cartesian2D(1, -1), new Cartesian2D(0, 0), TEST_TOLERANCE);
-
-        List<SubHyperplane<Euclidean2D>> boundaries = new ArrayList<SubHyperplane<Euclidean2D>>();
-        boundaries.add(line1.wholeHyperplane());
-        boundaries.add(line2.wholeHyperplane());
-
-        // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
-        GeometryTestUtils.assertPositiveInfinity(poly.getSize());
-        GeometryTestUtils.assertPositiveInfinity(poly.getBoundarySize());
-        Assert.assertFalse(poly.isEmpty());
-        Assert.assertFalse(poly.isFull());
-        GeometryTestUtils.assertVectorEquals(Cartesian2D.NaN, (Cartesian2D) poly.getBarycenter(), TEST_TOLERANCE);
-
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            {
-                null,
-                line2.toSpace(new Cartesian1D(-Float.MAX_VALUE)),
-                line2.toSpace(new Cartesian1D(Float.MAX_VALUE))
-            }
-        }, poly.getVertices());
-
-        checkPoints(Region.Location.INSIDE, poly,
-                new Cartesian2D(-1, 0),
-                new Cartesian2D(-Float.MAX_VALUE, Float.MAX_VALUE / 2.0));
-        checkPoints(Region.Location.OUTSIDE, poly,
-                new Cartesian2D(1, 0),
-                new Cartesian2D(Float.MAX_VALUE, Float.MAX_VALUE / 2.0));
-        checkPoints(Region.Location.BOUNDARY, poly, Cartesian2D.ZERO);
-    }
-
-    @Test
-    public void testInfiniteLines_twoParallel_facingIn() {
-        // arrange
-        Line line1 = new Line(new Cartesian2D(1, 1), new Cartesian2D(0, 1), TEST_TOLERANCE);
-        Line line2 = new Line(new Cartesian2D(0, -1), new Cartesian2D(1, -1), TEST_TOLERANCE);
-
-        List<SubHyperplane<Euclidean2D>> boundaries = new ArrayList<SubHyperplane<Euclidean2D>>();
-        boundaries.add(line1.wholeHyperplane());
-        boundaries.add(line2.wholeHyperplane());
-
-        // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
-        GeometryTestUtils.assertPositiveInfinity(poly.getSize());
-        GeometryTestUtils.assertPositiveInfinity(poly.getBoundarySize());
-        Assert.assertFalse(poly.isEmpty());
-        Assert.assertFalse(poly.isFull());
-        GeometryTestUtils.assertVectorEquals(Cartesian2D.NaN, (Cartesian2D) poly.getBarycenter(), TEST_TOLERANCE);
-
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            {
-                null,
-                line1.toSpace(new Cartesian1D(-Float.MAX_VALUE)),
-                line1.toSpace(new Cartesian1D(Float.MAX_VALUE))
-            },
-            {
-                null,
-                line2.toSpace(new Cartesian1D(-Float.MAX_VALUE)),
-                line2.toSpace(new Cartesian1D(Float.MAX_VALUE))
-            }
-        }, poly.getVertices());
-
-        checkPoints(Region.Location.INSIDE, poly,
-                new Cartesian2D(0, 0),
-                new Cartesian2D(0, 0.9),
-                new Cartesian2D(0, -0.9));
-        checkPoints(Region.Location.OUTSIDE, poly,
-                new Cartesian2D(0, 1.1),
-                new Cartesian2D(0, -1.1));
-        checkPoints(Region.Location.BOUNDARY, poly,
-                new Cartesian2D(0, 1),
-                new Cartesian2D(0, -1));
-    }
-
-    @Test
-    public void testInfiniteLines_twoParallel_facingOut() {
-        // arrange
-        Line line1 = new Line(new Cartesian2D(0, 1), new Cartesian2D(1, 1), TEST_TOLERANCE);
-        Line line2 = new Line(new Cartesian2D(1, -1), new Cartesian2D(0, -1), TEST_TOLERANCE);
-
-        List<SubHyperplane<Euclidean2D>> boundaries = new ArrayList<SubHyperplane<Euclidean2D>>();
-        boundaries.add(line1.wholeHyperplane());
-        boundaries.add(line2.wholeHyperplane());
-
-        // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
-        GeometryTestUtils.assertPositiveInfinity(poly.getSize());
-        GeometryTestUtils.assertPositiveInfinity(poly.getBoundarySize());
-        Assert.assertFalse(poly.isEmpty());
-        Assert.assertFalse(poly.isFull());
-        GeometryTestUtils.assertVectorEquals(Cartesian2D.NaN, (Cartesian2D) poly.getBarycenter(), TEST_TOLERANCE);
-
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            {
-                null,
-                line1.toSpace(new Cartesian1D(-Float.MAX_VALUE)),
-                line1.toSpace(new Cartesian1D(Float.MAX_VALUE))
-            },
-            {
-                null,
-                line2.toSpace(new Cartesian1D(-Float.MAX_VALUE)),
-                line2.toSpace(new Cartesian1D(Float.MAX_VALUE))
-            }
-        }, poly.getVertices());
-
-        checkPoints(Region.Location.OUTSIDE, poly,
-                new Cartesian2D(0, 0),
-                new Cartesian2D(0, 0.9),
-                new Cartesian2D(0, -0.9));
-        checkPoints(Region.Location.INSIDE, poly,
-                new Cartesian2D(0, 1.1),
-                new Cartesian2D(0, -1.1));
-        checkPoints(Region.Location.BOUNDARY, poly,
-                new Cartesian2D(0, 1),
-                new Cartesian2D(0, -1));
-    }
-
-    @Test
-    public void testMixedFiniteAndInfiniteLines_explicitInfiniteBoundaries() {
-        // arrange
-        Line line1 = new Line(new Cartesian2D(3, 3), new Cartesian2D(0, 3), TEST_TOLERANCE);
-        Line line2 = new Line(new Cartesian2D(0, -3), new Cartesian2D(3, -3), TEST_TOLERANCE);
-
-        List<SubHyperplane<Euclidean2D>> boundaries = new ArrayList<SubHyperplane<Euclidean2D>>();
-        boundaries.add(line1.wholeHyperplane());
-        boundaries.add(line2.wholeHyperplane());
-        boundaries.add(buildSegment(new Cartesian2D(0, 3), new Cartesian2D(0, -3)));
-
-        // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
-        GeometryTestUtils.assertPositiveInfinity(poly.getSize());
-        GeometryTestUtils.assertPositiveInfinity(poly.getBoundarySize());
-        Assert.assertFalse(poly.isEmpty());
-        Assert.assertFalse(poly.isFull());
-        GeometryTestUtils.assertVectorEquals(Cartesian2D.NaN, (Cartesian2D) poly.getBarycenter(), TEST_TOLERANCE);
-
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            {
-                null,
-                new Cartesian2D(1, 3), // dummy point
-                new Cartesian2D(0, 3),
-                new Cartesian2D(0, -3),
-                new Cartesian2D(1, -3) // dummy point
-            }
-        }, poly.getVertices());
-
-        checkPoints(Region.Location.INSIDE, poly,
-                new Cartesian2D(0.1, 2.9),
-                new Cartesian2D(0.1, 0),
-                new Cartesian2D(0.1, -2.9));
-        checkPoints(Region.Location.OUTSIDE, poly,
-                new Cartesian2D(0, 3.1),
-                new Cartesian2D(-0.5, 0),
-                new Cartesian2D(0, -3.1));
-        checkPoints(Region.Location.BOUNDARY, poly,
-                new Cartesian2D(3, 3),
-                new Cartesian2D(0, 0),
-                new Cartesian2D(3, -3));
-    }
-
-    // The polygon in this test is created from finite boundaries but the generated
-    // loop still begins and ends with infinite lines. This is because the boundaries
-    // used as input do not form a closed region, therefore the region itself is unclosed.
-    // In other words, the boundaries used as input only define the region, not the points
-    // returned from the getVertices() method.
-    @Test
-    public void testMixedFiniteAndInfiniteLines_impliedInfiniteBoundaries() {
-        // arrange
-        Line line = new Line(new Cartesian2D(3, 0), new Cartesian2D(3, 3), TEST_TOLERANCE);
-
-        List<SubHyperplane<Euclidean2D>> boundaries = new ArrayList<SubHyperplane<Euclidean2D>>();
-        boundaries.add(buildSegment(new Cartesian2D(0, 3), new Cartesian2D(0, 0)));
-        boundaries.add(buildSegment(new Cartesian2D(0, 0), new Cartesian2D(3, 0)));
-        boundaries.add(new SubLine(line, new IntervalsSet(0, Double.POSITIVE_INFINITY, TEST_TOLERANCE)));
-
-        // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
-        GeometryTestUtils.assertPositiveInfinity(poly.getSize());
-        GeometryTestUtils.assertPositiveInfinity(poly.getBoundarySize());
-        Assert.assertFalse(poly.isEmpty());
-        Assert.assertFalse(poly.isFull());
-        GeometryTestUtils.assertVectorEquals(Cartesian2D.NaN, (Cartesian2D) poly.getBarycenter(), TEST_TOLERANCE);
-
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            {
-                null,
-                new Cartesian2D(0, 1), // dummy point
-                new Cartesian2D(0, 0),
-                new Cartesian2D(3, 0),
-                new Cartesian2D(3, 1) // dummy point
-            }
-        }, poly.getVertices());
-
-        checkPoints(Region.Location.INSIDE, poly,
-                new Cartesian2D(0.1, Float.MAX_VALUE),
-                new Cartesian2D(0.1, 0.1),
-                new Cartesian2D(1.5, 0.1),
-                new Cartesian2D(2.9, 0.1),
-                new Cartesian2D(2.9, Float.MAX_VALUE));
-        checkPoints(Region.Location.OUTSIDE, poly,
-                new Cartesian2D(-0.1, Float.MAX_VALUE),
-                new Cartesian2D(-0.1, 0.1),
-                new Cartesian2D(1.5, -0.1),
-                new Cartesian2D(3.1, 0.1),
-                new Cartesian2D(3.1, Float.MAX_VALUE));
-        checkPoints(Region.Location.BOUNDARY, poly,
-                new Cartesian2D(0, 1),
-                new Cartesian2D(1, 0),
-                new Cartesian2D(3, 1));
-    }
-
-    @Test
-    public void testBox() {
-        // act
-        PolygonsSet box = new PolygonsSet(0, 2, -1, 1, TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(4.0, box.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(8.0, box.getBoundarySize(), TEST_TOLERANCE);
-        Assert.assertFalse(box.isEmpty());
-        Assert.assertFalse(box.isFull());
-        GeometryTestUtils.assertVectorEquals(new Cartesian2D(1, 0), (Cartesian2D) box.getBarycenter(), TEST_TOLERANCE);
-
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            {
-                new Cartesian2D(2, -1),
-                new Cartesian2D(2, 1),
-                new Cartesian2D(0, 1),
-                new Cartesian2D(0, -1)
-            }
-        }, box.getVertices());
-
-        checkPoints(Region.Location.INSIDE, box,
-                new Cartesian2D(0.1, 0),
-                new Cartesian2D(1.9, 0),
-                new Cartesian2D(1, 0.9),
-                new Cartesian2D(1, -0.9));
-        checkPoints(Region.Location.OUTSIDE, box,
-                new Cartesian2D(-0.1, 0),
-                new Cartesian2D(2.1, 0),
-                new Cartesian2D(1, -1.1),
-                new Cartesian2D(1, 1.1));
-        checkPoints(Region.Location.BOUNDARY, box,
-                new Cartesian2D(0, 0),
-                new Cartesian2D(2, 0),
-                new Cartesian2D(1, 1),
-                new Cartesian2D(1, -1));
-    }
-
-    @Test
-    public void testInvertedBox() {
-        // arrange
-        List<SubHyperplane<Euclidean2D>> boundaries = new ArrayList<SubHyperplane<Euclidean2D>>();
-        boundaries.add(buildSegment(new Cartesian2D(0, -1), new Cartesian2D(0, 1)));
-        boundaries.add(buildSegment(new Cartesian2D(2, 1), new Cartesian2D(2, -1)));
-        boundaries.add(buildSegment(new Cartesian2D(0, 1), new Cartesian2D(2, 1)));
-        boundaries.add(buildSegment(new Cartesian2D(2, -1), new Cartesian2D(0, -1)));
-
-        // act
-        PolygonsSet box = new PolygonsSet(boundaries, TEST_TOLERANCE);
-
-        // assert
-        GeometryTestUtils.assertPositiveInfinity(box.getSize());
-        Assert.assertEquals(8.0, box.getBoundarySize(), TEST_TOLERANCE);
-        Assert.assertFalse(box.isEmpty());
-        Assert.assertFalse(box.isFull());
-        GeometryTestUtils.assertVectorEquals(Cartesian2D.NaN, (Cartesian2D) box.getBarycenter(), TEST_TOLERANCE);
-
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            {
-                new Cartesian2D(0, -1),
-                new Cartesian2D(0, 1),
-                new Cartesian2D(2, 1),
-                new Cartesian2D(2, -1)
-            }
-        }, box.getVertices());
-
-        checkPoints(Region.Location.OUTSIDE, box,
-                new Cartesian2D(0.1, 0),
-                new Cartesian2D(1.9, 0),
-                new Cartesian2D(1, 0.9),
-                new Cartesian2D(1, -0.9));
-        checkPoints(Region.Location.INSIDE, box,
-                new Cartesian2D(-0.1, 0),
-                new Cartesian2D(2.1, 0),
-                new Cartesian2D(1, -1.1),
-                new Cartesian2D(1, 1.1));
-        checkPoints(Region.Location.BOUNDARY, box,
-                new Cartesian2D(0, 0),
-                new Cartesian2D(2, 0),
-                new Cartesian2D(1, 1),
-                new Cartesian2D(1, -1));
-    }
-
-    @Test
-    public void testSimplyConnected() {
-        // arrange
-        Cartesian2D[][] vertices = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D(36.0, 22.0),
-                new Cartesian2D(39.0, 32.0),
-                new Cartesian2D(19.0, 32.0),
-                new Cartesian2D( 6.0, 16.0),
-                new Cartesian2D(31.0, 10.0),
-                new Cartesian2D(42.0, 16.0),
-                new Cartesian2D(34.0, 20.0),
-                new Cartesian2D(29.0, 19.0),
-                new Cartesian2D(23.0, 22.0),
-                new Cartesian2D(33.0, 25.0)
-            }
-        };
-
-        // act
-        PolygonsSet set = buildSet(vertices);
-
-        // assert
-        checkPoints(Region.Location.INSIDE, set,
-            new Cartesian2D(30.0, 15.0),
-            new Cartesian2D(15.0, 20.0),
-            new Cartesian2D(24.0, 25.0),
-            new Cartesian2D(35.0, 30.0),
-            new Cartesian2D(19.0, 17.0));
-        checkPoints(Region.Location.OUTSIDE, set,
-            new Cartesian2D(50.0, 30.0),
-            new Cartesian2D(30.0, 35.0),
-            new Cartesian2D(10.0, 25.0),
-            new Cartesian2D(10.0, 10.0),
-            new Cartesian2D(40.0, 10.0),
-            new Cartesian2D(50.0, 15.0),
-            new Cartesian2D(30.0, 22.0));
-        checkPoints(Region.Location.BOUNDARY, set,
-            new Cartesian2D(30.0, 32.0),
-            new Cartesian2D(34.0, 20.0));
-
-        checkVertexLoopsEquivalent(vertices, set.getVertices());
-    }
-
-    @Test
-    public void testStair() {
-        // arrange
-        Cartesian2D[][] vertices = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.0, 0.0),
-                new Cartesian2D( 0.0, 2.0),
-                new Cartesian2D(-0.1, 2.0),
-                new Cartesian2D(-0.1, 1.0),
-                new Cartesian2D(-0.3, 1.0),
-                new Cartesian2D(-0.3, 1.5),
-                new Cartesian2D(-1.3, 1.5),
-                new Cartesian2D(-1.3, 2.0),
-                new Cartesian2D(-1.8, 2.0),
-                new Cartesian2D(-1.8 - 1.0 / FastMath.sqrt(2.0),
-                            2.0 - 1.0 / FastMath.sqrt(2.0))
-            }
-        };
-
-        // act
-        PolygonsSet set = buildSet(vertices);
-
-        // assert
-        checkVertexLoopsEquivalent(vertices, set.getVertices());
-
-        Assert.assertEquals(1.1 + 0.95 * FastMath.sqrt(2.0), set.getSize(), TEST_TOLERANCE);
-    }
-
-    @Test
-    public void testHole() {
-        // arrange
-        Cartesian2D[][] vertices = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D(0.0, 0.0),
-                new Cartesian2D(3.0, 0.0),
-                new Cartesian2D(3.0, 3.0),
-                new Cartesian2D(0.0, 3.0)
-            }, new Cartesian2D[] {
-                new Cartesian2D(1.0, 2.0),
-                new Cartesian2D(2.0, 2.0),
-                new Cartesian2D(2.0, 1.0),
-                new Cartesian2D(1.0, 1.0)
-            }
-        };
-
-        // act
-        PolygonsSet set = buildSet(vertices);
-
-        // assert
-        checkPoints(Region.Location.INSIDE, set, new Cartesian2D[] {
-            new Cartesian2D(0.5, 0.5),
-            new Cartesian2D(1.5, 0.5),
-            new Cartesian2D(2.5, 0.5),
-            new Cartesian2D(0.5, 1.5),
-            new Cartesian2D(2.5, 1.5),
-            new Cartesian2D(0.5, 2.5),
-            new Cartesian2D(1.5, 2.5),
-            new Cartesian2D(2.5, 2.5),
-            new Cartesian2D(0.5, 1.0)
-        });
-        checkPoints(Region.Location.OUTSIDE, set, new Cartesian2D[] {
-            new Cartesian2D(1.5, 1.5),
-            new Cartesian2D(3.5, 1.0),
-            new Cartesian2D(4.0, 1.5),
-            new Cartesian2D(6.0, 6.0)
-        });
-        checkPoints(Region.Location.BOUNDARY, set, new Cartesian2D[] {
-            new Cartesian2D(1.0, 1.0),
-            new Cartesian2D(1.5, 0.0),
-            new Cartesian2D(1.5, 1.0),
-            new Cartesian2D(1.5, 2.0),
-            new Cartesian2D(1.5, 3.0),
-            new Cartesian2D(3.0, 3.0)
-        });
-        checkVertexLoopsEquivalent(vertices, set.getVertices());
-
-        for (double x = -0.999; x < 3.999; x += 0.11) {
-            Cartesian2D v = new Cartesian2D(x, x + 0.5);
-            BoundaryProjection<Euclidean2D> projection = set.projectToBoundary(v);
-            Assert.assertTrue(projection.getOriginal() == v);
-            Cartesian2D p = (Cartesian2D) projection.getProjected();
-            if (x < -0.5) {
-                Assert.assertEquals(0.0,      p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(0.0,      p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(+v.distance(Cartesian2D.ZERO), projection.getOffset(), TEST_TOLERANCE);
-            } else if (x < 0.5) {
-                Assert.assertEquals(0.0,      p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(v.getY(), p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(-v.getX(), projection.getOffset(), TEST_TOLERANCE);
-            } else if (x < 1.25) {
-                Assert.assertEquals(1.0,      p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(v.getY(), p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(v.getX() - 1.0, projection.getOffset(), TEST_TOLERANCE);
-            } else if (x < 2.0) {
-                Assert.assertEquals(v.getX(), p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(2.0,      p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(2.0 - v.getY(), projection.getOffset(), TEST_TOLERANCE);
-            } else if (x < 3.0) {
-                Assert.assertEquals(v.getX(), p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(3.0,      p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(v.getY() - 3.0, projection.getOffset(), TEST_TOLERANCE);
-            } else {
-                Assert.assertEquals(3.0,      p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(3.0,      p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(+v.distance(new Cartesian2D(3, 3)), projection.getOffset(), TEST_TOLERANCE);
-            }
-        }
-    }
-
-    @Test
-    public void testDisjointPolygons() {
-        // arrange
-        Cartesian2D[][] vertices = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D(0.0, 1.0),
-                new Cartesian2D(2.0, 1.0),
-                new Cartesian2D(1.0, 2.0)
-            }, new Cartesian2D[] {
-                new Cartesian2D(4.0, 0.0),
-                new Cartesian2D(5.0, 1.0),
-                new Cartesian2D(3.0, 1.0)
-            }
-        };
-
-        // act
-        PolygonsSet set = buildSet(vertices);
-
-        // assert
-        Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Cartesian2D(1.0, 1.5)));
-        checkPoints(Region.Location.INSIDE, set, new Cartesian2D[] {
-            new Cartesian2D(1.0, 1.5),
-            new Cartesian2D(4.5, 0.8)
-        });
-        checkPoints(Region.Location.OUTSIDE, set, new Cartesian2D[] {
-            new Cartesian2D(1.0, 0.0),
-            new Cartesian2D(3.5, 1.2),
-            new Cartesian2D(2.5, 1.0),
-            new Cartesian2D(3.0, 4.0)
-        });
-        checkPoints(Region.Location.BOUNDARY, set, new Cartesian2D[] {
-            new Cartesian2D(1.0, 1.0),
-            new Cartesian2D(3.5, 0.5),
-            new Cartesian2D(0.0, 1.0)
-        });
-        checkVertexLoopsEquivalent(vertices, set.getVertices());
-    }
-
-    @Test
-    public void testOppositeHyperplanes() {
-        // arrange
-        Cartesian2D[][] vertices = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D(1.0, 0.0),
-                new Cartesian2D(2.0, 1.0),
-                new Cartesian2D(3.0, 1.0),
-                new Cartesian2D(2.0, 2.0),
-                new Cartesian2D(1.0, 1.0),
-                new Cartesian2D(0.0, 1.0)
-            }
-        };
-
-        // act
-        PolygonsSet set = buildSet(vertices);
-
-        // assert
-        checkVertexLoopsEquivalent(vertices, set.getVertices());
-    }
-
-    @Test
-    public void testSingularPoint() {
-        // arrange
-        Cartesian2D[][] vertices = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D( 1.0,  0.0),
-                new Cartesian2D( 1.0,  1.0),
-                new Cartesian2D( 0.0,  1.0),
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D(-1.0,  0.0),
-                new Cartesian2D(-1.0, -1.0),
-                new Cartesian2D( 0.0, -1.0)
-            }
-        };
-
-        // act
-        PolygonsSet set = buildSet(vertices);
-
-        // assert
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            {
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D( 1.0,  0.0),
-                new Cartesian2D( 1.0,  1.0),
-                new Cartesian2D( 0.0,  1.0)
-            },
-            {
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D(-1.0,  0.0),
-                new Cartesian2D(-1.0, -1.0),
-                new Cartesian2D( 0.0, -1.0)
-            }
-        }, set.getVertices());
-    }
-
-    @Test
-    public void testLineIntersection() {
-        // arrange
-        Cartesian2D[][] vertices = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D( 2.0,  0.0),
-                new Cartesian2D( 2.0,  1.0),
-                new Cartesian2D( 3.0,  1.0),
-                new Cartesian2D( 3.0,  3.0),
-                new Cartesian2D( 1.0,  3.0),
-                new Cartesian2D( 1.0,  2.0),
-                new Cartesian2D( 0.0,  2.0)
-            }
-        };
-
-        // act
-        PolygonsSet set = buildSet(vertices);
-
-        // assert
-        Line l1 = new Line(new Cartesian2D(-1.5, 0.0), FastMath.PI / 4, TEST_TOLERANCE);
-        SubLine s1 = (SubLine) set.intersection(l1.wholeHyperplane());
-        List<Interval> i1 = ((IntervalsSet) s1.getRemainingRegion()).asList();
-        Assert.assertEquals(2, i1.size());
-        Interval v10 = i1.get(0);
-        Cartesian2D p10Lower = l1.toSpace(new Cartesian1D(v10.getInf()));
-        Assert.assertEquals(0.0, p10Lower.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(1.5, p10Lower.getY(), TEST_TOLERANCE);
-        Cartesian2D p10Upper = l1.toSpace(new Cartesian1D(v10.getSup()));
-        Assert.assertEquals(0.5, p10Upper.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(2.0, p10Upper.getY(), TEST_TOLERANCE);
-        Interval v11 = i1.get(1);
-        Cartesian2D p11Lower = l1.toSpace(new Cartesian1D(v11.getInf()));
-        Assert.assertEquals(1.0, p11Lower.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(2.5, p11Lower.getY(), TEST_TOLERANCE);
-        Cartesian2D p11Upper = l1.toSpace(new Cartesian1D(v11.getSup()));
-        Assert.assertEquals(1.5, p11Upper.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(3.0, p11Upper.getY(), TEST_TOLERANCE);
-
-        Line l2 = new Line(new Cartesian2D(-1.0, 2.0), 0, TEST_TOLERANCE);
-        SubLine s2 = (SubLine) set.intersection(l2.wholeHyperplane());
-        List<Interval> i2 = ((IntervalsSet) s2.getRemainingRegion()).asList();
-        Assert.assertEquals(1, i2.size());
-        Interval v20 = i2.get(0);
-        Cartesian2D p20Lower = l2.toSpace(new Cartesian1D(v20.getInf()));
-        Assert.assertEquals(1.0, p20Lower.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(2.0, p20Lower.getY(), TEST_TOLERANCE);
-        Cartesian2D p20Upper = l2.toSpace(new Cartesian1D(v20.getSup()));
-        Assert.assertEquals(3.0, p20Upper.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(2.0, p20Upper.getY(), TEST_TOLERANCE);
-    }
-
-    @Test
-    public void testUnlimitedSubHyperplane() {
-        // arrange
-        Cartesian2D[][] vertices1 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D(0.0, 0.0),
-                new Cartesian2D(4.0, 0.0),
-                new Cartesian2D(1.4, 1.5),
-                new Cartesian2D(0.0, 3.5)
-            }
-        };
-        PolygonsSet set1 = buildSet(vertices1);
-        Cartesian2D[][] vertices2 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D(1.4,  0.2),
-                new Cartesian2D(2.8, -1.2),
-                new Cartesian2D(2.5,  0.6)
-            }
-        };
-        PolygonsSet set2 = buildSet(vertices2);
-
-        // act
-        PolygonsSet set =
-            (PolygonsSet) new RegionFactory<Euclidean2D>().union(set1.copySelf(),
-                                                                 set2.copySelf());
-
-        // assert
-        checkVertexLoopsEquivalent(vertices1, set1.getVertices());
-        checkVertexLoopsEquivalent(vertices2, set2.getVertices());
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D(0.0,  0.0),
-                new Cartesian2D(1.6,  0.0),
-                new Cartesian2D(2.8, -1.2),
-                new Cartesian2D(2.6,  0.0),
-                new Cartesian2D(4.0,  0.0),
-                new Cartesian2D(1.4,  1.5),
-                new Cartesian2D(0.0,  3.5)
-            }
-        }, set.getVertices());
-    }
-
-    @Test
-    public void testUnion() {
-        // arrange
-        Cartesian2D[][] vertices1 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D( 2.0,  0.0),
-                new Cartesian2D( 2.0,  2.0),
-                new Cartesian2D( 0.0,  2.0)
-            }
-        };
-        PolygonsSet set1 = buildSet(vertices1);
-        Cartesian2D[][] vertices2 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 1.0,  1.0),
-                new Cartesian2D( 3.0,  1.0),
-                new Cartesian2D( 3.0,  3.0),
-                new Cartesian2D( 1.0,  3.0)
-            }
-        };
-        PolygonsSet set2 = buildSet(vertices2);
-
-        // act
-        PolygonsSet set  = (PolygonsSet) new RegionFactory<Euclidean2D>().union(set1.copySelf(),
-                                                                                set2.copySelf());
-
-        // assert
-        checkVertexLoopsEquivalent(vertices1, set1.getVertices());
-        checkVertexLoopsEquivalent(vertices2, set2.getVertices());
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D( 2.0,  0.0),
-                new Cartesian2D( 2.0,  1.0),
-                new Cartesian2D( 3.0,  1.0),
-                new Cartesian2D( 3.0,  3.0),
-                new Cartesian2D( 1.0,  3.0),
-                new Cartesian2D( 1.0,  2.0),
-                new Cartesian2D( 0.0,  2.0)
-            }
-        }, set.getVertices());
-
-        checkPoints(Region.Location.INSIDE, set, new Cartesian2D[] {
-            new Cartesian2D(1.0, 1.0),
-            new Cartesian2D(0.5, 0.5),
-            new Cartesian2D(2.0, 2.0),
-            new Cartesian2D(2.5, 2.5),
-            new Cartesian2D(0.5, 1.5),
-            new Cartesian2D(1.5, 1.5),
-            new Cartesian2D(1.5, 0.5),
-            new Cartesian2D(1.5, 2.5),
-            new Cartesian2D(2.5, 1.5),
-            new Cartesian2D(2.5, 2.5)
-        });
-        checkPoints(Region.Location.OUTSIDE, set, new Cartesian2D[] {
-            new Cartesian2D(-0.5, 0.5),
-            new Cartesian2D( 0.5, 2.5),
-            new Cartesian2D( 2.5, 0.5),
-            new Cartesian2D( 3.5, 2.5)
-        });
-        checkPoints(Region.Location.BOUNDARY, set, new Cartesian2D[] {
-            new Cartesian2D(0.0, 0.0),
-            new Cartesian2D(0.5, 2.0),
-            new Cartesian2D(2.0, 0.5),
-            new Cartesian2D(2.5, 1.0),
-            new Cartesian2D(3.0, 2.5)
-        });
-    }
-
-    @Test
-    public void testIntersection() {
-        // arrange
-        Cartesian2D[][] vertices1 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D( 2.0,  0.0),
-                new Cartesian2D( 2.0,  2.0),
-                new Cartesian2D( 0.0,  2.0)
-            }
-        };
-        PolygonsSet set1 = buildSet(vertices1);
-        Cartesian2D[][] vertices2 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 1.0,  1.0),
-                new Cartesian2D( 3.0,  1.0),
-                new Cartesian2D( 3.0,  3.0),
-                new Cartesian2D( 1.0,  3.0)
-            }
-        };
-        PolygonsSet set2 = buildSet(vertices2);
-
-        // act
-        PolygonsSet set  = (PolygonsSet) new RegionFactory<Euclidean2D>().intersection(set1.copySelf(),
-                                                                                       set2.copySelf());
-
-        // assert
-        checkVertexLoopsEquivalent(vertices1, set1.getVertices());
-        checkVertexLoopsEquivalent(vertices2, set2.getVertices());
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 1.0,  1.0),
-                new Cartesian2D( 2.0,  1.0),
-                new Cartesian2D( 2.0,  2.0),
-                new Cartesian2D( 1.0,  2.0)
-            }
-        }, set.getVertices());
-
-        checkPoints(Region.Location.INSIDE, set, new Cartesian2D[] {
-            new Cartesian2D(1.5, 1.5)
-        });
-        checkPoints(Region.Location.OUTSIDE, set, new Cartesian2D[] {
-            new Cartesian2D(0.5, 1.5),
-            new Cartesian2D(2.5, 1.5),
-            new Cartesian2D(1.5, 0.5),
-            new Cartesian2D(0.5, 0.5)
-        });
-        checkPoints(Region.Location.BOUNDARY, set, new Cartesian2D[] {
-            new Cartesian2D(1.0, 1.0),
-            new Cartesian2D(2.0, 2.0),
-            new Cartesian2D(1.0, 1.5),
-            new Cartesian2D(1.5, 2.0)
-        });
-    }
-
-    @Test
-    public void testXor() {
-        // arrange
-        Cartesian2D[][] vertices1 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D( 2.0,  0.0),
-                new Cartesian2D( 2.0,  2.0),
-                new Cartesian2D( 0.0,  2.0)
-            }
-        };
-        PolygonsSet set1 = buildSet(vertices1);
-        Cartesian2D[][] vertices2 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 1.0,  1.0),
-                new Cartesian2D( 3.0,  1.0),
-                new Cartesian2D( 3.0,  3.0),
-                new Cartesian2D( 1.0,  3.0)
-            }
-        };
-        PolygonsSet set2 = buildSet(vertices2);
-
-        // act
-        PolygonsSet set  = (PolygonsSet) new RegionFactory<Euclidean2D>().xor(set1.copySelf(),
-                                                                              set2.copySelf());
-
-        // assert
-        checkVertexLoopsEquivalent(vertices1, set1.getVertices());
-        checkVertexLoopsEquivalent(vertices2, set2.getVertices());
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D( 2.0,  0.0),
-                new Cartesian2D( 2.0,  1.0),
-                new Cartesian2D( 3.0,  1.0),
-                new Cartesian2D( 3.0,  3.0),
-                new Cartesian2D( 1.0,  3.0),
-                new Cartesian2D( 1.0,  2.0),
-                new Cartesian2D( 0.0,  2.0)
-            },
-            new Cartesian2D[] {
-                new Cartesian2D( 1.0,  1.0),
-                new Cartesian2D( 1.0,  2.0),
-                new Cartesian2D( 2.0,  2.0),
-                new Cartesian2D( 2.0,  1.0)
-            }
-        }, set.getVertices());
-
-        checkPoints(Region.Location.INSIDE, set, new Cartesian2D[] {
-            new Cartesian2D(0.5, 0.5),
-            new Cartesian2D(2.5, 2.5),
-            new Cartesian2D(0.5, 1.5),
-            new Cartesian2D(1.5, 0.5),
-            new Cartesian2D(1.5, 2.5),
-            new Cartesian2D(2.5, 1.5),
-            new Cartesian2D(2.5, 2.5)
-        });
-        checkPoints(Region.Location.OUTSIDE, set, new Cartesian2D[] {
-            new Cartesian2D(-0.5, 0.5),
-            new Cartesian2D( 0.5, 2.5),
-            new Cartesian2D( 2.5, 0.5),
-            new Cartesian2D( 1.5, 1.5),
-            new Cartesian2D( 3.5, 2.5)
-        });
-        checkPoints(Region.Location.BOUNDARY, set, new Cartesian2D[] {
-            new Cartesian2D(1.0, 1.0),
-            new Cartesian2D(2.0, 2.0),
-            new Cartesian2D(1.5, 1.0),
-            new Cartesian2D(2.0, 1.5),
-            new Cartesian2D(0.0, 0.0),
-            new Cartesian2D(0.5, 2.0),
-            new Cartesian2D(2.0, 0.5),
-            new Cartesian2D(2.5, 1.0),
-            new Cartesian2D(3.0, 2.5)
-        });
-    }
-
-    @Test
-    public void testDifference() {
-        // arrange
-        Cartesian2D[][] vertices1 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D( 2.0,  0.0),
-                new Cartesian2D( 2.0,  2.0),
-                new Cartesian2D( 0.0,  2.0)
-            }
-        };
-        PolygonsSet set1 = buildSet(vertices1);
-        Cartesian2D[][] vertices2 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 1.0,  1.0),
-                new Cartesian2D( 3.0,  1.0),
-                new Cartesian2D( 3.0,  3.0),
-                new Cartesian2D( 1.0,  3.0)
-            }
-        };
-        PolygonsSet set2 = buildSet(vertices2);
-
-        // act
-        PolygonsSet set  = (PolygonsSet) new RegionFactory<Euclidean2D>().difference(set1.copySelf(),
-                                                                                     set2.copySelf());
-
-        // assert
-        checkVertexLoopsEquivalent(vertices1, set1.getVertices());
-        checkVertexLoopsEquivalent(vertices2, set2.getVertices());
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.0,  0.0),
-                new Cartesian2D( 2.0,  0.0),
-                new Cartesian2D( 2.0,  1.0),
-                new Cartesian2D( 1.0,  1.0),
-                new Cartesian2D( 1.0,  2.0),
-                new Cartesian2D( 0.0,  2.0)
-            }
-        }, set.getVertices());
-
-        checkPoints(Region.Location.INSIDE, set, new Cartesian2D[] {
-            new Cartesian2D(0.5, 0.5),
-            new Cartesian2D(0.5, 1.5),
-            new Cartesian2D(1.5, 0.5)
-        });
-        checkPoints(Region.Location.OUTSIDE, set, new Cartesian2D[] {
-            new Cartesian2D( 2.5, 2.5),
-            new Cartesian2D(-0.5, 0.5),
-            new Cartesian2D( 0.5, 2.5),
-            new Cartesian2D( 2.5, 0.5),
-            new Cartesian2D( 1.5, 1.5),
-            new Cartesian2D( 3.5, 2.5),
-            new Cartesian2D( 1.5, 2.5),
-            new Cartesian2D( 2.5, 1.5),
-            new Cartesian2D( 2.0, 1.5),
-            new Cartesian2D( 2.0, 2.0),
-            new Cartesian2D( 2.5, 1.0),
-            new Cartesian2D( 2.5, 2.5),
-            new Cartesian2D( 3.0, 2.5)
-        });
-        checkPoints(Region.Location.BOUNDARY, set, new Cartesian2D[] {
-            new Cartesian2D(1.0, 1.0),
-            new Cartesian2D(1.5, 1.0),
-            new Cartesian2D(0.0, 0.0),
-            new Cartesian2D(0.5, 2.0),
-            new Cartesian2D(2.0, 0.5)
-        });
-    }
-
-    @Test
-    public void testEmptyDifference() {
-        // arrange
-        Cartesian2D[][] vertices1 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.5, 3.5),
-                new Cartesian2D( 0.5, 4.5),
-                new Cartesian2D(-0.5, 4.5),
-                new Cartesian2D(-0.5, 3.5)
-            }
-        };
-        PolygonsSet set1 = buildSet(vertices1);
-        Cartesian2D[][] vertices2 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 1.0, 2.0),
-                new Cartesian2D( 1.0, 8.0),
-                new Cartesian2D(-1.0, 8.0),
-                new Cartesian2D(-1.0, 2.0)
-            }
-        };
-        PolygonsSet set2 = buildSet(vertices2);
-
-        // act
-        PolygonsSet diff = (PolygonsSet) new RegionFactory<Euclidean2D>().difference(set1.copySelf(), set2.copySelf());
-
-        // assert
-        Assert.assertEquals(0.0, diff.getSize(), TEST_TOLERANCE);
-        Assert.assertTrue(diff.isEmpty());
-    }
-
-    @Test
-    public void testChoppedHexagon() {
-        // arrange
-        double pi6   = FastMath.PI / 6.0;
-        double sqrt3 = FastMath.sqrt(3.0);
-        SubLine[] hyp = {
-            new Line(new Cartesian2D(   0.0, 1.0),  5 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Cartesian2D(-sqrt3, 1.0),  7 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Cartesian2D(-sqrt3, 1.0),  9 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Cartesian2D(-sqrt3, 0.0), 11 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Cartesian2D(   0.0, 0.0), 13 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Cartesian2D(   0.0, 1.0),  3 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Cartesian2D(-5.0 * sqrt3 / 6.0, 0.0), 9 * pi6, TEST_TOLERANCE).wholeHyperplane()
-        };
-        hyp[1] = (SubLine) hyp[1].split(hyp[0].getHyperplane()).getMinus();
-        hyp[2] = (SubLine) hyp[2].split(hyp[1].getHyperplane()).getMinus();
-        hyp[3] = (SubLine) hyp[3].split(hyp[2].getHyperplane()).getMinus();
-        hyp[4] = (SubLine) hyp[4].split(hyp[3].getHyperplane()).getMinus().split(hyp[0].getHyperplane()).getMinus();
-        hyp[5] = (SubLine) hyp[5].split(hyp[4].getHyperplane()).getMinus().split(hyp[0].getHyperplane()).getMinus();
-        hyp[6] = (SubLine) hyp[6].split(hyp[3].getHyperplane()).getMinus().split(hyp[1].getHyperplane()).getMinus();
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.TRUE);
-        for (int i = hyp.length - 1; i >= 0; --i) {
-            tree = new BSPTree<>(hyp[i], new BSPTree<Euclidean2D>(Boolean.FALSE), tree, null);
-        }
-        PolygonsSet set = new PolygonsSet(tree, TEST_TOLERANCE);
-        SubLine splitter =
-            new Line(new Cartesian2D(-2.0 * sqrt3 / 3.0, 0.0), 9 * pi6, TEST_TOLERANCE).wholeHyperplane();
-
-        // act
-        PolygonsSet slice =
-            new PolygonsSet(new BSPTree<>(splitter,
-                                                     set.getTree(false).split(splitter).getPlus(),
-                                                     new BSPTree<Euclidean2D>(Boolean.FALSE), null),
-                            TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(Region.Location.OUTSIDE,
-                            slice.checkPoint(new Cartesian2D(0.1, 0.5)));
-        Assert.assertEquals(11.0 / 3.0, slice.getBoundarySize(), TEST_TOLERANCE);
-    }
-
-    @Test
-    public void testConcentric() {
-        // arrange
-        double h = FastMath.sqrt(3.0) / 2.0;
-        Cartesian2D[][] vertices1 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.00, 0.1 * h),
-                new Cartesian2D( 0.05, 0.1 * h),
-                new Cartesian2D( 0.10, 0.2 * h),
-                new Cartesian2D( 0.05, 0.3 * h),
-                new Cartesian2D(-0.05, 0.3 * h),
-                new Cartesian2D(-0.10, 0.2 * h),
-                new Cartesian2D(-0.05, 0.1 * h)
-            }
-        };
-        PolygonsSet set1 = buildSet(vertices1);
-        Cartesian2D[][] vertices2 = new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D( 0.00, 0.0 * h),
-                new Cartesian2D( 0.10, 0.0 * h),
-                new Cartesian2D( 0.20, 0.2 * h),
-                new Cartesian2D( 0.10, 0.4 * h),
-                new Cartesian2D(-0.10, 0.4 * h),
-                new Cartesian2D(-0.20, 0.2 * h),
-                new Cartesian2D(-0.10, 0.0 * h)
-            }
-        };
-        PolygonsSet set2 = buildSet(vertices2);
-
-        // act/assert
-        Assert.assertTrue(set2.contains(set1));
-    }
-
-    @Test
-    public void testBug20040520() {
-        // arrange
-        BSPTree<Euclidean2D> a0 =
-            new BSPTree<>(buildSegment(new Cartesian2D(0.85, -0.05),
-                                                  new Cartesian2D(0.90, -0.10)),
-                                                  new BSPTree<Euclidean2D>(Boolean.FALSE),
-                                                  new BSPTree<Euclidean2D>(Boolean.TRUE),
-                                                  null);
-        BSPTree<Euclidean2D> a1 =
-            new BSPTree<>(buildSegment(new Cartesian2D(0.85, -0.10),
-                                                  new Cartesian2D(0.90, -0.10)),
-                                                  new BSPTree<Euclidean2D>(Boolean.FALSE), a0, null);
-        BSPTree<Euclidean2D> a2 =
-            new BSPTree<>(buildSegment(new Cartesian2D(0.90, -0.05),
-                                                  new Cartesian2D(0.85, -0.05)),
-                                                  new BSPTree<Euclidean2D>(Boolean.FALSE), a1, null);
-        BSPTree<Euclidean2D> a3 =
-            new BSPTree<>(buildSegment(new Cartesian2D(0.82, -0.05),
-                                                  new Cartesian2D(0.82, -0.08)),
-                                                  new BSPTree<Euclidean2D>(Boolean.FALSE),
-                                                  new BSPTree<Euclidean2D>(Boolean.TRUE),
-                                                  null);
-        BSPTree<Euclidean2D> a4 =
-            new BSPTree<>(buildHalfLine(new Cartesian2D(0.85, -0.05),
-                                                   new Cartesian2D(0.80, -0.05),
-                                                   false),
-                                                   new BSPTree<Euclidean2D>(Boolean.FALSE), a3, null);
-        BSPTree<Euclidean2D> a5 =
-            new BSPTree<>(buildSegment(new Cartesian2D(0.82, -0.08),
-                                                  new Cartesian2D(0.82, -0.18)),
-                                                  new BSPTree<Euclidean2D>(Boolean.FALSE),
-                                                  new BSPTree<Euclidean2D>(Boolean.TRUE),
-                                                  null);
-        BSPTree<Euclidean2D> a6 =
-            new BSPTree<>(buildHalfLine(new Cartesian2D(0.82, -0.18),
-                                                   new Cartesian2D(0.85, -0.15),
-                                                   true),
-                                                   new BSPTree<Euclidean2D>(Boolean.FALSE), a5, null);
-        BSPTree<Euclidean2D> a7 =
-            new BSPTree<>(buildHalfLine(new Cartesian2D(0.85, -0.05),
-                                                   new Cartesian2D(0.82, -0.08),
-                                                   false),
-                                                   a4, a6, null);
-        BSPTree<Euclidean2D> a8 =
-            new BSPTree<>(buildLine(new Cartesian2D(0.85, -0.25),
-                                               new Cartesian2D(0.85,  0.05)),
-                                               a2, a7, null);
-        BSPTree<Euclidean2D> a9 =
-            new BSPTree<>(buildLine(new Cartesian2D(0.90,  0.05),
-                                               new Cartesian2D(0.90, -0.50)),
-                                               a8, new BSPTree<Euclidean2D>(Boolean.FALSE), null);
-
-        BSPTree<Euclidean2D> b0 =
-            new BSPTree<>(buildSegment(new Cartesian2D(0.92, -0.12),
-                                                  new Cartesian2D(0.92, -0.08)),
-                                                  new BSPTree<Euclidean2D>(Boolean.FALSE), new BSPTree<Euclidean2D>(Boolean.TRUE),
-                                                  null);
-        BSPTree<Euclidean2D> b1 =
-            new BSPTree<>(buildHalfLine(new Cartesian2D(0.92, -0.08),
-                                                   new Cartesian2D(0.90, -0.10),
-                                                   true),
-                                                   new BSPTree<Euclidean2D>(Boolean.FALSE), b0, null);
-        BSPTree<Euclidean2D> b2 =
-            new BSPTree<>(buildSegment(new Cartesian2D(0.92, -0.18),
-                                                  new Cartesian2D(0.92, -0.12)),
-                                                  new BSPTree<Euclidean2D>(Boolean.FALSE), new BSPTree<Euclidean2D>(Boolean.TRUE),
-                                                  null);
-        BSPTree<Euclidean2D> b3 =
-            new BSPTree<>(buildSegment(new Cartesian2D(0.85, -0.15),
-                                                  new Cartesian2D(0.90, -0.20)),
-                                                  new BSPTree<Euclidean2D>(Boolean.FALSE), b2, null);
-        BSPTree<Euclidean2D> b4 =
-            new BSPTree<>(buildSegment(new Cartesian2D(0.95, -0.15),
-                                                  new Cartesian2D(0.85, -0.05)),
-                                                  b1, b3, null);
-        BSPTree<Euclidean2D> b5 =
-            new BSPTree<>(buildHalfLine(new Cartesian2D(0.85, -0.05),
-                                                   new Cartesian2D(0.85, -0.25),
-                                                   true),
-                                                   new BSPTree<Euclidean2D>(Boolean.FALSE), b4, null);
-        BSPTree<Euclidean2D> b6 =
-            new BSPTree<>(buildLine(new Cartesian2D(0.0, -1.10),
-                                               new Cartesian2D(1.0, -0.10)),
-                                               new BSPTree<Euclidean2D>(Boolean.FALSE), b5, null);
-
-        // act
-        PolygonsSet c =
-            (PolygonsSet) new RegionFactory<Euclidean2D>().union(new PolygonsSet(a9, TEST_TOLERANCE),
-                                                                 new PolygonsSet(b6, TEST_TOLERANCE));
-
-        // assert
-        checkPoints(Region.Location.INSIDE, c, new Cartesian2D[] {
-            new Cartesian2D(0.83, -0.06),
-            new Cartesian2D(0.83, -0.15),
-            new Cartesian2D(0.88, -0.15),
-            new Cartesian2D(0.88, -0.09),
-            new Cartesian2D(0.88, -0.07),
-            new Cartesian2D(0.91, -0.18),
-            new Cartesian2D(0.91, -0.10)
-        });
-
-        checkPoints(Region.Location.OUTSIDE, c, new Cartesian2D[] {
-            new Cartesian2D(0.80, -0.10),
-            new Cartesian2D(0.83, -0.50),
-            new Cartesian2D(0.83, -0.20),
-            new Cartesian2D(0.83, -0.02),
-            new Cartesian2D(0.87, -0.50),
-            new Cartesian2D(0.87, -0.20),
-            new Cartesian2D(0.87, -0.02),
-            new Cartesian2D(0.91, -0.20),
-            new Cartesian2D(0.91, -0.08),
-            new Cartesian2D(0.93, -0.15)
-        });
-
-        checkVertexLoopsEquivalent(new Cartesian2D[][] {
-            new Cartesian2D[] {
-                new Cartesian2D(0.85, -0.15),
-                new Cartesian2D(0.90, -0.20),
-                new Cartesian2D(0.92, -0.18),
-                new Cartesian2D(0.92, -0.08),
-                new Cartesian2D(0.90, -0.10),
-                new Cartesian2D(0.90, -0.05),
-                new Cartesian2D(0.82, -0.05),
-                new Cartesian2D(0.82, -0.18),
-            }
-        }, c.getVertices());
-    }
-
-    @Test
-    public void testBug20041003() {
-        // arrange
-        Line[] l = {
-            new Line(new Cartesian2D(0.0, 0.625000007541172),
-                     new Cartesian2D(1.0, 0.625000007541172), TEST_TOLERANCE),
-            new Line(new Cartesian2D(-0.19204433621902645, 0.0),
-                     new Cartesian2D(-0.19204433621902645, 1.0), TEST_TOLERANCE),
-            new Line(new Cartesian2D(-0.40303524786887,  0.4248364535319128),
-                     new Cartesian2D(-1.12851149797877, -0.2634107480798909), TEST_TOLERANCE),
-            new Line(new Cartesian2D(0.0, 2.0),
-                     new Cartesian2D(1.0, 2.0), TEST_TOLERANCE)
-        };
-
-        BSPTree<Euclidean2D> node1 =
-            new BSPTree<>(new SubLine(l[0],
-                                                 new IntervalsSet(intersectionAbscissa(l[0], l[1]),
-                                                                  intersectionAbscissa(l[0], l[2]),
-                                                                  TEST_TOLERANCE)),
-                                     new BSPTree<Euclidean2D>(Boolean.TRUE),
-                                     new BSPTree<Euclidean2D>(Boolean.FALSE),
-                                     null);
-        BSPTree<Euclidean2D> node2 =
-            new BSPTree<>(new SubLine(l[1],
-                                                 new IntervalsSet(intersectionAbscissa(l[1], l[2]),
-                                                                  intersectionAbscissa(l[1], l[3]),
-                                                                  TEST_TOLERANCE)),
-                                     node1,
-                                     new BSPTree<Euclidean2D>(Boolean.FALSE),
-                                     null);
-        BSPTree<Euclidean2D> node3 =
-            new BSPTree<>(new SubLine(l[2],
-                                                 new IntervalsSet(intersectionAbscissa(l[2], l[3]),
-                                                 Double.POSITIVE_INFINITY, TEST_TOLERANCE)),
-                                     node2,
-                                     new BSPTree<Euclidean2D>(Boolean.FALSE),
-                                     null);
-        BSPTree<Euclidean2D> node4 =
-            new BSPTree<>(l[3].wholeHyperplane(),
-                                     node3,
-                                     new BSPTree<Euclidean2D>(Boolean.FALSE),
-                                     null);
-
-        // act
-        PolygonsSet set = new PolygonsSet(node4, TEST_TOLERANCE);
-
-        // assert
-        Assert.assertEquals(0, set.getVertices().length);
-    }
-
-    @Test
-    public void testSqueezedHexa() {
-        // act
-        PolygonsSet set = new PolygonsSet(TEST_TOLERANCE,
-                                          new Cartesian2D(-6, -4), new Cartesian2D(-8, -8), new Cartesian2D(  8, -8),
-                                          new Cartesian2D( 6, -4), new Cartesian2D(10,  4), new Cartesian2D(-10,  4));
-
-        // assert
-        Assert.assertEquals(Location.OUTSIDE, set.checkPoint(new Cartesian2D(0, 6)));
-    }
-
-    @Test
-    public void testIssue880Simplified() {
-        // arrange
-        Cartesian2D[] vertices1 = new Cartesian2D[] {
-            new Cartesian2D( 90.13595870833188,  38.33604606376991),
-            new Cartesian2D( 90.14047850603913,  38.34600084496253),
-            new Cartesian2D( 90.11045289492762,  38.36801537312368),
-            new Cartesian2D( 90.10871471476526,  38.36878044144294),
-            new Cartesian2D( 90.10424901707671,  38.374300101757),
-            new Cartesian2D( 90.0979455456843,   38.373578376172475),
-            new Cartesian2D( 90.09081227075944,  38.37526295920463),
-            new Cartesian2D( 90.09081378927135,  38.375193883266434)
-        };
-
-        // act
-        PolygonsSet set1 = new PolygonsSet(TEST_TOLERANCE, vertices1);
-
-        // assert
-        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(new Cartesian2D(90.12,  38.32)));
-        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(new Cartesian2D(90.135, 38.355)));
-
-    }
-
-    @Test
-    public void testIssue880Complete() {
-        Cartesian2D[] vertices1 = new Cartesian2D[] {
-                new Cartesian2D( 90.08714908223715,  38.370299337260235),
-                new Cartesian2D( 90.08709517675004,  38.3702895991413),
-                new Cartesian2D( 90.08401538704919,  38.368849330127944),
-                new Cartesian2D( 90.08258210430711,  38.367634558585564),
-                new Cartesian2D( 90.08251455106665,  38.36763409247078),
-                new Cartesian2D( 90.08106599752608,  38.36761621664249),
-                new Cartesian2D( 90.08249585300035,  38.36753627557965),
-                new Cartesian2D( 90.09075743352184,  38.35914647644972),
-                new Cartesian2D( 90.09099945896571,  38.35896264724079),
-                new Cartesian2D( 90.09269383800086,  38.34595756121246),
-                new Cartesian2D( 90.09638631543191,  38.3457988093121),
-                new Cartesian2D( 90.09666417351019,  38.34523360999418),
-                new Cartesian2D( 90.1297082145872,  38.337670454923625),
-                new Cartesian2D( 90.12971687748956,  38.337669827794684),
-                new Cartesian2D( 90.1240820219179,  38.34328502001131),
-                new Cartesian2D( 90.13084259656404,  38.34017811765017),
-                new Cartesian2D( 90.13378567942857,  38.33860579180606),
-                new Cartesian2D( 90.13519557833206,  38.33621054663689),
-                new Cartesian2D( 90.13545616732307,  38.33614965452864),
-                new Cartesian2D( 90.13553111202748,  38.33613962818305),
-                new Cartesian2D( 90.1356903436448,  38.33610227127048),
-                new Cartesian2D( 90.13576283227428,  38.33609255422783),
-                new Cartesian2D( 90.13595870833188,  38.33604606376991),
-                new Cartesian2D( 90.1361556630693,  38.3360024198866),
-                new Cartesian2D( 90.13622408795709,  38.335987048115726),
-                new Cartesian2D( 90.13696189099994,  38.33581914328681),
-                new Cartesian2D( 90.13746655304897,  38.33616706665265),
-                new Cartesian2D( 90.13845973716064,  38.33650776167099),
-                new Cartesian2D( 90.13950901827667,  38.3368469456463),
-                new Cartesian2D( 90.14393814424852,  38.337591835857495),
-                new Cartesian2D( 90.14483839716831,  38.337076122362475),
-                new Cartesian2D( 90.14565474433601,  38.33769000964429),
-                new Cartesian2D( 90.14569421179482,  38.3377117256905),
-                new Cartesian2D( 90.14577067124333,  38.33770883625908),
-                new Cartesian2D( 90.14600350631684,  38.337714326520995),
-                new Cartesian2D( 90.14600355139731,  38.33771435193319),
-                new Cartesian2D( 90.14600369112401,  38.33771443882085),
-                new Cartesian2D( 90.14600382486884,  38.33771453466096),
-                new Cartesian2D( 90.14600395205912,  38.33771463904344),
-                new Cartesian2D( 90.14600407214999,  38.337714751520764),
-                new Cartesian2D( 90.14600418462749,  38.337714871611695),
-                new Cartesian2D( 90.14600422249327,  38.337714915811034),
-                new Cartesian2D( 90.14867838361471,  38.34113888210675),
-                new Cartesian2D( 90.14923750157374,  38.341582537502575),
-                new Cartesian2D( 90.14877083250991,  38.34160685841391),
-                new Cartesian2D( 90.14816667319519,  38.34244232585684),
-                new Cartesian2D( 90.14797696744586,  38.34248455284745),
-                new Cartesian2D( 90.14484318014337,  38.34385573215269),
-                new Cartesian2D( 90.14477919958296,  38.3453797747614),
-                new Cartesian2D( 90.14202393306448,  38.34464324839456),
-                new Cartesian2D( 90.14198920640195,  38.344651155237216),
-                new Cartesian2D( 90.14155207025175,  38.34486424263724),
-                new Cartesian2D( 90.1415196143314,  38.344871730519),
-                new Cartesian2D( 90.14128611910814,  38.34500196593859),
-                new Cartesian2D( 90.14047850603913,  38.34600084496253),
-                new Cartesian2D( 90.14045907000337,  38.34601860032171),
-                new Cartesian2D( 90.14039496493928,  38.346223030432384),
-                new Cartesian2D( 90.14037626063737,  38.346240203360026),
-                new Cartesian2D( 90.14030005823724,  38.34646920000705),
-                new Cartesian2D( 90.13799164754806,  38.34903093011013),
-                new Cartesian2D( 90.11045289492762,  38.36801537312368),
-                new Cartesian2D( 90.10871471476526,  38.36878044144294),
-                new Cartesian2D( 90.10424901707671,  38.374300101757),
-                new Cartesian2D( 90.10263482039932,  38.37310041316073),
-                new Cartesian2D( 90.09834601753448,  38.373615053823414),
-                new Cartesian2D( 90.0979455456843,  38.373578376172475),
-                new Cartesian2D( 90.09086514328669,  38.37527884194668),
-                new Cartesian2D( 90.09084931407364,  38.37590801712463),
-                new Cartesian2D( 90.09081227075944,  38.37526295920463),
-                new Cartesian2D( 90.09081378927135,  38.375193883266434)
-        };
-        PolygonsSet set1 = new PolygonsSet(1.0e-8, vertices1);
-        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(new Cartesian2D(90.0905,  38.3755)));
-        Assert.assertEquals(Location.INSIDE,  set1.checkPoint(new Cartesian2D(90.09084, 38.3755)));
-        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(new Cartesian2D(90.0913,  38.3755)));
-        Assert.assertEquals(Location.INSIDE,  set1.checkPoint(new Cartesian2D(90.1042,  38.3739)));
-        Assert.assertEquals(Location.INSIDE,  set1.checkPoint(new Cartesian2D(90.1111,  38.3673)));
-        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(new Cartesian2D(90.0959,  38.3457)));
-
-        Cartesian2D[] vertices2 = new Cartesian2D[] {
-                new Cartesian2D( 90.13067558880044,  38.36977255037573),
-                new Cartesian2D( 90.12907570488,  38.36817308242706),
-                new Cartesian2D( 90.1342774136516,  38.356886880294724),
-                new Cartesian2D( 90.13090330629757,  38.34664392676211),
-                new Cartesian2D( 90.13078571364593,  38.344904617518466),
-                new Cartesian2D( 90.1315602208914,  38.3447185040846),
-                new Cartesian2D( 90.1316336226821,  38.34470643148342),
-                new Cartesian2D( 90.134020944832,  38.340936644972885),
-                new Cartesian2D( 90.13912536387306,  38.335497255122334),
-                new Cartesian2D( 90.1396178806582,  38.334878075552126),
-                new Cartesian2D( 90.14083049696671,  38.33316530644106),
-                new Cartesian2D( 90.14145252901329,  38.33152722916191),
-                new Cartesian2D( 90.1404779335565,  38.32863516047786),
-                new Cartesian2D( 90.14282712131586,  38.327504432532066),
-                new Cartesian2D( 90.14616669875488,  38.3237354115015),
-                new Cartesian2D( 90.14860976050608,  38.315714862457924),
-                new Cartesian2D( 90.14999277782437,  38.3164932507504),
-                new Cartesian2D( 90.15005207194997,  38.316534677663356),
-                new Cartesian2D( 90.15508513859612,  38.31878731691609),
-                new Cartesian2D( 90.15919938519221,  38.31852743183782),
-                new Cartesian2D( 90.16093758658837,  38.31880662005153),
-                new Cartesian2D( 90.16099420184912,  38.318825953291594),
-                new Cartesian2D( 90.1665411125756,  38.31859497874757),
-                new Cartesian2D( 90.16999653861313,  38.32505772048029),
-                new Cartesian2D( 90.17475243391698,  38.32594398441148),
-                new Cartesian2D( 90.17940844844992,  38.327427213761325),
-                new Cartesian2D( 90.20951909541378,  38.330616833491774),
-                new Cartesian2D( 90.2155400467941,  38.331746223670336),
-                new Cartesian2D( 90.21559881391778,  38.33175551425302),
-                new Cartesian2D( 90.21916646426041,  38.332584299620805),
-                new Cartesian2D( 90.23863749852285,  38.34778978875795),
-                new Cartesian2D( 90.25459855175802,  38.357790570608984),
-                new Cartesian2D( 90.25964298227257,  38.356918010203174),
-                new Cartesian2D( 90.26024593994703,  38.361692743151366),
-                new Cartesian2D( 90.26146187570015,  38.36311080550837),
-                new Cartesian2D( 90.26614159359622,  38.36510808579902),
-                new Cartesian2D( 90.26621342936448,  38.36507942500333),
-                new Cartesian2D( 90.26652190211962,  38.36494042196722),
-                new Cartesian2D( 90.26621240678867,  38.365113172030874),
-                new Cartesian2D( 90.26614057102057,  38.365141832826794),
-                new Cartesian2D( 90.26380080055299,  38.3660381760273),
-                new Cartesian2D( 90.26315345241,  38.36670658276421),
-                new Cartesian2D( 90.26251574942881,  38.367490323488084),
-                new Cartesian2D( 90.26247873448426,  38.36755266444749),
-                new Cartesian2D( 90.26234628016698,  38.36787989125406),
-                new Cartesian2D( 90.26214559424784,  38.36945909356126),
-                new Cartesian2D( 90.25861728442555,  38.37200753430875),
-                new Cartesian2D( 90.23905557537864,  38.375405314295904),
-                new Cartesian2D( 90.22517251874075,  38.38984691662256),
-                new Cartesian2D( 90.22549955153215,  38.3911564273979),
-                new Cartesian2D( 90.22434386063355,  38.391476432092134),
-                new Cartesian2D( 90.22147729457276,  38.39134652252034),
-                new Cartesian2D( 90.22142070120117,  38.391349167741964),
-                new Cartesian2D( 90.20665060751588,  38.39475580900313),
-                new Cartesian2D( 90.20042268367109,  38.39842558622888),
-                new Cartesian2D( 90.17423771242085,  38.402727751805344),
-                new Cartesian2D( 90.16756796257476,  38.40913898597597),
-                new Cartesian2D( 90.16728283954308,  38.411255399912875),
-                new Cartesian2D( 90.16703538220418,  38.41136059866693),
-                new Cartesian2D( 90.16725865657685,  38.41013618805954),
-                new Cartesian2D( 90.16746107640665,  38.40902614307544),
-                new Cartesian2D( 90.16122795307462,  38.39773101873203)
-        };
-        PolygonsSet set2 = new PolygonsSet(1.0e-8, vertices2);
-        PolygonsSet set  = (PolygonsSet) new
-                RegionFactory<Euclidean2D>().difference(set1.copySelf(),
-                                                        set2.copySelf());
-
-        Cartesian2D[][] vertices = set.getVertices();
-        Assert.assertTrue(vertices[0][0] != null);
-        Assert.assertEquals(1, vertices.length);
-    }
-
-    @Test
-    public void testTooThinBox() {
-        // act/assert
-        Assert.assertEquals(0.0,
-                            new PolygonsSet(0.0, 0.0, 0.0, 10.3206397147574, TEST_TOLERANCE).getSize(),
-                            TEST_TOLERANCE);
-    }
-
-    @Test
-    public void testWrongUsage() {
-        // the following is a wrong usage of the constructor.
-        // as explained in the javadoc, the failure is NOT detected at construction
-        // time but occurs later on
-        PolygonsSet ps = new PolygonsSet(new BSPTree<Euclidean2D>(), TEST_TOLERANCE);
-        Assert.assertNotNull(ps);
-        try {
-            ps.getSize();
-            Assert.fail("an exception should have been thrown");
-        } catch (NullPointerException npe) {
-            // this is expected
-        }
-    }
-
-    @Test
-    public void testIssue1162() {
-        // arrange
-        PolygonsSet p = new PolygonsSet(TEST_TOLERANCE,
-                                                new Cartesian2D(4.267199999996532, -11.928637756014894),
-                                                new Cartesian2D(4.267200000026445, -14.12360595809307),
-                                                new Cartesian2D(9.144000000273694, -14.12360595809307),
-                                                new Cartesian2D(9.144000000233383, -11.928637756020067));
-
-        PolygonsSet w = new PolygonsSet(TEST_TOLERANCE,
-                                                new Cartesian2D(2.56735636510452512E-9, -11.933116461089332),
-                                                new Cartesian2D(2.56735636510452512E-9, -12.393225665247766),
-                                                new Cartesian2D(2.56735636510452512E-9, -27.785625665247778),
-                                                new Cartesian2D(4.267200000030211,      -27.785625665247778),
-                                                new Cartesian2D(4.267200000030211,      -11.933116461089332));
-
-        // act/assert
-        Assert.assertFalse(p.contains(w));
-    }
-
-    @Test
-    public void testThinRectangle_toleranceLessThanWidth_resultIsAccurate() {
-        // if tolerance is smaller than rectangle width, the rectangle is computed accurately
-
-        // arrange
-        RegionFactory<Euclidean2D> factory = new RegionFactory<>();
-        Cartesian2D pA = new Cartesian2D(0.0,        1.0);
-        Cartesian2D pB = new Cartesian2D(0.0,        0.0);
-        Cartesian2D pC = new Cartesian2D(1.0 / 64.0, 0.0);
-        Cartesian2D pD = new Cartesian2D(1.0 / 64.0, 1.0);
-
-        // if tolerance is smaller than rectangle width, the rectangle is computed accurately
-        Hyperplane<Euclidean2D>[] h1 = new Line[] {
-            new Line(pA, pB, 1.0 / 256),
-            new Line(pB, pC, 1.0 / 256),
-            new Line(pC, pD, 1.0 / 256),
-            new Line(pD, pA, 1.0 / 256)
-        };
-
-        // act
-        Region<Euclidean2D> accuratePolygon = factory.buildConvex(h1);
-
-        // assert
-        Assert.assertEquals(1.0 / 64.0, accuratePolygon.getSize(), TEST_TOLERANCE);
-        GeometryTestUtils.assertPositiveInfinity(new RegionFactory<Euclidean2D>().getComplement(accuratePolygon).getSize());
-        Assert.assertEquals(2 * (1.0 + 1.0 / 64.0), accuratePolygon.getBoundarySize(), TEST_TOLERANCE);
-    }
-
-    @Test
-    public void testThinRectangle_toleranceGreaterThanWidth_resultIsDegenerate() {
-        // if tolerance is larger than rectangle width, the rectangle degenerates
-        // as of 3.3, its two long edges cannot be distinguished anymore and this part of the test did fail
-        // this has been fixed in 3.4 (issue MATH-1174)
-
-        // arrange
-        RegionFactory<Euclidean2D> factory = new RegionFactory<>();
-        Cartesian2D pA = new Cartesian2D(0.0,        1.0);
-        Cartesian2D pB = new Cartesian2D(0.0,        0.0);
-        Cartesian2D pC = new Cartesian2D(1.0 / 64.0, 0.0);
-        Cartesian2D pD = new Cartesian2D(1.0 / 64.0, 1.0);
-
-        Hyperplane<Euclidean2D>[] h2 = new Line[] {
-                new Line(pA, pB, 1.0 / 16),
-                new Line(pB, pC, 1.0 / 16),
-                new Line(pC, pD, 1.0 / 16),
-                new Line(pD, pA, 1.0 / 16)
-            };
-
-        // act
-        Region<Euclidean2D> degeneratedPolygon = factory.buildConvex(h2);
-
-        // assert
-        Assert.assertEquals(0.0, degeneratedPolygon.getSize(), TEST_TOLERANCE);
-        Assert.assertTrue(degeneratedPolygon.isEmpty());
-    }
-
-    @Test(expected = MathIllegalArgumentException.class)
-    public void testInconsistentHyperplanes() {
-        // act
-        double tolerance = TEST_TOLERANCE;
-        new RegionFactory<Euclidean2D>().buildConvex(new Line(new Cartesian2D(0, 0), new Cartesian2D(0, 1), tolerance),
-                                                     new Line(new Cartesian2D(1, 1), new Cartesian2D(1, 0), tolerance));
-    }
-
-    @Test
-    public void testBoundarySimplification() {
-        // a simple square will result in a 4 cuts and 5 leafs tree
-        PolygonsSet square = new PolygonsSet(TEST_TOLERANCE,
-                                             new Cartesian2D(0, 0),
-                                             new Cartesian2D(1, 0),
-                                             new Cartesian2D(1, 1),
-                                             new Cartesian2D(0, 1));
-        Cartesian2D[][] squareBoundary = square.getVertices();
-        Assert.assertEquals(1, squareBoundary.length);
-        Assert.assertEquals(4, squareBoundary[0].length);
-        Counter squareCount = new Counter();
-        squareCount.count(square);
-        Assert.assertEquals(4, squareCount.getInternalNodes());
-        Assert.assertEquals(5, squareCount.getLeafNodes());
-
-        // splitting the square in two halves increases the BSP tree
-        // with 3 more cuts and 3 more leaf nodes
-        SubLine cut = new Line(new Cartesian2D(0.5, 0.5), 0.0, square.getTolerance()).wholeHyperplane();
-        PolygonsSet splitSquare = new PolygonsSet(square.getTree(false).split(cut),
-                                                  square.getTolerance());
-        Counter splitSquareCount = new Counter();
-        splitSquareCount.count(splitSquare);
-        Assert.assertEquals(squareCount.getInternalNodes() + 3, splitSquareCount.getInternalNodes());
-        Assert.assertEquals(squareCount.getLeafNodes()     + 3, splitSquareCount.getLeafNodes());
-
-        // the number of vertices should not change, as the intermediate vertices
-        // at (0.0, 0.5) and (1.0, 0.5) induced by the top level horizontal split
-        // should be removed during the boundary extraction process
-        Cartesian2D[][] splitBoundary = splitSquare.getVertices();
-        Assert.assertEquals(1, splitBoundary.length);
-        Assert.assertEquals(4, splitBoundary[0].length);
-    }
-
-    private static class Counter {
-
-        private int internalNodes;
-        private int leafNodes;
-
-        public void count(PolygonsSet polygonsSet) {
-            leafNodes     = 0;
-            internalNodes = 0;
-            polygonsSet.getTree(false).visit(new BSPTreeVisitor<Euclidean2D>() {
-                @Override
-                public Order visitOrder(BSPTree<Euclidean2D> node) {
-                    return Order.SUB_PLUS_MINUS;
-                }
-                @Override
-                public void visitInternalNode(BSPTree<Euclidean2D> node) {
-                    ++internalNodes;
-                }
-                @Override
-                public void visitLeafNode(BSPTree<Euclidean2D> node) {
-                    ++leafNodes;
-                }
-
-            });
-        }
-
-        public int getInternalNodes() {
-            return internalNodes;
-        }
-
-        public int getLeafNodes() {
-            return leafNodes;
-        }
-    }
-
-    private PolygonsSet buildSet(Cartesian2D[][] vertices) {
-        ArrayList<SubHyperplane<Euclidean2D>> edges = new ArrayList<>();
-        for (int i = 0; i < vertices.length; ++i) {
-            int l = vertices[i].length;
-            for (int j = 0; j < l; ++j) {
-                edges.add(buildSegment(vertices[i][j], vertices[i][(j + 1) % l]));
-            }
-        }
-        return new PolygonsSet(edges, TEST_TOLERANCE);
-    }
-
-    private SubHyperplane<Euclidean2D> buildLine(Cartesian2D start, Cartesian2D end) {
-        return new Line(start, end, TEST_TOLERANCE).wholeHyperplane();
-    }
-
-    private double intersectionAbscissa(Line l0, Line l1) {
-        Cartesian2D p = l0.intersection(l1);
-        return (l0.toSubSpace(p)).getX();
-    }
-
-    private SubHyperplane<Euclidean2D> buildHalfLine(Cartesian2D start, Cartesian2D end,
-                                                     boolean startIsVirtual) {
-        Line   line  = new Line(start, end, TEST_TOLERANCE);
-        double lower = startIsVirtual ? Double.NEGATIVE_INFINITY : (line.toSubSpace(start)).getX();
-        double upper = startIsVirtual ? (line.toSubSpace(end)).getX() : Double.POSITIVE_INFINITY;
-        return new SubLine(line, new IntervalsSet(lower, upper, TEST_TOLERANCE));
-    }
-
-    private SubHyperplane<Euclidean2D> buildSegment(Cartesian2D start, Cartesian2D end) {
-        Line   line  = new Line(start, end, TEST_TOLERANCE);
-        double lower = (line.toSubSpace(start)).getX();
-        double upper = (line.toSubSpace(end)).getX();
-        return new SubLine(line, new IntervalsSet(lower, upper, TEST_TOLERANCE));
-    }
-
-    private void checkPoints(Region.Location expected, PolygonsSet poly, Cartesian2D ... points) {
-        for (int i = 0; i < points.length; ++i) {
-            Assert.assertEquals("Incorrect location for " + points[i], expected, poly.checkPoint(points[i]));
-        }
-    }
-
-    /** Asserts that the two arrays of vertex loops have equivalent content.
-     * @param expectedLoops
-     * @param actualLoops
-     */
-    private void checkVertexLoopsEquivalent(Cartesian2D[][] expectedLoops, Cartesian2D[][] actualLoops) {
-        Assert.assertEquals("Expected vertices array to have length of " + expectedLoops.length + " but was " + actualLoops.length,
-                expectedLoops.length, actualLoops.length);
-
-        // go through each loop in the expected array and try to find a match in the actual array
-        for (Cartesian2D[] expectedLoop : expectedLoops) {
-            boolean foundMatch = false;
-            for (Cartesian2D[] actualLoop : actualLoops) {
-                if (vertexLoopsEquivalent(expectedLoop, actualLoop, TEST_TOLERANCE)) {
-                    foundMatch = true;
-                    break;
-                }
-            }
-
-            if (!foundMatch) {
-                StringBuilder sb = new StringBuilder();
-                for (Cartesian2D[] actualLoop : actualLoops) {
-                    sb.append(Arrays.toString(actualLoop));
-                    sb.append(", ");
-                }
-                if (sb.length() > 0) {
-                    sb.delete(sb.length() - 2, sb.length());
-                }
-                Assert.fail("Failed to find vertex loop " + Arrays.toString(expectedLoop) + " in loop array [" +
-                        sb.toString() + "].");
-            }
-        }
-    }
-
-    /** Returns true if the two sets of vertices can be considered equivalent using the given
-     * tolerance. For open loops, (i.e. ones that start with null) this means that the two loops
-     * must have the exact same elements in the exact same order. For closed loops, equivalent
-     * means that one of the loops can be rotated to match the other (e.g. [3, 1, 2] is equivalent
-     * to [1, 2, 3]).
-     * @param a
-     * @param b
-     * @param tolerance
-     * @return
-     */
-    private boolean vertexLoopsEquivalent(Cartesian2D[] a, Cartesian2D[] b, double tolerance) {
-        if (a.length == b.length) {
-            if (a.length < 1) {
-                // the loops are empty
-                return true;
-            }
-            if (a[0] == null || b[0] == null) {
-                // at least one of the loops is unclosed, so there is only one
-                // possible sequence that could match
-                return vertexLoopsEqual(a, 0, b, 0, tolerance);
-            }
-            else {
-                // the loops are closed so they could be equivalent but
-                // start at different vertices
-                for (int i=0; i<a.length; ++i) {
-                    if (vertexLoopsEqual(a, 0, b, i, tolerance)) {
-                        return true;
-                    }
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /** Returns true if the two vertex loops have the same elements, starting
-     * from the given indices and allowing loop-around.
-     * @param a
-     * @param aStartIdx
-     * @param b
-     * @param bStartIdx
-     * @param tolerance
-     * @return
-     */
-    private boolean vertexLoopsEqual(Cartesian2D[] a, int aStartIdx,
-            Cartesian2D[] b, int bStartIdx, double tolerance) {
-
-        int len = a.length;
-
-        Cartesian2D ptA;
-        Cartesian2D ptB;
-        for (int i=0; i<len; ++i) {
-            ptA = a[(i + aStartIdx) % len];
-            ptB = b[(i + bStartIdx) % len];
-
-            if (!((ptA == null && ptB == null) ||
-                    (Precision.equals(ptA.getX(), ptB.getX(), tolerance) &&
-                     Precision.equals(ptA.getY(), ptB.getY(), tolerance)))) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/SegmentTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/SegmentTest.java
deleted file mode 100644
index cbbd003..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/SegmentTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.twod;
-
-import org.apache.commons.math4.geometry.euclidean.twod.Line;
-import org.apache.commons.math4.geometry.euclidean.twod.Segment;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.math4.util.FastMath;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SegmentTest {
-
-    @Test
-    public void testDistance() {
-        Cartesian2D start = new Cartesian2D(2, 2);
-        Cartesian2D end = new Cartesian2D(-2, -2);
-        Segment segment = new Segment(start, end, new Line(start, end, 1.0e-10));
-
-        // distance to center of segment
-        Assert.assertEquals(FastMath.sqrt(2), segment.distance(new Cartesian2D(1, -1)), 1.0e-10);
-
-        // distance a point on segment
-        Assert.assertEquals(FastMath.sin(Math.PI / 4.0), segment.distance(new Cartesian2D(0, -1)), 1.0e-10);
-
-        // distance to end point
-        Assert.assertEquals(FastMath.sqrt(8), segment.distance(new Cartesian2D(0, 4)), 1.0e-10);
-
-        // distance to start point
-        Assert.assertEquals(FastMath.sqrt(8), segment.distance(new Cartesian2D(0, -4)), 1.0e-10);
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/SubLineTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/SubLineTest.java
deleted file mode 100644
index cdfc2c0..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/SubLineTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * 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.twod;
-
-import java.util.List;
-
-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.twod.Line;
-import org.apache.commons.math4.geometry.euclidean.twod.Segment;
-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.RegionFactory;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SubLineTest {
-
-    @Test
-    public void testEndPoints() {
-        Cartesian2D p1 = new Cartesian2D(-1, -7);
-        Cartesian2D p2 = new Cartesian2D(7, -1);
-        Segment segment = new Segment(p1, p2, new Line(p1, p2, 1.0e-10));
-        SubLine sub = new SubLine(segment);
-        List<Segment> segments = sub.getSegments();
-        Assert.assertEquals(1, segments.size());
-        Assert.assertEquals(0.0, new Cartesian2D(-1, -7).distance(segments.get(0).getStart()), 1.0e-10);
-        Assert.assertEquals(0.0, new Cartesian2D( 7, -1).distance(segments.get(0).getEnd()), 1.0e-10);
-    }
-
-    @Test
-    public void testNoEndPoints() {
-        SubLine wholeLine = new Line(new Cartesian2D(-1, 7), new Cartesian2D(7, 1), 1.0e-10).wholeHyperplane();
-        List<Segment> segments = wholeLine.getSegments();
-        Assert.assertEquals(1, segments.size());
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getX()) &&
-                          segments.get(0).getStart().getX() < 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getY()) &&
-                          segments.get(0).getStart().getY() > 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getX()) &&
-                          segments.get(0).getEnd().getX() > 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getY()) &&
-                          segments.get(0).getEnd().getY() < 0);
-    }
-
-    @Test
-    public void testNoSegments() {
-        SubLine empty = new SubLine(new Line(new Cartesian2D(-1, -7), new Cartesian2D(7, -1), 1.0e-10),
-                                    new RegionFactory<Euclidean1D>().getComplement(new IntervalsSet(1.0e-10)));
-        List<Segment> segments = empty.getSegments();
-        Assert.assertEquals(0, segments.size());
-    }
-
-    @Test
-    public void testSeveralSegments() {
-        SubLine twoSubs = new SubLine(new Line(new Cartesian2D(-1, -7), new Cartesian2D(7, -1), 1.0e-10),
-                                    new RegionFactory<Euclidean1D>().union(new IntervalsSet(1, 2, 1.0e-10),
-                                                                           new IntervalsSet(3, 4, 1.0e-10)));
-        List<Segment> segments = twoSubs.getSegments();
-        Assert.assertEquals(2, segments.size());
-    }
-
-    @Test
-    public void testHalfInfiniteNeg() {
-        SubLine empty = new SubLine(new Line(new Cartesian2D(-1, -7), new Cartesian2D(7, -1), 1.0e-10),
-                                    new IntervalsSet(Double.NEGATIVE_INFINITY, 0.0, 1.0e-10));
-        List<Segment> segments = empty.getSegments();
-        Assert.assertEquals(1, segments.size());
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getX()) &&
-                          segments.get(0).getStart().getX() < 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getY()) &&
-                          segments.get(0).getStart().getY() < 0);
-        Assert.assertEquals(0.0, new Cartesian2D(3, -4).distance(segments.get(0).getEnd()), 1.0e-10);
-    }
-
-    @Test
-    public void testHalfInfinitePos() {
-        SubLine empty = new SubLine(new Line(new Cartesian2D(-1, -7), new Cartesian2D(7, -1), 1.0e-10),
-                                    new IntervalsSet(0.0, Double.POSITIVE_INFINITY, 1.0e-10));
-        List<Segment> segments = empty.getSegments();
-        Assert.assertEquals(1, segments.size());
-        Assert.assertEquals(0.0, new Cartesian2D(3, -4).distance(segments.get(0).getStart()), 1.0e-10);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getX()) &&
-                          segments.get(0).getEnd().getX() > 0);
-        Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getY()) &&
-                          segments.get(0).getEnd().getY() > 0);
-    }
-
-    @Test
-    public void testIntersectionInsideInside() {
-        SubLine sub1 = new SubLine(new Cartesian2D(1, 1), new Cartesian2D(3, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian2D(2, 0), new Cartesian2D(2, 2), 1.0e-10);
-        Assert.assertEquals(0.0, new Cartesian2D(2, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
-        Assert.assertEquals(0.0, new Cartesian2D(2, 1).distance(sub1.intersection(sub2, false)), 1.0e-12);
-    }
-
-    @Test
-    public void testIntersectionInsideBoundary() {
-        SubLine sub1 = new SubLine(new Cartesian2D(1, 1), new Cartesian2D(3, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian2D(2, 0), new Cartesian2D(2, 1), 1.0e-10);
-        Assert.assertEquals(0.0, new Cartesian2D(2, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-    @Test
-    public void testIntersectionInsideOutside() {
-        SubLine sub1 = new SubLine(new Cartesian2D(1, 1), new Cartesian2D(3, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian2D(2, 0), new Cartesian2D(2, 0.5), 1.0e-10);
-        Assert.assertNull(sub1.intersection(sub2, true));
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-    @Test
-    public void testIntersectionBoundaryBoundary() {
-        SubLine sub1 = new SubLine(new Cartesian2D(1, 1), new Cartesian2D(2, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian2D(2, 0), new Cartesian2D(2, 1), 1.0e-10);
-        Assert.assertEquals(0.0, new Cartesian2D(2, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-    @Test
-    public void testIntersectionBoundaryOutside() {
-        SubLine sub1 = new SubLine(new Cartesian2D(1, 1), new Cartesian2D(2, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian2D(2, 0), new Cartesian2D(2, 0.5), 1.0e-10);
-        Assert.assertNull(sub1.intersection(sub2, true));
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-    @Test
-    public void testIntersectionOutsideOutside() {
-        SubLine sub1 = new SubLine(new Cartesian2D(1, 1), new Cartesian2D(1.5, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Cartesian2D(2, 0), new Cartesian2D(2, 0.5), 1.0e-10);
-        Assert.assertNull(sub1.intersection(sub2, true));
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-    @Test
-    public void testIntersectionParallel() {
-        final SubLine sub1 = new SubLine(new Cartesian2D(0, 1), new Cartesian2D(0, 2), 1.0e-10);
-        final SubLine sub2 = new SubLine(new Cartesian2D(66, 3), new Cartesian2D(66, 4), 1.0e-10);
-        Assert.assertNull(sub1.intersection(sub2, true));
-        Assert.assertNull(sub1.intersection(sub2, false));
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2DFormatAbstractTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2DFormatAbstractTest.java
deleted file mode 100644
index 93d3421..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2DFormatAbstractTest.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * 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.twod;
-
-import java.text.NumberFormat;
-import java.text.ParsePosition;
-import java.util.Locale;
-
-import org.apache.commons.math4.exception.MathParseException;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.math4.geometry.euclidean.twod.Vector2DFormat;
-import org.junit.Assert;
-import org.junit.Test;
-
-public abstract class Vector2DFormatAbstractTest {
-
-    Vector2DFormat vector2DFormat = null;
-    Vector2DFormat vector2DFormatSquare = null;
-
-    protected abstract Locale getLocale();
-
-    protected abstract char getDecimalCharacter();
-
-    protected Vector2DFormatAbstractTest() {
-        vector2DFormat = Vector2DFormat.getInstance(getLocale());
-        final NumberFormat nf = NumberFormat.getInstance(getLocale());
-        nf.setMaximumFractionDigits(2);
-        vector2DFormatSquare = new Vector2DFormat("[", "]", " : ", nf);
-    }
-
-    @Test
-    public void testSimpleNoDecimals() {
-        Cartesian2D c = new Cartesian2D(1, 1);
-        String expected = "{1; 1}";
-        String actual = vector2DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testSimpleWithDecimals() {
-        Cartesian2D c = new Cartesian2D(1.23, 1.43);
-        String expected =
-            "{1"    + getDecimalCharacter() +
-            "23; 1" + getDecimalCharacter() +
-            "43}";
-        String actual = vector2DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testSimpleWithDecimalsTrunc() {
-        Cartesian2D c = new Cartesian2D(1.232323232323, 1.434343434343);
-        String expected =
-            "{1"    + getDecimalCharacter() +
-            "2323232323; 1" + getDecimalCharacter() +
-            "4343434343}";
-        String actual = vector2DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testNegativeX() {
-        Cartesian2D c = new Cartesian2D(-1.232323232323, 1.43);
-        String expected =
-            "{-1"    + getDecimalCharacter() +
-            "2323232323; 1" + getDecimalCharacter() +
-            "43}";
-        String actual = vector2DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testNegativeY() {
-        Cartesian2D c = new Cartesian2D(1.23, -1.434343434343);
-        String expected =
-            "{1"    + getDecimalCharacter() +
-            "23; -1" + getDecimalCharacter() +
-            "4343434343}";
-        String actual = vector2DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testNegativeZ() {
-        Cartesian2D c = new Cartesian2D(1.23, 1.43);
-        String expected =
-            "{1"    + getDecimalCharacter() +
-            "23; 1" + getDecimalCharacter() +
-            "43}";
-        String actual = vector2DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testNonDefaultSetting() {
-        Cartesian2D c = new Cartesian2D(1, 1);
-        String expected = "[1 : 1]";
-        String actual = vector2DFormatSquare.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testDefaultFormatVector2D() {
-        Locale defaultLocal = Locale.getDefault();
-        Locale.setDefault(getLocale());
-
-        Cartesian2D c = new Cartesian2D(232.22222222222, -342.3333333333);
-        String expected =
-            "{232"    + getDecimalCharacter() +
-            "2222222222; -342" + getDecimalCharacter() +
-            "3333333333}";
-        String actual = (new Vector2DFormat()).format(c);
-        Assert.assertEquals(expected, actual);
-
-        Locale.setDefault(defaultLocal);
-    }
-
-    @Test
-    public void testNan() {
-        Cartesian2D c = Cartesian2D.NaN;
-        String expected = "{(NaN); (NaN)}";
-        String actual = vector2DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testPositiveInfinity() {
-        Cartesian2D c = Cartesian2D.POSITIVE_INFINITY;
-        String expected = "{(Infinity); (Infinity)}";
-        String actual = vector2DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void tesNegativeInfinity() {
-        Cartesian2D c = Cartesian2D.NEGATIVE_INFINITY;
-        String expected = "{(-Infinity); (-Infinity)}";
-        String actual = vector2DFormat.format(c);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseSimpleNoDecimals() throws MathParseException {
-        String source = "{1; 1}";
-        Vector2D expected = new Cartesian2D(1, 1);
-        Vector2D actual = vector2DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseIgnoredWhitespace() {
-        Cartesian2D expected = new Cartesian2D(1, 1);
-        ParsePosition pos1 = new ParsePosition(0);
-        String source1 = "{1;1}";
-        Assert.assertEquals(expected, vector2DFormat.parse(source1, pos1));
-        Assert.assertEquals(source1.length(), pos1.getIndex());
-        ParsePosition pos2 = new ParsePosition(0);
-        String source2 = " { 1 ; 1 } ";
-        Assert.assertEquals(expected, vector2DFormat.parse(source2, pos2));
-        Assert.assertEquals(source2.length() - 1, pos2.getIndex());
-    }
-
-    @Test
-    public void testParseSimpleWithDecimals() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "23; 1" + getDecimalCharacter() +
-            "43}";
-        Vector2D expected = new Cartesian2D(1.23, 1.43);
-        Vector2D actual = vector2DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseSimpleWithDecimalsTrunc() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "2323; 1" + getDecimalCharacter() +
-            "4343}";
-        Vector2D expected = new Cartesian2D(1.2323, 1.4343);
-        Vector2D actual = vector2DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeX() throws MathParseException {
-        String source =
-            "{-1" + getDecimalCharacter() +
-            "2323; 1" + getDecimalCharacter() +
-            "4343}";
-        Vector2D expected = new Cartesian2D(-1.2323, 1.4343);
-        Vector2D actual = vector2DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeY() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "2323; -1" + getDecimalCharacter() +
-            "4343}";
-        Vector2D expected = new Cartesian2D(1.2323, -1.4343);
-        Vector2D actual = vector2DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeZ() throws MathParseException {
-        String source =
-            "{1" + getDecimalCharacter() +
-            "2323; 1" + getDecimalCharacter() +
-            "4343}";
-        Vector2D expected = new Cartesian2D(1.2323, 1.4343);
-        Vector2D actual = vector2DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNegativeAll() throws MathParseException {
-        String source =
-            "{-1" + getDecimalCharacter() +
-            "2323; -1" + getDecimalCharacter() +
-            "4343}";
-        Vector2D expected = new Cartesian2D(-1.2323, -1.4343);
-        Vector2D actual = vector2DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseZeroX() throws MathParseException {
-        String source =
-            "{0" + getDecimalCharacter() +
-            "0; -1" + getDecimalCharacter() +
-            "4343}";
-        Vector2D expected = new Cartesian2D(0.0, -1.4343);
-        Vector2D actual = vector2DFormat.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNonDefaultSetting() throws MathParseException {
-        String source =
-            "[1" + getDecimalCharacter() +
-            "2323 : 1" + getDecimalCharacter() +
-            "4343]";
-        Vector2D expected = new Cartesian2D(1.2323, 1.4343);
-        Vector2D actual = vector2DFormatSquare.parse(source);
-        Assert.assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testParseNan() throws MathParseException {
-        String source = "{(NaN); (NaN)}";
-        Vector2D actual = vector2DFormat.parse(source);
-        Assert.assertEquals(Cartesian2D.NaN, actual);
-    }
-
-    @Test
-    public void testParsePositiveInfinity() throws MathParseException {
-        String source = "{(Infinity); (Infinity)}";
-        Vector2D actual = vector2DFormat.parse(source);
-        Assert.assertEquals(Cartesian2D.POSITIVE_INFINITY, actual);
-    }
-
-    @Test
-    public void testParseNegativeInfinity() throws MathParseException {
-        String source = "{(-Infinity); (-Infinity)}";
-        Vector2D actual = vector2DFormat.parse(source);
-        Assert.assertEquals(Cartesian2D.NEGATIVE_INFINITY, actual);
-    }
-
-    @Test
-    public void testConstructorSingleFormat() {
-        NumberFormat nf = NumberFormat.getInstance();
-        Vector2DFormat cf = new Vector2DFormat(nf);
-        Assert.assertNotNull(cf);
-        Assert.assertEquals(nf, cf.getFormat());
-    }
-
-    @Test
-    public void testForgottenPrefix() {
-        ParsePosition pos = new ParsePosition(0);
-        Assert.assertNull(new Vector2DFormat().parse("1; 1}", pos));
-        Assert.assertEquals(0, pos.getErrorIndex());
-    }
-
-    @Test
-    public void testForgottenSeparator() {
-        ParsePosition pos = new ParsePosition(0);
-        Assert.assertNull(new Vector2DFormat().parse("{1 1}", pos));
-        Assert.assertEquals(3, pos.getErrorIndex());
-    }
-
-    @Test
-    public void testForgottenSuffix() {
-        ParsePosition pos = new ParsePosition(0);
-        Assert.assertNull(new Vector2DFormat().parse("{1; 1 ", pos));
-        Assert.assertEquals(5, pos.getErrorIndex());
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2DFormatTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2DFormatTest.java
deleted file mode 100644
index fbb5076..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/Vector2DFormatTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.twod;
-
-import java.util.Locale;
-
-
-public class Vector2DFormatTest extends Vector2DFormatAbstractTest {
-
-    @Override
-    protected char getDecimalCharacter() {
-        return '.';
-    }
-
-    @Override
-    protected Locale getLocale() {
-        return Locale.US;
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
deleted file mode 100644
index edc5596..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.twod.hull;
-
-import java.util.Collection;
-
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.math4.geometry.euclidean.twod.hull.AklToussaintHeuristic;
-import org.apache.commons.math4.geometry.euclidean.twod.hull.ConvexHullGenerator2D;
-import org.apache.commons.math4.geometry.euclidean.twod.hull.MonotoneChain;
-
-/**
- * Test class for AklToussaintHeuristic.
- */
-public class AklToussaintHeuristicTest extends ConvexHullGenerator2DAbstractTest {
-
-    @Override
-    protected ConvexHullGenerator2D createConvexHullGenerator(boolean includeCollinearPoints) {
-        return new MonotoneChain(includeCollinearPoints);
-    }
-
-    @Override
-    protected Collection<Cartesian2D> reducePoints(Collection<Cartesian2D> points) {
-        return AklToussaintHeuristic.reducePoints(points);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java
deleted file mode 100644
index 4bf88e1..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * 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.twod.hull;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.commons.numbers.core.Precision;
-import org.apache.commons.numbers.arrays.LinearCombination;
-import org.apache.commons.rng.UniformRandomProvider;
-import org.apache.commons.rng.simple.RandomSource;
-import org.apache.commons.math4.exception.NullArgumentException;
-import org.apache.commons.math4.geometry.euclidean.twod.Euclidean2D;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.math4.geometry.euclidean.twod.hull.ConvexHull2D;
-import org.apache.commons.math4.geometry.euclidean.twod.hull.ConvexHullGenerator2D;
-import org.apache.commons.math4.geometry.partitioning.Region;
-import org.apache.commons.math4.geometry.partitioning.Region.Location;
-import org.apache.commons.math4.util.FastMath;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Abstract base test class for 2D convex hull generators.
- *
- */
-public abstract class ConvexHullGenerator2DAbstractTest {
-
-    protected ConvexHullGenerator2D generator;
-    protected UniformRandomProvider random;
-
-    protected abstract ConvexHullGenerator2D createConvexHullGenerator(boolean includeCollinearPoints);
-
-    protected Collection<Cartesian2D> reducePoints(Collection<Cartesian2D> points) {
-        // do nothing by default, may be overridden by other tests
-        return points;
-    }
-
-    @Before
-    public void setUp() {
-        // by default, do not include collinear points
-        generator = createConvexHullGenerator(false);
-        random = RandomSource.create(RandomSource.MT, 10);
-    }
-
-    // ------------------------------------------------------------------------------
-
-    @Test(expected = NullArgumentException.class)
-    public void testNullArgument() {
-        generator.generate(null);
-    }
-
-    @Test
-    public void testEmpty() {
-        ConvexHull2D hull = generator.generate(Collections.<Cartesian2D>emptyList());
-        Assert.assertTrue(hull.getVertices().length == 0);
-        Assert.assertTrue(hull.getLineSegments().length == 0);
-    }
-
-    @Test
-    public void testOnePoint() {
-        List<Cartesian2D> points = createRandomPoints(1);
-        ConvexHull2D hull = generator.generate(points);
-        Assert.assertTrue(hull.getVertices().length == 1);
-        Assert.assertTrue(hull.getLineSegments().length == 0);
-    }
-
-    @Test
-    public void testTwoPoints() {
-        List<Cartesian2D> points = createRandomPoints(2);
-        ConvexHull2D hull = generator.generate(points);
-        Assert.assertTrue(hull.getVertices().length == 2);
-        Assert.assertTrue(hull.getLineSegments().length == 1);
-    }
-
-    @Test
-    public void testAllIdentical() {
-        final Collection<Cartesian2D> points = new ArrayList<>();
-        points.add(new Cartesian2D(1, 1));
-        points.add(new Cartesian2D(1, 1));
-        points.add(new Cartesian2D(1, 1));
-        points.add(new Cartesian2D(1, 1));
-
-        final ConvexHull2D hull = generator.generate(points);
-        Assert.assertTrue(hull.getVertices().length == 1);
-    }
-
-    @Test
-    public void testConvexHull() {
-        // execute 100 random variations
-        for (int i = 0; i < 100; i++) {
-            // randomize the size from 4 to 100
-            int size = (int) FastMath.floor(random.nextDouble() * 96.0 + 4.0);
-
-            List<Cartesian2D> points = createRandomPoints(size);
-            ConvexHull2D hull = generator.generate(reducePoints(points));
-            checkConvexHull(points, hull);
-        }
-    }
-
-    @Test
-    public void testCollinearPoints() {
-        final Collection<Cartesian2D> points = new ArrayList<>();
-        points.add(new Cartesian2D(1, 1));
-        points.add(new Cartesian2D(2, 2));
-        points.add(new Cartesian2D(2, 4));
-        points.add(new Cartesian2D(4, 1));
-        points.add(new Cartesian2D(10, 1));
-
-        final ConvexHull2D hull = generator.generate(points);
-        checkConvexHull(points, hull);
-    }
-
-    @Test
-    public void testCollinearPointsReverse() {
-        final Collection<Cartesian2D> points = new ArrayList<>();
-        points.add(new Cartesian2D(1, 1));
-        points.add(new Cartesian2D(2, 2));
-        points.add(new Cartesian2D(2, 4));
-        points.add(new Cartesian2D(10, 1));
-        points.add(new Cartesian2D(4, 1));
-
-        final ConvexHull2D hull = generator.generate(points);
-        checkConvexHull(points, hull);
-    }
-
-    @Test
-    public void testCollinearPointsIncluded() {
-        final Collection<Cartesian2D> points = new ArrayList<>();
-        points.add(new Cartesian2D(1, 1));
-        points.add(new Cartesian2D(2, 2));
-        points.add(new Cartesian2D(2, 4));
-        points.add(new Cartesian2D(4, 1));
-        points.add(new Cartesian2D(10, 1));
-
-        final ConvexHull2D hull = createConvexHullGenerator(true).generate(points);
-        checkConvexHull(points, hull, true);
-    }
-
-    @Test
-    public void testCollinearPointsIncludedReverse() {
-        final Collection<Cartesian2D> points = new ArrayList<>();
-        points.add(new Cartesian2D(1, 1));
-        points.add(new Cartesian2D(2, 2));
-        points.add(new Cartesian2D(2, 4));
-        points.add(new Cartesian2D(10, 1));
-        points.add(new Cartesian2D(4, 1));
-
-        final ConvexHull2D hull = createConvexHullGenerator(true).generate(points);
-        checkConvexHull(points, hull, true);
-    }
-
-    @Test
-    public void testIdenticalPoints() {
-        final Collection<Cartesian2D> points = new ArrayList<>();
-        points.add(new Cartesian2D(1, 1));
-        points.add(new Cartesian2D(2, 2));
-        points.add(new Cartesian2D(2, 4));
-        points.add(new Cartesian2D(4, 1));
-        points.add(new Cartesian2D(1, 1));
-
-        final ConvexHull2D hull = generator.generate(points);
-        checkConvexHull(points, hull);
-    }
-
-    @Test
-    public void testIdenticalPoints2() {
-        final Collection<Cartesian2D> points = new ArrayList<>();
-        points.add(new Cartesian2D(1, 1));
-        points.add(new Cartesian2D(2, 2));
-        points.add(new Cartesian2D(2, 4));
-        points.add(new Cartesian2D(4, 1));
-        points.add(new Cartesian2D(1, 1));
-
-        final ConvexHull2D hull = createConvexHullGenerator(true).generate(points);
-        checkConvexHull(points, hull, true);
-    }
-
-    @Test
-    public void testClosePoints() {
-        final Collection<Cartesian2D> points = new ArrayList<>();
-        points.add(new Cartesian2D(1, 1));
-        points.add(new Cartesian2D(2, 2));
-        points.add(new Cartesian2D(2, 4));
-        points.add(new Cartesian2D(4, 1));
-        points.add(new Cartesian2D(1.00001, 1));
-
-        final ConvexHull2D hull = generator.generate(points);
-        checkConvexHull(points, hull);
-    }
-
-    @Test
-    public void testCollinearPointOnExistingBoundary() {
-        // MATH-1135: check that collinear points on the hull are handled correctly
-        //            when only a minimal hull shall be constructed
-        final Collection<Cartesian2D> points = new ArrayList<>();
-        points.add(new Cartesian2D(7.3152, 34.7472));
-        points.add(new Cartesian2D(6.400799999999997, 34.747199999999985));
-        points.add(new Cartesian2D(5.486399999999997, 34.7472));
-        points.add(new Cartesian2D(4.876799999999999, 34.7472));
-        points.add(new Cartesian2D(4.876799999999999, 34.1376));
-        points.add(new Cartesian2D(4.876799999999999, 30.48));
-        points.add(new Cartesian2D(6.0959999999999965, 30.48));
-        points.add(new Cartesian2D(6.0959999999999965, 34.1376));
-        points.add(new Cartesian2D(7.315199999999996, 34.1376));
-        points.add(new Cartesian2D(7.3152, 30.48));
-
-        final ConvexHull2D hull = createConvexHullGenerator(false).generate(points);
-        checkConvexHull(points, hull);
-    }
-
-    @Test
-    public void testCollinearPointsInAnyOrder() {
-        // MATH-1148: collinear points on the hull might be in any order
-        //            make sure that they are processed in the proper order
-        //            for each algorithm.
-
-        List<Cartesian2D> points = new ArrayList<>();
-
-        // first case: 3 points are collinear
-        points.add(new Cartesian2D(16.078200000000184, -36.52519999989808));
-        points.add(new Cartesian2D(19.164300000000186, -36.52519999989808));
-        points.add(new Cartesian2D(19.1643, -25.28136477910407));
-        points.add(new Cartesian2D(19.1643, -17.678400000004157));
-
-        ConvexHull2D hull = createConvexHullGenerator(false).generate(points);
-        checkConvexHull(points, hull);
-
-        hull = createConvexHullGenerator(true).generate(points);
-        checkConvexHull(points, hull, true);
-
-        points.clear();
-
-        // second case: multiple points are collinear
-        points.add(new Cartesian2D(0, -29.959696875));
-        points.add(new Cartesian2D(0, -31.621809375));
-        points.add(new Cartesian2D(0, -28.435696875));
-        points.add(new Cartesian2D(0, -33.145809375));
-        points.add(new Cartesian2D(3.048, -33.145809375));
-        points.add(new Cartesian2D(3.048, -31.621809375));
-        points.add(new Cartesian2D(3.048, -29.959696875));
-        points.add(new Cartesian2D(4.572, -33.145809375));
-        points.add(new Cartesian2D(4.572, -28.435696875));
-
-        hull = createConvexHullGenerator(false).generate(points);
-        checkConvexHull(points, hull);
-
-        hull = createConvexHullGenerator(true).generate(points);
-        checkConvexHull(points, hull, true);
-    }
-
-    @Test
-    public void testIssue1123() {
-
-        List<Cartesian2D> points = new ArrayList<>();
-
-        int[][] data = new int[][] { { -11, -1 }, { -11, 0 }, { -11, 1 },
-                { -10, -3 }, { -10, -2 }, { -10, -1 }, { -10, 0 }, { -10, 1 },
-                { -10, 2 }, { -10, 3 }, { -9, -4 }, { -9, -3 }, { -9, -2 },
-                { -9, -1 }, { -9, 0 }, { -9, 1 }, { -9, 2 }, { -9, 3 },
-                { -9, 4 }, { -8, -5 }, { -8, -4 }, { -8, -3 }, { -8, -2 },
-                { -8, -1 }, { -8, 0 }, { -8, 1 }, { -8, 2 }, { -8, 3 },
-                { -8, 4 }, { -8, 5 }, { -7, -6 }, { -7, -5 }, { -7, -4 },
-                { -7, -3 }, { -7, -2 }, { -7, -1 }, { -7, 0 }, { -7, 1 },
-                { -7, 2 }, { -7, 3 }, { -7, 4 }, { -7, 5 }, { -7, 6 },
-                { -6, -7 }, { -6, -6 }, { -6, -5 }, { -6, -4 }, { -6, -3 },
-                { -6, -2 }, { -6, -1 }, { -6, 0 }, { -6, 1 }, { -6, 2 },
-                { -6, 3 }, { -6, 4 }, { -6, 5 }, { -6, 6 }, { -6, 7 },
-                { -5, -7 }, { -5, -6 }, { -5, -5 }, { -5, -4 }, { -5, -3 },
-                { -5, -2 }, { -5, 4 }, { -5, 5 }, { -5, 6 }, { -5, 7 },
-                { -4, -7 }, { -4, -6 }, { -4, -5 }, { -4, -4 }, { -4, -3 },
-                { -4, -2 }, { -4, 4 }, { -4, 5 }, { -4, 6 }, { -4, 7 },
-                { -3, -8 }, { -3, -7 }, { -3, -6 }, { -3, -5 }, { -3, -4 },
-                { -3, -3 }, { -3, -2 }, { -3, 4 }, { -3, 5 }, { -3, 6 },
-                { -3, 7 }, { -3, 8 }, { -2, -8 }, { -2, -7 }, { -2, -6 },
-                { -2, -5 }, { -2, -4 }, { -2, -3 }, { -2, -2 }, { -2, 4 },
-                { -2, 5 }, { -2, 6 }, { -2, 7 }, { -2, 8 }, { -1, -8 },
-                { -1, -7 }, { -1, -6 }, { -1, -5 }, { -1, -4 }, { -1, -3 },
-                { -1, -2 }, { -1, 4 }, { -1, 5 }, { -1, 6 }, { -1, 7 },
-                { -1, 8 }, { 0, -8 }, { 0, -7 }, { 0, -6 }, { 0, -5 },
-                { 0, -4 }, { 0, -3 }, { 0, -2 }, { 0, 4 }, { 0, 5 }, { 0, 6 },
-                { 0, 7 }, { 0, 8 }, { 1, -8 }, { 1, -7 }, { 1, -6 }, { 1, -5 },
-                { 1, -4 }, { 1, -3 }, { 1, -2 }, { 1, -1 }, { 1, 0 }, { 1, 1 },
-                { 1, 2 }, { 1, 3 }, { 1, 4 }, { 1, 5 }, { 1, 6 }, { 1, 7 },
-                { 1, 8 }, { 2, -8 }, { 2, -7 }, { 2, -6 }, { 2, -5 },
-                { 2, -4 }, { 2, -3 }, { 2, -2 }, { 2, -1 }, { 2, 0 }, { 2, 1 },
-                { 2, 2 }, { 2, 3 }, { 2, 4 }, { 2, 5 }, { 2, 6 }, { 2, 7 },
-                { 2, 8 }, { 3, -8 }, { 3, -7 }, { 3, -6 }, { 3, -5 },
-                { 3, -4 }, { 3, -3 }, { 3, -2 }, { 3, -1 }, { 3, 0 }, { 3, 1 },
-                { 3, 2 }, { 3, 3 }, { 3, 4 }, { 3, 5 }, { 3, 6 }, { 3, 7 },
-                { 3, 8 }, { 4, -7 }, { 4, -6 }, { 4, -5 }, { 4, -4 },
-                { 4, -3 }, { 4, -2 }, { 4, -1 }, { 4, 0 }, { 4, 1 }, { 4, 2 },
-                { 4, 3 }, { 4, 4 }, { 4, 5 }, { 4, 6 }, { 4, 7 }, { 5, -7 },
-                { 5, -6 }, { 5, -5 }, { 5, -4 }, { 5, -3 }, { 5, -2 },
-                { 5, -1 }, { 5, 0 }, { 5, 1 }, { 5, 2 }, { 5, 3 }, { 5, 4 },
-                { 5, 5 }, { 5, 6 }, { 5, 7 }, { 6, -7 }, { 6, -6 }, { 6, -5 },
-                { 6, -4 }, { 6, -3 }, { 6, -2 }, { 6, -1 }, { 6, 0 }, { 6, 1 },
-                { 6, 2 }, { 6, 3 }, { 6, 4 }, { 6, 5 }, { 6, 6 }, { 6, 7 },
-                { 7, -6 }, { 7, -5 }, { 7, -4 }, { 7, -3 }, { 7, -2 },
-                { 7, -1 }, { 7, 0 }, { 7, 1 }, { 7, 2 }, { 7, 3 }, { 7, 4 },
-                { 7, 5 }, { 7, 6 }, { 8, -5 }, { 8, -4 }, { 8, -3 }, { 8, -2 },
-                { 8, -1 }, { 8, 0 }, { 8, 1 }, { 8, 2 }, { 8, 3 }, { 8, 4 },
-                { 8, 5 }, { 9, -4 }, { 9, -3 }, { 9, -2 }, { 9, -1 }, { 9, 0 },
-                { 9, 1 }, { 9, 2 }, { 9, 3 }, { 9, 4 }, { 10, -3 }, { 10, -2 },
-                { 10, -1 }, { 10, 0 }, { 10, 1 }, { 10, 2 }, { 10, 3 },
-                { 11, -1 }, { 11, 0 }, { 11, 1 } };
-
-        for (int[] line : data) {
-            points.add(new Cartesian2D(line[0], line[1]));
-        }
-
-        Cartesian2D[] referenceHull = new Cartesian2D[] {
-            new Cartesian2D(-11.0, -1.0),
-            new Cartesian2D(-10.0, -3.0),
-            new Cartesian2D( -6.0, -7.0),
-            new Cartesian2D( -3.0, -8.0),
-            new Cartesian2D(  3.0, -8.0),
-            new Cartesian2D(  6.0, -7.0),
-            new Cartesian2D( 10.0, -3.0),
-            new Cartesian2D( 11.0, -1.0),
-            new Cartesian2D( 11.0,  1.0),
-            new Cartesian2D( 10.0,  3.0),
-            new Cartesian2D(  6.0,  7.0),
-            new Cartesian2D(  3.0,  8.0),
-            new Cartesian2D( -3.0,  8.0),
-            new Cartesian2D( -6.0,  7.0),
-            new Cartesian2D(-10.0,  3.0),
-            new Cartesian2D(-11.0,  1.0),
-        };
-
-        ConvexHull2D convHull = generator.generate(points);
-        Region<Euclidean2D> hullRegion = convHull.createRegion();
-
-        Assert.assertEquals(274.0, hullRegion.getSize(), 1.0e-12);
-        double perimeter = 0;
-        for (int i = 0; i < referenceHull.length; ++i) {
-            perimeter += Cartesian2D.distance(referenceHull[i],
-                                           referenceHull[(i + 1) % referenceHull.length]);
-        }
-        Assert.assertEquals(perimeter, hullRegion.getBoundarySize(), 1.0e-12);
-
-        for (int i = 0; i < referenceHull.length; ++i) {
-            Assert.assertEquals(Location.BOUNDARY, hullRegion.checkPoint(referenceHull[i]));
-        }
-
-    }
-
-    // ------------------------------------------------------------------------------
-
-    protected final List<Cartesian2D> createRandomPoints(int size) {
-        // create the cloud container
-        List<Cartesian2D> points = new ArrayList<>(size);
-        // fill the cloud with a random distribution of points
-        for (int i = 0; i < size; i++) {
-            points.add(new Cartesian2D(random.nextDouble() * 2.0 - 1.0, random.nextDouble() * 2.0 - 1.0));
-        }
-        return points;
-    }
-
-    protected final void checkConvexHull(final Collection<Cartesian2D> points, final ConvexHull2D hull) {
-        checkConvexHull(points, hull, false);
-    }
-
-    protected final void checkConvexHull(final Collection<Cartesian2D> points, final ConvexHull2D hull,
-                                         final boolean includesCollinearPoints) {
-        checkConvexHull(points, hull, includesCollinearPoints, 1e-10);
-    }
-
-    protected final void checkConvexHull(final Collection<Cartesian2D> points, final ConvexHull2D hull,
-                                         final boolean includesCollinearPoints, final double tolerance) {
-        Assert.assertNotNull(hull);
-        Assert.assertTrue(isConvex(hull, includesCollinearPoints, tolerance));
-        checkPointsInsideHullRegion(points, hull, includesCollinearPoints);
-    }
-
-    // verify that the constructed hull is really convex
-    protected final boolean isConvex(final ConvexHull2D hull, final boolean includesCollinearPoints,
-                                     final double tolerance) {
-
-        final Cartesian2D[] points = hull.getVertices();
-        int sign = 0;
-
-        for (int i = 0; i < points.length; i++) {
-            Cartesian2D p1 = points[i == 0 ? points.length - 1 : i - 1];
-            Cartesian2D p2 = points[i];
-            Cartesian2D p3 = points[i == points.length - 1 ? 0 : i + 1];
-
-            Cartesian2D d1 = p2.subtract(p1);
-            Cartesian2D d2 = p3.subtract(p2);
-
-            Assert.assertTrue(d1.getNorm() > 1e-10);
-            Assert.assertTrue(d2.getNorm() > 1e-10);
-
-            final double cross = LinearCombination.value(d1.getX(), d2.getY(), -d1.getY(), d2.getX());
-            final int cmp = Precision.compareTo(cross, 0.0, tolerance);
-
-            if (sign != 0 && cmp != sign) {
-                if (includesCollinearPoints && cmp == 0) {
-                    // in case of collinear points the cross product will be zero
-                } else {
-                    return false;
-                }
-            }
-
-            sign = cmp;
-        }
-
-        return true;
-    }
-
-    // verify that all points are inside the convex hull region
-    protected final void checkPointsInsideHullRegion(final Collection<Cartesian2D> points,
-                                                     final ConvexHull2D hull,
-                                                     final boolean includesCollinearPoints) {
-
-        final Collection<Cartesian2D> hullVertices = Arrays.asList(hull.getVertices());
-        final Region<Euclidean2D> region = hull.createRegion();
-
-        for (final Cartesian2D p : points) {
-            Location location = region.checkPoint(p);
-            Assert.assertTrue(location != Location.OUTSIDE);
-
-            if (location == Location.BOUNDARY && includesCollinearPoints) {
-                Assert.assertTrue(hullVertices.contains(p));
-            }
-        }
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/hull/MonotoneChainTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/hull/MonotoneChainTest.java
deleted file mode 100644
index 8ce3979..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/twod/hull/MonotoneChainTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.twod.hull;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-import org.apache.commons.math4.exception.ConvergenceException;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
-import org.apache.commons.math4.geometry.euclidean.twod.hull.ConvexHull2D;
-import org.apache.commons.math4.geometry.euclidean.twod.hull.ConvexHullGenerator2D;
-import org.apache.commons.math4.geometry.euclidean.twod.hull.MonotoneChain;
-import org.junit.Test;
-
-/**
- * Test class for MonotoneChain.
- */
-public class MonotoneChainTest extends ConvexHullGenerator2DAbstractTest {
-
-    @Override
-    protected ConvexHullGenerator2D createConvexHullGenerator(boolean includeCollinearPoints) {
-        return new MonotoneChain(includeCollinearPoints);
-    }
-
-    // ------------------------------------------------------------------------------
-
-    @Test(expected=ConvergenceException.class)
-    public void testConvergenceException() {
-        final Collection<Cartesian2D> points = new ArrayList<>();
-
-        points.add(new Cartesian2D(1, 1));
-        points.add(new Cartesian2D(1, 5));
-        points.add(new Cartesian2D(0, 7));
-        points.add(new Cartesian2D(1, 10));
-        points.add(new Cartesian2D(1, 20));
-        points.add(new Cartesian2D(20, 20));
-        points.add(new Cartesian2D(20, 40));
-        points.add(new Cartesian2D(40, 1));
-
-        @SuppressWarnings("unused")
-        final ConvexHull2D hull = new MonotoneChain(true, 2).generate(points);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/partitioning/CharacterizationTest.java b/src/test/java/org/apache/commons/math4/geometry/partitioning/CharacterizationTest.java
deleted file mode 100644
index 5fafe0f..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/partitioning/CharacterizationTest.java
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * 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.partitioning;
-
-import java.util.Iterator;
-
-import org.apache.commons.math4.geometry.euclidean.oned.IntervalsSet;
-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.junit.Assert;
-import org.junit.Test;
-
-public class CharacterizationTest {
-
-    private static final double TEST_TOLERANCE = 1e-10;
-
-    @Test
-    public void testCharacterize_insideLeaf() {
-        // arrange
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.TRUE);
-        SubLine sub = buildSubLine(new Cartesian2D(0, -1), new Cartesian2D(0, 1));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(true, ch.touchInside());
-        Assert.assertSame(sub, ch.insideTouching());
-        Assert.assertEquals(0, size(ch.getInsideSplitters()));
-
-        Assert.assertEquals(false, ch.touchOutside());
-        Assert.assertEquals(null,  ch.outsideTouching());
-        Assert.assertEquals(0, size(ch.getOutsideSplitters()));
-    }
-
-    @Test
-    public void testCharacterize_outsideLeaf() {
-        // arrange
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.FALSE);
-        SubLine sub = buildSubLine(new Cartesian2D(0, -1), new Cartesian2D(0, 1));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(false, ch.touchInside());
-        Assert.assertSame(null, ch.insideTouching());
-        Assert.assertEquals(0, size(ch.getInsideSplitters()));
-
-        Assert.assertEquals(true, ch.touchOutside());
-        Assert.assertEquals(sub,  ch.outsideTouching());
-        Assert.assertEquals(0, size(ch.getOutsideSplitters()));
-    }
-
-    @Test
-    public void testCharacterize_onPlusSide() {
-        // arrange
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Cartesian2D(0, 0), new Cartesian2D(1, 0)));
-
-        SubLine sub = buildSubLine(new Cartesian2D(0, -1), new Cartesian2D(0, -2));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(false, ch.touchInside());
-        Assert.assertSame(null, ch.insideTouching());
-        Assert.assertEquals(0, size(ch.getInsideSplitters()));
-
-        Assert.assertEquals(true, ch.touchOutside());
-        Assert.assertEquals(sub,  ch.outsideTouching());
-        Assert.assertEquals(0, size(ch.getOutsideSplitters()));
-    }
-
-    @Test
-    public void testCharacterize_onMinusSide() {
-        // arrange
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Cartesian2D(0, 0), new Cartesian2D(1, 0)));
-
-        SubLine sub = buildSubLine(new Cartesian2D(0, 1), new Cartesian2D(0, 2));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(true, ch.touchInside());
-        Assert.assertSame(sub, ch.insideTouching());
-        Assert.assertEquals(0, size(ch.getInsideSplitters()));
-
-        Assert.assertEquals(false, ch.touchOutside());
-        Assert.assertEquals(null,  ch.outsideTouching());
-        Assert.assertEquals(0, size(ch.getOutsideSplitters()));
-    }
-
-    @Test
-    public void testCharacterize_onBothSides() {
-        // arrange
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Cartesian2D(0, 0), new Cartesian2D(1, 0)));
-
-        SubLine sub = buildSubLine(new Cartesian2D(0, -1), new Cartesian2D(0, 1));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(true, ch.touchInside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine inside = (SubLine) ch.insideTouching();
-        Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(0, 0), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(0, 1), inside.getSegments().get(0).getEnd());
-
-        Assert.assertEquals(1, size(ch.getInsideSplitters()));
-        Iterator<BSPTree<Euclidean2D>> insideSplitterIter = ch.getInsideSplitters().iterator();
-        Assert.assertSame(tree, insideSplitterIter.next());
-
-        Assert.assertEquals(true, ch.touchOutside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine outside = (SubLine) ch.outsideTouching();
-        Assert.assertEquals(1, outside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(0, -1), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(0, 0), outside.getSegments().get(0).getEnd());
-
-        Assert.assertEquals(1, size(ch.getOutsideSplitters()));
-        Iterator<BSPTree<Euclidean2D>> outsideSplitterIter = ch.getOutsideSplitters().iterator();
-        Assert.assertSame(tree, outsideSplitterIter.next());
-    }
-
-    @Test
-    public void testCharacterize_multipleSplits_reunitedOnPlusSide() {
-        // arrange
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Cartesian2D(0, 0), new Cartesian2D(1, 0)));
-        cut(tree.getMinus(), buildLine(new Cartesian2D(-1, 0), new Cartesian2D(0, 1)));
-
-        SubLine sub = buildSubLine(new Cartesian2D(0, -2), new Cartesian2D(0, 2));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(true, ch.touchInside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine inside = (SubLine) ch.insideTouching();
-        Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(0, 1), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(0, 2), inside.getSegments().get(0).getEnd());
-
-        Assert.assertEquals(2, size(ch.getInsideSplitters()));
-        Iterator<BSPTree<Euclidean2D>> insideSplitterIter = ch.getInsideSplitters().iterator();
-        Assert.assertSame(tree, insideSplitterIter.next());
-        Assert.assertSame(tree.getMinus(), insideSplitterIter.next());
-
-        Assert.assertEquals(true, ch.touchOutside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine outside = (SubLine) ch.outsideTouching();
-        Assert.assertEquals(1, outside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(0, -2), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(0, 1), outside.getSegments().get(0).getEnd());
-
-        Assert.assertEquals(2, size(ch.getOutsideSplitters()));
-        Iterator<BSPTree<Euclidean2D>> outsideSplitterIter = ch.getOutsideSplitters().iterator();
-        Assert.assertSame(tree, outsideSplitterIter.next());
-        Assert.assertSame(tree.getMinus(), outsideSplitterIter.next());
-    }
-
-    @Test
-    public void testCharacterize_multipleSplits_reunitedOnMinusSide() {
-        // arrange
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Cartesian2D(0, 0), new Cartesian2D(1, 0)));
-        cut(tree.getMinus(), buildLine(new Cartesian2D(-1, 0), new Cartesian2D(0, 1)));
-        cut(tree.getMinus().getPlus(), buildLine(new Cartesian2D(-0.5, 0.5), new Cartesian2D(0, 0)));
-
-        SubLine sub = buildSubLine(new Cartesian2D(0, -2), new Cartesian2D(0, 2));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(true, ch.touchInside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine inside = (SubLine) ch.insideTouching();
-        Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(0, 0), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(0, 2), inside.getSegments().get(0).getEnd());
-
-        Assert.assertEquals(2, size(ch.getInsideSplitters()));
-        Iterator<BSPTree<Euclidean2D>> insideSplitterIter = ch.getInsideSplitters().iterator();
-        Assert.assertSame(tree, insideSplitterIter.next());
-        Assert.assertSame(tree.getMinus(), insideSplitterIter.next());
-
-        Assert.assertEquals(true, ch.touchOutside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine outside = (SubLine) ch.outsideTouching();
-        Assert.assertEquals(1, outside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(0, -2), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(0, 0), outside.getSegments().get(0).getEnd());
-
-        Assert.assertEquals(1, size(ch.getOutsideSplitters()));
-        Iterator<BSPTree<Euclidean2D>> outsideSplitterIter = ch.getOutsideSplitters().iterator();
-        Assert.assertSame(tree, outsideSplitterIter.next());
-    }
-
-    @Test
-    public void testCharacterize_onHyperplane_sameOrientation() {
-        // arrange
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Cartesian2D(0, 0), new Cartesian2D(1, 0)));
-
-        SubLine sub = buildSubLine(new Cartesian2D(0, 0), new Cartesian2D(1, 0));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(true, ch.touchInside());
-        Assert.assertSame(sub, ch.insideTouching());
-        Assert.assertEquals(0, size(ch.getInsideSplitters()));
-
-        Assert.assertEquals(false, ch.touchOutside());
-        Assert.assertEquals(null,  ch.outsideTouching());
-        Assert.assertEquals(0, size(ch.getOutsideSplitters()));
-    }
-
-    @Test
-    public void testCharacterize_onHyperplane_oppositeOrientation() {
-        // arrange
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Cartesian2D(0, 0), new Cartesian2D(1, 0)));
-
-        SubLine sub = buildSubLine(new Cartesian2D(1, 0), new Cartesian2D(0, 0));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(true, ch.touchInside());
-        Assert.assertSame(sub, ch.insideTouching());
-        Assert.assertEquals(0, size(ch.getInsideSplitters()));
-
-        Assert.assertEquals(false, ch.touchOutside());
-        Assert.assertEquals(null,  ch.outsideTouching());
-        Assert.assertEquals(0, size(ch.getOutsideSplitters()));
-    }
-
-    @Test
-    public void testCharacterize_onHyperplane_multipleSplits_sameOrientation() {
-        // arrange
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Cartesian2D(0, 0), new Cartesian2D(1, 0)));
-        cut(tree.getMinus(), buildLine(new Cartesian2D(-1, 0), new Cartesian2D(0, 1)));
-
-        SubLine sub = buildSubLine(new Cartesian2D(-2, 0), new Cartesian2D(2, 0));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(true, ch.touchInside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine inside = (SubLine) ch.insideTouching();
-        Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(-2, 0), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(-1, 0), inside.getSegments().get(0).getEnd());
-
-        Assert.assertEquals(1, size(ch.getInsideSplitters()));
-        Iterator<BSPTree<Euclidean2D>> insideSplitterIter = ch.getInsideSplitters().iterator();
-        Assert.assertSame(tree.getMinus(), insideSplitterIter.next());
-
-        Assert.assertEquals(true, ch.touchOutside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine outside = (SubLine) ch.outsideTouching();
-        Assert.assertEquals(1, outside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(-1, 0), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(2, 0), outside.getSegments().get(0).getEnd());
-
-        Assert.assertEquals(1, size(ch.getOutsideSplitters()));
-        Iterator<BSPTree<Euclidean2D>> outsideSplitterIter = ch.getOutsideSplitters().iterator();
-        Assert.assertSame(tree.getMinus(), outsideSplitterIter.next());
-    }
-
-    @Test
-    public void testCharacterize_onHyperplane_multipleSplits_oppositeOrientation() {
-        // arrange
-        BSPTree<Euclidean2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Cartesian2D(0, 0), new Cartesian2D(1, 0)));
-        cut(tree.getMinus(), buildLine(new Cartesian2D(-1, 0), new Cartesian2D(0, 1)));
-
-        SubLine sub = buildSubLine(new Cartesian2D(2, 0), new Cartesian2D(-2, 0));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(true, ch.touchInside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine inside = (SubLine) ch.insideTouching();
-        Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(-1, 0), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(-2, 0), inside.getSegments().get(0).getEnd());
-
-        Assert.assertEquals(1, size(ch.getInsideSplitters()));
-        Iterator<BSPTree<Euclidean2D>> insideSplitterIter = ch.getInsideSplitters().iterator();
-        Assert.assertSame(tree.getMinus(), insideSplitterIter.next());
-
-        Assert.assertEquals(true, ch.touchOutside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine outside = (SubLine) ch.outsideTouching();
-        Assert.assertEquals(1, outside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(2, 0), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(-1, 0), outside.getSegments().get(0).getEnd());
-
-        Assert.assertEquals(1, size(ch.getOutsideSplitters()));
-        Iterator<BSPTree<Euclidean2D>> outsideSplitterIter = ch.getOutsideSplitters().iterator();
-        Assert.assertSame(tree.getMinus(), outsideSplitterIter.next());
-    }
-
-    @Test
-    public void testCharacterize_onHyperplane_box() {
-        // arrange
-        PolygonsSet poly = new PolygonsSet(0, 1, 0, 1, TEST_TOLERANCE);
-        BSPTree<Euclidean2D> tree = poly.getTree(false);
-
-        SubLine sub = buildSubLine(new Cartesian2D(2, 0), new Cartesian2D(-2, 0));
-
-        // act
-        Characterization<Euclidean2D> ch = new Characterization<>(tree, sub);
-
-        // assert
-        Assert.assertEquals(true, ch.touchInside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine inside = (SubLine) ch.insideTouching();
-        Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(1, 0), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(0, 0), inside.getSegments().get(0).getEnd());
-
-        Assert.assertEquals(2, size(ch.getInsideSplitters()));
-
-        Assert.assertEquals(true, ch.touchOutside());
-        Assert.assertNotSame(sub, ch.insideTouching());
-
-        SubLine outside = (SubLine) ch.outsideTouching();
-        Assert.assertEquals(2, outside.getSegments().size());
-        assertVectorEquals(new Cartesian2D(2, 0), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Cartesian2D(1, 0), outside.getSegments().get(0).getEnd());
-        assertVectorEquals(new Cartesian2D(0, 0), outside.getSegments().get(1).getStart());
-        assertVectorEquals(new Cartesian2D(-2, 0), outside.getSegments().get(1).getEnd());
-
-        Assert.assertEquals(2, size(ch.getOutsideSplitters()));
-    }
-
-    private void cut(BSPTree<Euclidean2D> tree, Line line) {
-        if (tree.insertCut(line)) {
-            tree.setAttribute(null);
-            tree.getPlus().setAttribute(Boolean.FALSE);
-            tree.getMinus().setAttribute(Boolean.TRUE);
-        }
-    }
-
-    private int size(NodesSet<Euclidean2D> nodes) {
-        Iterator<BSPTree<Euclidean2D>> it = nodes.iterator();
-
-        int size = 0;
-        while (it.hasNext()) {
-            it.next();
-            ++size;
-        }
-
-        return size;
-    }
-
-    private Line buildLine(Cartesian2D p1, Cartesian2D p2) {
-        return new Line(p1, p2, TEST_TOLERANCE);
-    }
-
-    private SubLine buildSubLine(Cartesian2D start, Cartesian2D end) {
-        Line line = new Line(start, end, TEST_TOLERANCE);
-        double lower = (line.toSubSpace(start)).getX();
-        double upper = (line.toSubSpace(end)).getX();
-        return new SubLine(line, new IntervalsSet(lower, upper, TEST_TOLERANCE));
-    }
-
-    private void assertVectorEquals(Cartesian2D expected, Cartesian2D actual) {
-        String msg = "Expected vector to equal " + expected + " but was " + actual + ";";
-        Assert.assertEquals(msg, expected.getX(), actual.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(msg, expected.getY(), actual.getY(), TEST_TOLERANCE);
-    }
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/partitioning/RegionDumper.java b/src/test/java/org/apache/commons/math4/geometry/partitioning/RegionDumper.java
deleted file mode 100644
index 0107e22..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/partitioning/RegionDumper.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * 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.partitioning;
-
-import java.util.Formatter;
-import java.util.Locale;
-
-import org.apache.commons.math4.geometry.Space;
-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.Cartesian1D;
-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.Cartesian3D;
-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.Cartesian2D;
-import org.apache.commons.math4.geometry.spherical.oned.ArcsSet;
-import org.apache.commons.math4.geometry.spherical.oned.LimitAngle;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.apache.commons.math4.geometry.spherical.twod.Circle;
-import org.apache.commons.math4.geometry.spherical.twod.Sphere2D;
-import org.apache.commons.math4.geometry.spherical.twod.SphericalPolygonsSet;
-
-/** Class dumping a string representation of an {@link AbstractRegion}.
- * <p>
- * This class is intended for tests and debug purposes only.
- * </p>
- * @see RegionParser
- * @since 3.5
- */
-public class RegionDumper {
-
-    /** Private constructor for a utility class
-     */
-    private RegionDumper() {
-    }
-
-    /** Get a string representation of an {@link ArcsSet}.
-     * @param arcsSet region to dump
-     * @return string representation of the region
-     */
-    public static String dump(final ArcsSet arcsSet) {
-        final TreeDumper<Sphere1D> visitor = new TreeDumper<Sphere1D>("ArcsSet", arcsSet.getTolerance()) {
-
-            /** {@inheritDoc} */
-            @Override
-            protected void formatHyperplane(final Hyperplane<Sphere1D> hyperplane) {
-                final LimitAngle h = (LimitAngle) hyperplane;
-                getFormatter().format("%22.15e %b %22.15e",
-                                      h.getLocation().getAlpha(), h.isDirect(), h.getTolerance());
-            }
-
-        };
-        arcsSet.getTree(false).visit(visitor);
-        return visitor.getDump();
-    }
-
-    /** Get a string representation of a {@link SphericalPolygonsSet}.
-     * @param sphericalPolygonsSet region to dump
-     * @return string representation of the region
-     */
-    public static String dump(final SphericalPolygonsSet sphericalPolygonsSet) {
-        final TreeDumper<Sphere2D> visitor = new TreeDumper<Sphere2D>("SphericalPolygonsSet", sphericalPolygonsSet.getTolerance()) {
-
-            /** {@inheritDoc} */
-            @Override
-            protected void formatHyperplane(final Hyperplane<Sphere2D> hyperplane) {
-                final Circle h = (Circle) hyperplane;
-                getFormatter().format("%22.15e %22.15e %22.15e %22.15e",
-                                      h.getPole().getX(), h.getPole().getY(), h.getPole().getZ(),
-                                      h.getTolerance());
-            }
-
-        };
-        sphericalPolygonsSet.getTree(false).visit(visitor);
-        return visitor.getDump();
-    }
-
-    /** Get a string representation of an {@link IntervalsSet}.
-     * @param intervalsSet region to dump
-     * @return string representation of the region
-     */
-    public static String dump(final IntervalsSet intervalsSet) {
-        final TreeDumper<Euclidean1D> visitor = new TreeDumper<Euclidean1D>("IntervalsSet", intervalsSet.getTolerance()) {
-
-            /** {@inheritDoc} */
-            @Override
-            protected void formatHyperplane(final Hyperplane<Euclidean1D> hyperplane) {
-                final OrientedPoint h = (OrientedPoint) hyperplane;
-                getFormatter().format("%22.15e %b %22.15e",
-                                      h.getLocation().getX(), h.isDirect(), h.getTolerance());
-            }
-
-        };
-        intervalsSet.getTree(false).visit(visitor);
-        return visitor.getDump();
-    }
-
-    /** Get a string representation of a {@link PolygonsSet}.
-     * @param polygonsSet region to dump
-     * @return string representation of the region
-     */
-    public static String dump(final PolygonsSet polygonsSet) {
-        final TreeDumper<Euclidean2D> visitor = new TreeDumper<Euclidean2D>("PolygonsSet", polygonsSet.getTolerance()) {
-
-            /** {@inheritDoc} */
-            @Override
-            protected void formatHyperplane(final Hyperplane<Euclidean2D> hyperplane) {
-                final Line h = (Line) hyperplane;
-                final Cartesian2D p = h.toSpace(Cartesian1D.ZERO);
-                getFormatter().format("%22.15e %22.15e %22.15e %22.15e",
-                                      p.getX(), p.getY(), h.getAngle(), h.getTolerance());
-            }
-
-        };
-        polygonsSet.getTree(false).visit(visitor);
-        return visitor.getDump();
-    }
-
-    /** Get a string representation of a {@link PolyhedronsSet}.
-     * @param polyhedronsSet region to dump
-     * @return string representation of the region
-     */
-    public static String dump(final PolyhedronsSet polyhedronsSet) {
-        final TreeDumper<Euclidean3D> visitor = new TreeDumper<Euclidean3D>("PolyhedronsSet", polyhedronsSet.getTolerance()) {
-
-            /** {@inheritDoc} */
-            @Override
-            protected void formatHyperplane(final Hyperplane<Euclidean3D> hyperplane) {
-                final Plane h = (Plane) hyperplane;
-                final Cartesian3D p = h.toSpace(Cartesian2D.ZERO);
-                getFormatter().format("%22.15e %22.15e %22.15e %22.15e %22.15e %22.15e %22.15e",
-                                      p.getX(), p.getY(), p.getZ(),
-                                      h.getNormal().getX(), h.getNormal().getY(), h.getNormal().getZ(),
-                                      h.getTolerance());
-            }
-
-        };
-        polyhedronsSet.getTree(false).visit(visitor);
-        return visitor.getDump();
-    }
-
-    /** Dumping visitor.
-     * @param <S> Type of the space.
-     */
-    private abstract static class TreeDumper<S extends Space> implements BSPTreeVisitor<S> {
-
-        /** Builder for the string representation of the dumped tree. */
-        private final StringBuilder dump;
-
-        /** Formatter for strings. */
-        private final Formatter formatter;
-
-        /** Current indentation prefix. */
-        private String prefix;
-
-        /** Simple constructor.
-         * @param type type of the region to dump
-         * @param tolerance tolerance of the region
-         */
-        public TreeDumper(final String type, final double tolerance) {
-            this.dump      = new StringBuilder();
-            this.formatter = new Formatter(dump, Locale.US);
-            this.prefix    = "";
-            formatter.format("%s%n", type);
-            formatter.format("tolerance %22.15e%n", tolerance);
-        }
-
-        /** Get the string representation of the tree.
-         * @return string representation of the tree.
-         */
-        public String getDump() {
-            return dump.toString();
-        }
-
-        /** Get the formatter to use.
-         * @return formatter to use
-         */
-        protected Formatter getFormatter() {
-            return formatter;
-        }
-
-        /** Format a string representation of the hyperplane underlying a cut sub-hyperplane.
-         * @param hyperplane hyperplane to format
-         */
-        protected abstract void formatHyperplane(Hyperplane<S> hyperplane);
-
-        /** {@inheritDoc} */
-        @Override
-        public Order visitOrder(final BSPTree<S> node) {
-            return Order.SUB_MINUS_PLUS;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void visitInternalNode(final BSPTree<S> node) {
-            formatter.format("%s %s internal ", prefix, type(node));
-            formatHyperplane(node.getCut().getHyperplane());
-            formatter.format("%n");
-            prefix = prefix + "  ";
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void visitLeafNode(final BSPTree<S> node) {
-            formatter.format("%s %s leaf %s%n",
-                             prefix, type(node), node.getAttribute());
-            for (BSPTree<S> n = node;
-                 n.getParent() != null && n == n.getParent().getPlus();
-                 n = n.getParent()) {
-                prefix = prefix.substring(0, prefix.length() - 2);
-            }
-        }
-
-        /** Get the type of the node.
-         * @param node node to check
-         * @return "plus " or "minus" depending on the node being the plus or minus
-         * child of its parent ("plus " is arbitrarily returned for the root node)
-         */
-        private String type(final BSPTree<S> node) {
-            return (node.getParent() != null && node == node.getParent().getMinus()) ? "minus" : "plus ";
-        }
-
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/partitioning/RegionParser.java b/src/test/java/org/apache/commons/math4/geometry/partitioning/RegionParser.java
deleted file mode 100644
index c338749..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/partitioning/RegionParser.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * 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.partitioning;
-
-import java.io.IOException;
-import java.text.ParseException;
-import java.util.StringTokenizer;
-
-import org.apache.commons.math4.geometry.Space;
-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.Cartesian1D;
-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.Cartesian3D;
-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.Cartesian2D;
-import org.apache.commons.math4.geometry.spherical.oned.ArcsSet;
-import org.apache.commons.math4.geometry.spherical.oned.LimitAngle;
-import org.apache.commons.math4.geometry.spherical.oned.S1Point;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.apache.commons.math4.geometry.spherical.twod.Circle;
-import org.apache.commons.math4.geometry.spherical.twod.Sphere2D;
-import org.apache.commons.math4.geometry.spherical.twod.SphericalPolygonsSet;
-
-/** Class parsing a string representation of an {@link AbstractRegion}.
- * <p>
- * This class is intended for tests and debug purposes only.
- * </p>
- * @see RegionDumper
- * @since 3.5
- */
-public class RegionParser {
-
-    /** Private constructor for a utility class
-     */
-    private RegionParser() {
-    }
-
-    /** Parse a string representation of an {@link ArcsSet}.
-     * @param s string to parse
-     * @return parsed region
-     * @exception IOException if the string cannot be read
-     * @exception ParseException if the string cannot be parsed
-     */
-    public static ArcsSet parseArcsSet(final String s)
-        throws IOException, ParseException {
-        final TreeBuilder<Sphere1D> builder = new TreeBuilder<Sphere1D>("ArcsSet", s) {
-
-            /** {@inheritDoc} */
-            @Override
-            protected LimitAngle parseHyperplane()
-                throws IOException, ParseException {
-                return new LimitAngle(new S1Point(getNumber()), getBoolean(), getNumber());
-            }
-
-        };
-        return new ArcsSet(builder.getTree(), builder.getTolerance());
-    }
-
-    /** Parse a string representation of a {@link SphericalPolygonsSet}.
-     * @param s string to parse
-     * @return parsed region
-     * @exception IOException if the string cannot be read
-     * @exception ParseException if the string cannot be parsed
-     */
-    public static SphericalPolygonsSet parseSphericalPolygonsSet(final String s)
-        throws IOException, ParseException {
-        final TreeBuilder<Sphere2D> builder = new TreeBuilder<Sphere2D>("SphericalPolygonsSet", s) {
-
-            /** {@inheritDoc} */
-            @Override
-            public Circle parseHyperplane()
-                throws IOException, ParseException {
-                return new Circle(new Cartesian3D(getNumber(), getNumber(), getNumber()), getNumber());
-            }
-
-        };
-        return new SphericalPolygonsSet(builder.getTree(), builder.getTolerance());
-    }
-
-    /** Parse a string representation of an {@link IntervalsSet}.
-     * @param s string to parse
-     * @return parsed region
-     * @exception IOException if the string cannot be read
-     * @exception ParseException if the string cannot be parsed
-     */
-    public static IntervalsSet parseIntervalsSet(final String s)
-        throws IOException, ParseException {
-        final TreeBuilder<Euclidean1D> builder = new TreeBuilder<Euclidean1D>("IntervalsSet", s) {
-
-            /** {@inheritDoc} */
-            @Override
-            public OrientedPoint parseHyperplane()
-                throws IOException, ParseException {
-                return new OrientedPoint(new Cartesian1D(getNumber()), getBoolean(), getNumber());
-            }
-
-        };
-        return new IntervalsSet(builder.getTree(), builder.getTolerance());
-    }
-
-    /** Parse a string representation of a {@link PolygonsSet}.
-     * @param s string to parse
-     * @return parsed region
-     * @exception IOException if the string cannot be read
-     * @exception ParseException if the string cannot be parsed
-     */
-    public static PolygonsSet parsePolygonsSet(final String s)
-        throws IOException, ParseException {
-        final TreeBuilder<Euclidean2D> builder = new TreeBuilder<Euclidean2D>("PolygonsSet", s) {
-
-            /** {@inheritDoc} */
-            @Override
-            public Line parseHyperplane()
-                throws IOException, ParseException {
-                return new Line(new Cartesian2D(getNumber(), getNumber()), getNumber(), getNumber());
-            }
-
-        };
-        return new PolygonsSet(builder.getTree(), builder.getTolerance());
-    }
-
-    /** Parse a string representation of a {@link PolyhedronsSet}.
-     * @param s string to parse
-     * @return parsed region
-     * @exception IOException if the string cannot be read
-     * @exception ParseException if the string cannot be parsed
-     */
-    public static PolyhedronsSet parsePolyhedronsSet(final String s)
-        throws IOException, ParseException {
-        final TreeBuilder<Euclidean3D> builder = new TreeBuilder<Euclidean3D>("PolyhedronsSet", s) {
-
-            /** {@inheritDoc} */
-            @Override
-            public Plane parseHyperplane()
-                throws IOException, ParseException {
-                return new Plane(new Cartesian3D(getNumber(), getNumber(), getNumber()),
-                                 new Cartesian3D(getNumber(), getNumber(), getNumber()),
-                                 getNumber());
-            }
-
-        };
-        return new PolyhedronsSet(builder.getTree(), builder.getTolerance());
-    }
-
-    /** Local class for building an {@link AbstractRegion} tree.
-     * @param <S> Type of the space.
-     */
-    private abstract static class TreeBuilder<S extends Space> {
-
-        /** Keyword for tolerance. */
-        private static final String TOLERANCE = "tolerance";
-
-        /** Keyword for internal nodes. */
-        private static final String INTERNAL  = "internal";
-
-        /** Keyword for leaf nodes. */
-        private static final String LEAF      = "leaf";
-
-        /** Keyword for plus children trees. */
-        private static final String PLUS      = "plus";
-
-        /** Keyword for minus children trees. */
-        private static final String MINUS     = "minus";
-
-        /** Keyword for true flags. */
-        private static final String TRUE      = "true";
-
-        /** Keyword for false flags. */
-        private static final String FALSE     = "false";
-
-        /** Tree root. */
-        private BSPTree<S> root;
-
-        /** Tolerance. */
-        private final double tolerance;
-
-        /** Tokenizer parsing string representation. */
-        private final StringTokenizer tokenizer;
-
-        /** Simple constructor.
-         * @param type type of the expected representation
-         * @param reader reader for the string representation
-         * @exception IOException if the string cannot be read
-         * @exception ParseException if the string cannot be parsed
-         */
-        public TreeBuilder(final String type, final String s)
-            throws IOException, ParseException {
-            root = null;
-            tokenizer = new StringTokenizer(s);
-            getWord(type);
-            getWord(TOLERANCE);
-            tolerance = getNumber();
-            getWord(PLUS);
-            root = new BSPTree<>();
-            parseTree(root);
-            if (tokenizer.hasMoreTokens()) {
-                throw new ParseException("unexpected " + tokenizer.nextToken(), 0);
-            }
-        }
-
-        /** Parse a tree.
-         * @param node start node
-         * @exception IOException if the string cannot be read
-         * @exception ParseException if the string cannot be parsed
-         */
-        private void parseTree(final BSPTree<S> node)
-            throws IOException, ParseException {
-            if (INTERNAL.equals(getWord(INTERNAL, LEAF))) {
-                // this is an internal node, it has a cut sub-hyperplane (stored as a whole hyperplane)
-                // then a minus tree, then a plus tree
-                node.insertCut(parseHyperplane());
-                getWord(MINUS);
-                parseTree(node.getMinus());
-                getWord(PLUS);
-                parseTree(node.getPlus());
-            } else {
-                // this is a leaf node, it has only an inside/outside flag
-                node.setAttribute(getBoolean());
-            }
-        }
-
-        /** Get next word.
-         * @param allowed allowed values
-         * @return parsed word
-         * @exception IOException if the string cannot be read
-         * @exception ParseException if the string cannot be parsed
-         */
-        protected String getWord(final String ... allowed)
-            throws IOException, ParseException {
-            final String token = tokenizer.nextToken();
-            for (final String a : allowed) {
-                if (a.equals(token)) {
-                    return token;
-                }
-            }
-            throw new ParseException(token + " != " + allowed[0], 0);
-        }
-
-        /** Get next number.
-         * @return parsed number
-         * @exception IOException if the string cannot be read
-         * @exception NumberFormatException if the string cannot be parsed
-         */
-        protected double getNumber()
-            throws IOException, NumberFormatException {
-            return Double.parseDouble(tokenizer.nextToken());
-        }
-
-        /** Get next boolean.
-         * @return parsed boolean
-         * @exception IOException if the string cannot be read
-         * @exception ParseException if the string cannot be parsed
-         */
-        protected boolean getBoolean()
-            throws IOException, ParseException {
-            return getWord(TRUE, FALSE).equals(TRUE);
-        }
-
-        /** Get the built tree.
-         * @return built tree
-         */
-        public BSPTree<S> getTree() {
-            return root;
-        }
-
-        /** Get the tolerance.
-         * @return tolerance
-         */
-        public double getTolerance() {
-            return tolerance;
-        }
-
-        /** Parse an hyperplane.
-         * @return next hyperplane from the stream
-         * @exception IOException if the string cannot be read
-         * @exception ParseException if the string cannot be parsed
-         */
-        protected abstract Hyperplane<S> parseHyperplane()
-            throws IOException, ParseException;
-
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/spherical/oned/ArcTest.java b/src/test/java/org/apache/commons/math4/geometry/spherical/oned/ArcTest.java
deleted file mode 100644
index 3a2e6b1..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/spherical/oned/ArcTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.spherical.oned;
-
-import org.apache.commons.math4.exception.NumberIsTooLargeException;
-import org.apache.commons.math4.geometry.partitioning.Region;
-import org.apache.commons.math4.geometry.spherical.oned.Arc;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-import org.apache.commons.numbers.core.Precision;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class ArcTest {
-
-    @Test
-    public void testArc() {
-        Arc arc = new Arc(2.3, 5.7, 1.0e-10);
-        Assert.assertEquals(3.4, arc.getSize(), 1.0e-10);
-        Assert.assertEquals(4.0, arc.getBarycenter(), 1.0e-10);
-        Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(2.3));
-        Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(5.7));
-        Assert.assertEquals(Region.Location.OUTSIDE,  arc.checkPoint(1.2));
-        Assert.assertEquals(Region.Location.OUTSIDE,  arc.checkPoint(8.5));
-        Assert.assertEquals(Region.Location.INSIDE,   arc.checkPoint(8.7));
-        Assert.assertEquals(Region.Location.INSIDE,   arc.checkPoint(3.0));
-        Assert.assertEquals(2.3, arc.getInf(), 1.0e-10);
-        Assert.assertEquals(5.7, arc.getSup(), 1.0e-10);
-        Assert.assertEquals(4.0, arc.getBarycenter(), 1.0e-10);
-        Assert.assertEquals(3.4, arc.getSize(), 1.0e-10);
-    }
-
-    @Test(expected=NumberIsTooLargeException.class)
-    public void testWrongInterval() {
-        new Arc(1.2, 0.0, 1.0e-10);
-    }
-
-    @Test
-    public void testTolerance() {
-        Assert.assertEquals(Region.Location.OUTSIDE,  new Arc(2.3, 5.7, 1.0).checkPoint(1.2));
-        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 1.2).checkPoint(1.2));
-        Assert.assertEquals(Region.Location.OUTSIDE,  new Arc(2.3, 5.7, 0.7).checkPoint(6.5));
-        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 0.9).checkPoint(6.5));
-        Assert.assertEquals(Region.Location.INSIDE,   new Arc(2.3, 5.7, 0.6).checkPoint(3.0));
-        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 0.8).checkPoint(3.0));
-    }
-
-    @Test
-    public void testFullCircle() {
-        Arc arc = new Arc(9.0, 9.0, 1.0e-10);
-        // no boundaries on a full circle
-        Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(9.0));
-        Assert.assertEquals(.0, arc.getInf(), 1.0e-10);
-        Assert.assertEquals(MathUtils.TWO_PI, arc.getSup(), 1.0e-10);
-        Assert.assertEquals(2.0 * FastMath.PI, arc.getSize(), 1.0e-10);
-        for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
-            Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(alpha));
-        }
-    }
-
-    @Test
-    public void testSmall() {
-        Arc arc = new Arc(1.0, FastMath.nextAfter(1.0, Double.POSITIVE_INFINITY), Precision.EPSILON);
-        Assert.assertEquals(2 * Precision.EPSILON, arc.getSize(), Precision.SAFE_MIN);
-        Assert.assertEquals(1.0, arc.getBarycenter(), Precision.EPSILON);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/spherical/oned/ArcsSetTest.java b/src/test/java/org/apache/commons/math4/geometry/spherical/oned/ArcsSetTest.java
deleted file mode 100644
index 663af6a..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/spherical/oned/ArcsSetTest.java
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * 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.spherical.oned;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-import org.apache.commons.math4.exception.NumberIsTooLargeException;
-import org.apache.commons.math4.geometry.partitioning.BSPTree;
-import org.apache.commons.math4.geometry.partitioning.Region;
-import org.apache.commons.math4.geometry.partitioning.RegionFactory;
-import org.apache.commons.math4.geometry.partitioning.Side;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-import org.apache.commons.math4.geometry.partitioning.Region.Location;
-import org.apache.commons.math4.geometry.spherical.oned.Arc;
-import org.apache.commons.math4.geometry.spherical.oned.ArcsSet;
-import org.apache.commons.math4.geometry.spherical.oned.LimitAngle;
-import org.apache.commons.math4.geometry.spherical.oned.S1Point;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.apache.commons.math4.geometry.spherical.oned.SubLimitAngle;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-import org.apache.commons.numbers.core.Precision;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class ArcsSetTest {
-
-    @Test
-    public void testArc() {
-        ArcsSet set = new ArcsSet(2.3, 5.7, 1.0e-10);
-        Assert.assertEquals(3.4, set.getSize(), 1.0e-10);
-        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(2.3)));
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.7)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(1.2)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(8.5)));
-        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new S1Point(8.7)));
-        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new S1Point(3.0)));
-        Assert.assertEquals(1, set.asList().size());
-        Assert.assertEquals(2.3, set.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.7, set.asList().get(0).getSup(), 1.0e-10);
-    }
-
-    @Test
-    public void testWrapAround2PiArc() {
-        ArcsSet set = new ArcsSet(5.7 - MathUtils.TWO_PI, 2.3, 1.0e-10);
-        Assert.assertEquals(MathUtils.TWO_PI - 3.4, set.getSize(), 1.0e-10);
-        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(2.3)));
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.7)));
-        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new S1Point(1.2)));
-        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new S1Point(8.5)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(8.7)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(3.0)));
-        Assert.assertEquals(1, set.asList().size());
-        Assert.assertEquals(5.7, set.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(2.3 + MathUtils.TWO_PI, set.asList().get(0).getSup(), 1.0e-10);
-    }
-
-    @Test
-    public void testSplitOver2Pi() {
-        ArcsSet set = new ArcsSet(1.0e-10);
-        Arc     arc = new Arc(1.5 * FastMath.PI, 2.5 * FastMath.PI, 1.0e-10);
-        ArcsSet.Split split = set.split(arc);
-        for (double alpha = 0.0; alpha <= MathUtils.TWO_PI; alpha += 0.01) {
-            S1Point p = new S1Point(alpha);
-            if (alpha < 0.5 * FastMath.PI || alpha > 1.5 * FastMath.PI) {
-                Assert.assertEquals(Location.OUTSIDE, split.getPlus().checkPoint(p));
-                Assert.assertEquals(Location.INSIDE,  split.getMinus().checkPoint(p));
-            } else {
-                Assert.assertEquals(Location.INSIDE,  split.getPlus().checkPoint(p));
-                Assert.assertEquals(Location.OUTSIDE, split.getMinus().checkPoint(p));
-            }
-        }
-    }
-
-    @Test
-    public void testSplitAtEnd() {
-        ArcsSet set = new ArcsSet(1.0e-10);
-        Arc     arc = new Arc(FastMath.PI, MathUtils.TWO_PI, 1.0e-10);
-        ArcsSet.Split split = set.split(arc);
-        for (double alpha = 0.01; alpha < MathUtils.TWO_PI; alpha += 0.01) {
-            S1Point p = new S1Point(alpha);
-            if (alpha > FastMath.PI) {
-                Assert.assertEquals(Location.OUTSIDE, split.getPlus().checkPoint(p));
-                Assert.assertEquals(Location.INSIDE,  split.getMinus().checkPoint(p));
-            } else {
-                Assert.assertEquals(Location.INSIDE,  split.getPlus().checkPoint(p));
-                Assert.assertEquals(Location.OUTSIDE, split.getMinus().checkPoint(p));
-            }
-        }
-
-        S1Point zero = new S1Point(0.0);
-        Assert.assertEquals(Location.BOUNDARY,  split.getPlus().checkPoint(zero));
-        Assert.assertEquals(Location.BOUNDARY,  split.getMinus().checkPoint(zero));
-
-        S1Point pi = new S1Point(FastMath.PI);
-        Assert.assertEquals(Location.BOUNDARY,  split.getPlus().checkPoint(pi));
-        Assert.assertEquals(Location.BOUNDARY,  split.getMinus().checkPoint(pi));
-
-    }
-
-    @Test(expected=NumberIsTooLargeException.class)
-    public void testWrongInterval() {
-        new ArcsSet(1.2, 0.0, 1.0e-10);
-    }
-
-    @Test
-    public void testFullEqualEndPoints() {
-        ArcsSet set = new ArcsSet(1.0, 1.0, 1.0e-10);
-        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
-        Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(9.0)));
-        for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
-            Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(alpha)));
-        }
-        Assert.assertEquals(1, set.asList().size());
-        Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(2 * FastMath.PI, set.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(2 * FastMath.PI, set.getSize(), 1.0e-10);
-    }
-
-    @Test
-    public void testFullCircle() {
-        ArcsSet set = new ArcsSet(1.0e-10);
-        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
-        Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(9.0)));
-        for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
-            Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(alpha)));
-        }
-        Assert.assertEquals(1, set.asList().size());
-        Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(2 * FastMath.PI, set.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(2 * FastMath.PI, set.getSize(), 1.0e-10);
-    }
-
-    @Test
-    public void testEmpty() {
-        ArcsSet empty = (ArcsSet) new RegionFactory<Sphere1D>().getComplement(new ArcsSet(1.0e-10));
-        Assert.assertEquals(1.0e-10, empty.getTolerance(), 1.0e-20);
-        Assert.assertEquals(0.0, empty.getSize(), 1.0e-10);
-        Assert.assertTrue(empty.asList().isEmpty());
-    }
-
-    @Test
-    public void testTiny() {
-        ArcsSet tiny = new ArcsSet(0.0, Precision.SAFE_MIN / 2, 1.0e-10);
-        Assert.assertEquals(1.0e-10, tiny.getTolerance(), 1.0e-20);
-        Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.getSize(), 1.0e-10);
-        Assert.assertEquals(1, tiny.asList().size());
-        Assert.assertEquals(0.0, tiny.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.asList().get(0).getSup(), 1.0e-10);
-    }
-
-    @Test
-    public void testSpecialConstruction() {
-        List<SubHyperplane<Sphere1D>> boundary = new ArrayList<>();
-        boundary.add(new LimitAngle(new S1Point(0.0), false, 1.0e-10).wholeHyperplane());
-        boundary.add(new LimitAngle(new S1Point(MathUtils.TWO_PI - 1.0e-11), true, 1.0e-10).wholeHyperplane());
-        ArcsSet set = new ArcsSet(boundary, 1.0e-10);
-        Assert.assertEquals(MathUtils.TWO_PI, set.getSize(), 1.0e-10);
-        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
-        Assert.assertEquals(1, set.asList().size());
-        Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(MathUtils.TWO_PI, set.asList().get(0).getSup(), 1.0e-10);
-    }
-
-    @Test
-    public void testDifference() {
-
-        ArcsSet a   = new ArcsSet(1.0, 6.0, 1.0e-10);
-        List<Arc> aList = a.asList();
-        Assert.assertEquals(1,   aList.size());
-        Assert.assertEquals(1.0, aList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, aList.get(0).getSup(), 1.0e-10);
-
-        ArcsSet b   = new ArcsSet(3.0, 5.0, 1.0e-10);
-        List<Arc> bList = b.asList();
-        Assert.assertEquals(1,   bList.size());
-        Assert.assertEquals(3.0, bList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, bList.get(0).getSup(), 1.0e-10);
-
-        ArcsSet aMb = (ArcsSet) new RegionFactory<Sphere1D>().difference(a, b);
-        for (int k = -2; k < 3; ++k) {
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(0.0 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(0.9 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(1.0 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(1.1 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(2.9 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(3.0 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(3.1 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(4.9 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(5.0 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(5.1 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(5.9 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(6.0 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(6.1 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(6.2 + k * MathUtils.TWO_PI)));
-        }
-
-        List<Arc> aMbList = aMb.asList();
-        Assert.assertEquals(2,   aMbList.size());
-        Assert.assertEquals(1.0, aMbList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, aMbList.get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(5.0, aMbList.get(1).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, aMbList.get(1).getSup(), 1.0e-10);
-
-
-    }
-
-    @Test
-    public void testIntersection() {
-
-        ArcsSet a   = (ArcsSet) new RegionFactory<Sphere1D>().union(new ArcsSet(1.0, 3.0, 1.0e-10),
-                                                                    new ArcsSet(5.0, 6.0, 1.0e-10));
-        List<Arc> aList = a.asList();
-        Assert.assertEquals(2,   aList.size());
-        Assert.assertEquals(1.0, aList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, aList.get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(5.0, aList.get(1).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, aList.get(1).getSup(), 1.0e-10);
-
-        ArcsSet b   = new ArcsSet(0.0, 5.5, 1.0e-10);
-        List<Arc> bList = b.asList();
-        Assert.assertEquals(1,   bList.size());
-        Assert.assertEquals(0.0, bList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.5, bList.get(0).getSup(), 1.0e-10);
-
-        ArcsSet aMb = (ArcsSet) new RegionFactory<Sphere1D>().intersection(a, b);
-        for (int k = -2; k < 3; ++k) {
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(0.0 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(1.0 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(1.1 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(2.9 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(3.0 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(3.1 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(4.9 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(5.0 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(5.1 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(5.4 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(5.5 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(5.6 + k * MathUtils.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(6.2 + k * MathUtils.TWO_PI)));
-        }
-
-        List<Arc> aMbList = aMb.asList();
-        Assert.assertEquals(2,   aMbList.size());
-        Assert.assertEquals(1.0, aMbList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, aMbList.get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(5.0, aMbList.get(1).getInf(), 1.0e-10);
-        Assert.assertEquals(5.5, aMbList.get(1).getSup(), 1.0e-10);
-
-
-    }
-
-    @Test
-    public void testMultiple() {
-        RegionFactory<Sphere1D> factory = new RegionFactory<>();
-        ArcsSet set = (ArcsSet)
-        factory.intersection(factory.union(factory.difference(new ArcsSet(1.0, 6.0, 1.0e-10),
-                                                              new ArcsSet(3.0, 5.0, 1.0e-10)),
-                                                              new ArcsSet(0.5, 2.0, 1.0e-10)),
-                                                              new ArcsSet(0.0, 5.5, 1.0e-10));
-        Assert.assertEquals(3.0, set.getSize(), 1.0e-10);
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(0.0)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(4.0)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(6.0)));
-        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new S1Point(1.2)));
-        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new S1Point(5.25)));
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(0.5)));
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(3.0)));
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.0)));
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.5)));
-
-        List<Arc> list = set.asList();
-        Assert.assertEquals(2, list.size());
-        Assert.assertEquals( 0.5, list.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals( 3.0, list.get(0).getSup(), 1.0e-10);
-        Assert.assertEquals( 5.0, list.get(1).getInf(), 1.0e-10);
-        Assert.assertEquals( 5.5, list.get(1).getSup(), 1.0e-10);
-
-    }
-
-    @Test
-    public void testSinglePoint() {
-        ArcsSet set = new ArcsSet(1.0, FastMath.nextAfter(1.0, Double.POSITIVE_INFINITY), 1.0e-10);
-        Assert.assertEquals(2 * Precision.EPSILON, set.getSize(), Precision.SAFE_MIN);
-    }
-
-    @Test
-    public void testIteration() {
-        ArcsSet set = (ArcsSet) new RegionFactory<Sphere1D>().difference(new ArcsSet(1.0, 6.0, 1.0e-10),
-                                                                         new ArcsSet(3.0, 5.0, 1.0e-10));
-        Iterator<double[]> iterator = set.iterator();
-        try {
-            iterator.remove();
-            Assert.fail("an exception should have been thrown");
-        } catch (UnsupportedOperationException uoe) {
-            // expected
-        }
-
-        Assert.assertTrue(iterator.hasNext());
-        double[] a0 = iterator.next();
-        Assert.assertEquals(2, a0.length);
-        Assert.assertEquals(1.0, a0[0], 1.0e-10);
-        Assert.assertEquals(3.0, a0[1], 1.0e-10);
-
-        Assert.assertTrue(iterator.hasNext());
-        double[] a1 = iterator.next();
-        Assert.assertEquals(2, a1.length);
-        Assert.assertEquals(5.0, a1[0], 1.0e-10);
-        Assert.assertEquals(6.0, a1[1], 1.0e-10);
-
-        Assert.assertFalse(iterator.hasNext());
-        try {
-            iterator.next();
-            Assert.fail("an exception should have been thrown");
-        } catch (NoSuchElementException nsee) {
-            // expected
-        }
-
-    }
-
-    @Test
-    public void testEmptyTree() {
-        Assert.assertEquals(MathUtils.TWO_PI, new ArcsSet(new BSPTree<Sphere1D>(Boolean.TRUE), 1.0e-10).getSize(), 1.0e-10);
-    }
-
-    @Test
-    public void testShiftedAngles() {
-        for (int k = -2; k < 3; ++k) {
-            SubLimitAngle l1  = new LimitAngle(new S1Point(1.0 + k * MathUtils.TWO_PI), false, 1.0e-10).wholeHyperplane();
-            SubLimitAngle l2  = new LimitAngle(new S1Point(1.5 + k * MathUtils.TWO_PI), true,  1.0e-10).wholeHyperplane();
-            ArcsSet set = new ArcsSet(new BSPTree<>(l1,
-                                                            new BSPTree<Sphere1D>(Boolean.FALSE),
-                                                            new BSPTree<>(l2,
-                                                                                  new BSPTree<Sphere1D>(Boolean.FALSE),
-                                                                                  new BSPTree<Sphere1D>(Boolean.TRUE),
-                                                                                  null),
-                                                            null),
-                                      1.0e-10);
-            for (double alpha = 1.0e-6; alpha < MathUtils.TWO_PI; alpha += 0.001) {
-                if (alpha < 1 || alpha > 1.5) {
-                    Assert.assertEquals(Location.OUTSIDE, set.checkPoint(new S1Point(alpha)));
-                } else {
-                    Assert.assertEquals(Location.INSIDE,  set.checkPoint(new S1Point(alpha)));
-                }
-            }
-        }
-
-    }
-
-    @Test(expected=ArcsSet.InconsistentStateAt2PiWrapping.class)
-    public void testInconsistentState() {
-        SubLimitAngle l1 = new LimitAngle(new S1Point(1.0), false, 1.0e-10).wholeHyperplane();
-        SubLimitAngle l2 = new LimitAngle(new S1Point(2.0), true,  1.0e-10).wholeHyperplane();
-        SubLimitAngle l3 = new LimitAngle(new S1Point(3.0), false, 1.0e-10).wholeHyperplane();
-        new ArcsSet(new BSPTree<>(l1,
-                                          new BSPTree<Sphere1D>(Boolean.FALSE),
-                                          new BSPTree<>(l2,
-                                                                new BSPTree<>(l3,
-                                                                                      new BSPTree<Sphere1D>(Boolean.FALSE),
-                                                                                      new BSPTree<Sphere1D>(Boolean.TRUE),
-                                                                                      null),
-                                                                new BSPTree<Sphere1D>(Boolean.TRUE),
-                                                                null),
-                                          null),
-                                          1.0e-10);
-    }
-
-    @Test
-    public void testSide() {
-        ArcsSet set = (ArcsSet) new RegionFactory<Sphere1D>().difference(new ArcsSet(1.0, 6.0, 1.0e-10),
-                                                                         new ArcsSet(3.0, 5.0, 1.0e-10));
-        for (int k = -2; k < 3; ++k) {
-            Assert.assertEquals(Side.MINUS, set.split(new Arc(0.5 + k * MathUtils.TWO_PI,
-                                                              6.1 + k * MathUtils.TWO_PI,
-                                                              set.getTolerance())).getSide());
-            Assert.assertEquals(Side.PLUS,  set.split(new Arc(0.5 + k * MathUtils.TWO_PI,
-                                                              0.8 + k * MathUtils.TWO_PI,
-                                                              set.getTolerance())).getSide());
-            Assert.assertEquals(Side.PLUS,  set.split(new Arc(6.2 + k * MathUtils.TWO_PI,
-                                                              6.3 + k * MathUtils.TWO_PI,
-                                                              set.getTolerance())).getSide());
-            Assert.assertEquals(Side.PLUS,  set.split(new Arc(3.5 + k * MathUtils.TWO_PI,
-                                                              4.5 + k * MathUtils.TWO_PI,
-                                                              set.getTolerance())).getSide());
-            Assert.assertEquals(Side.BOTH,  set.split(new Arc(2.9 + k * MathUtils.TWO_PI,
-                                                              4.5 + k * MathUtils.TWO_PI,
-                                                              set.getTolerance())).getSide());
-            Assert.assertEquals(Side.BOTH,  set.split(new Arc(0.5 + k * MathUtils.TWO_PI,
-                                                              1.2 + k * MathUtils.TWO_PI,
-                                                              set.getTolerance())).getSide());
-            Assert.assertEquals(Side.BOTH,  set.split(new Arc(0.5 + k * MathUtils.TWO_PI,
-                                                              5.9 + k * MathUtils.TWO_PI,
-                                                              set.getTolerance())).getSide());
-        }
-    }
-
-    @Test
-    public void testSideEmbedded() {
-
-        ArcsSet s35 = new ArcsSet(3.0, 5.0, 1.0e-10);
-        ArcsSet s16 = new ArcsSet(1.0, 6.0, 1.0e-10);
-
-        Assert.assertEquals(Side.BOTH,  s16.split(new Arc(3.0, 5.0, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.BOTH,  s16.split(new Arc(5.0, 3.0 + MathUtils.TWO_PI, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.MINUS, s35.split(new Arc(1.0, 6.0, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.PLUS,  s35.split(new Arc(6.0, 1.0 + MathUtils.TWO_PI, 1.0e-10)).getSide());
-
-    }
-
-    @Test
-    public void testSideOverlapping() {
-        ArcsSet s35 = new ArcsSet(3.0, 5.0, 1.0e-10);
-        ArcsSet s46 = new ArcsSet(4.0, 6.0, 1.0e-10);
-
-        Assert.assertEquals(Side.BOTH,  s46.split(new Arc(3.0, 5.0, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.BOTH,  s46.split(new Arc(5.0, 3.0 + MathUtils.TWO_PI, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.BOTH, s35.split(new Arc(4.0, 6.0, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.BOTH,  s35.split(new Arc(6.0, 4.0 + MathUtils.TWO_PI, 1.0e-10)).getSide());
-    }
-
-    @Test
-    public void testSideHyper() {
-        ArcsSet sub = (ArcsSet) new RegionFactory<Sphere1D>().getComplement(new ArcsSet(1.0e-10));
-        Assert.assertTrue(sub.isEmpty());
-        Assert.assertEquals(Side.HYPER,  sub.split(new Arc(2.0, 3.0, 1.0e-10)).getSide());
-    }
-
-    @Test
-    public void testSplitEmbedded() {
-
-        ArcsSet s35 = new ArcsSet(3.0, 5.0, 1.0e-10);
-        ArcsSet s16 = new ArcsSet(1.0, 6.0, 1.0e-10);
-
-        ArcsSet.Split split1 = s16.split(new Arc(3.0, 5.0, 1.0e-10));
-        ArcsSet split1Plus  = split1.getPlus();
-        ArcsSet split1Minus = split1.getMinus();
-        Assert.assertEquals(3.0, split1Plus.getSize(), 1.0e-10);
-        Assert.assertEquals(2,   split1Plus.asList().size());
-        Assert.assertEquals(1.0, split1Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, split1Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(5.0, split1Plus.asList().get(1).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, split1Plus.asList().get(1).getSup(), 1.0e-10);
-        Assert.assertEquals(2.0, split1Minus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split1Minus.asList().size());
-        Assert.assertEquals(3.0, split1Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split1Minus.asList().get(0).getSup(), 1.0e-10);
-
-        ArcsSet.Split split2 = s16.split(new Arc(5.0, 3.0 + MathUtils.TWO_PI, 1.0e-10));
-        ArcsSet split2Plus  = split2.getPlus();
-        ArcsSet split2Minus = split2.getMinus();
-        Assert.assertEquals(2.0, split2Plus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split2Plus.asList().size());
-        Assert.assertEquals(3.0, split2Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split2Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(3.0, split2Minus.getSize(), 1.0e-10);
-        Assert.assertEquals(2,   split2Minus.asList().size());
-        Assert.assertEquals(1.0, split2Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, split2Minus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(5.0, split2Minus.asList().get(1).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, split2Minus.asList().get(1).getSup(), 1.0e-10);
-
-        ArcsSet.Split split3 = s35.split(new Arc(1.0, 6.0, 1.0e-10));
-        ArcsSet split3Plus  = split3.getPlus();
-        ArcsSet split3Minus = split3.getMinus();
-        Assert.assertNull(split3Plus);
-        Assert.assertEquals(2.0, split3Minus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split3Minus.asList().size());
-        Assert.assertEquals(3.0, split3Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split3Minus.asList().get(0).getSup(), 1.0e-10);
-
-        ArcsSet.Split split4 = s35.split(new Arc(6.0, 1.0 + MathUtils.TWO_PI, 1.0e-10));
-        ArcsSet split4Plus  = split4.getPlus();
-        ArcsSet split4Minus = split4.getMinus();
-        Assert.assertEquals(2.0, split4Plus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split4Plus.asList().size());
-        Assert.assertEquals(3.0, split4Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split4Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertNull(split4Minus);
-
-    }
-
-    @Test
-    public void testSplitOverlapping() {
-
-        ArcsSet s35 = new ArcsSet(3.0, 5.0, 1.0e-10);
-        ArcsSet s46 = new ArcsSet(4.0, 6.0, 1.0e-10);
-
-        ArcsSet.Split split1 = s46.split(new Arc(3.0, 5.0, 1.0e-10));
-        ArcsSet split1Plus  = split1.getPlus();
-        ArcsSet split1Minus = split1.getMinus();
-        Assert.assertEquals(1.0, split1Plus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split1Plus.asList().size());
-        Assert.assertEquals(5.0, split1Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, split1Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(1.0, split1Minus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split1Minus.asList().size());
-        Assert.assertEquals(4.0, split1Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split1Minus.asList().get(0).getSup(), 1.0e-10);
-
-        ArcsSet.Split split2 = s46.split(new Arc(5.0, 3.0 + MathUtils.TWO_PI, 1.0e-10));
-        ArcsSet split2Plus  = split2.getPlus();
-        ArcsSet split2Minus = split2.getMinus();
-        Assert.assertEquals(1.0, split2Plus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split2Plus.asList().size());
-        Assert.assertEquals(4.0, split2Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split2Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(1.0, split2Minus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split2Minus.asList().size());
-        Assert.assertEquals(5.0, split2Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, split2Minus.asList().get(0).getSup(), 1.0e-10);
-
-        ArcsSet.Split split3 = s35.split(new Arc(4.0, 6.0, 1.0e-10));
-        ArcsSet split3Plus  = split3.getPlus();
-        ArcsSet split3Minus = split3.getMinus();
-        Assert.assertEquals(1.0, split3Plus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split3Plus.asList().size());
-        Assert.assertEquals(3.0, split3Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(4.0, split3Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(1.0, split3Minus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split3Minus.asList().size());
-        Assert.assertEquals(4.0, split3Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split3Minus.asList().get(0).getSup(), 1.0e-10);
-
-        ArcsSet.Split split4 = s35.split(new Arc(6.0, 4.0 + MathUtils.TWO_PI, 1.0e-10));
-        ArcsSet split4Plus  = split4.getPlus();
-        ArcsSet split4Minus = split4.getMinus();
-        Assert.assertEquals(1.0, split4Plus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split4Plus.asList().size());
-        Assert.assertEquals(4.0, split4Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split4Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(1.0, split4Minus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   split4Minus.asList().size());
-        Assert.assertEquals(3.0, split4Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(4.0, split4Minus.asList().get(0).getSup(), 1.0e-10);
-
-    }
-
-    @Test
-    public void testFarSplit() {
-        ArcsSet set = new ArcsSet(FastMath.PI, 2.5 * FastMath.PI, 1.0e-10);
-        ArcsSet.Split split = set.split(new Arc(0.5 * FastMath.PI, 1.5 * FastMath.PI, 1.0e-10));
-        ArcsSet splitPlus  = split.getPlus();
-        ArcsSet splitMinus = split.getMinus();
-        Assert.assertEquals(1,   splitMinus.asList().size());
-        Assert.assertEquals(1.0 * FastMath.PI, splitMinus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(1.5 * FastMath.PI, splitMinus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, splitMinus.getSize(), 1.0e-10);
-        Assert.assertEquals(1,   splitPlus.asList().size());
-        Assert.assertEquals(1.5 * FastMath.PI, splitPlus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(2.5 * FastMath.PI, splitPlus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(1.0 * FastMath.PI, splitPlus.getSize(), 1.0e-10);
-
-    }
-
-    @Test
-    public void testSplitWithinEpsilon() {
-        double epsilon = 1.0e-10;
-        double a = 6.25;
-        double b = a - 0.5 * epsilon;
-        ArcsSet set = new ArcsSet(a - 1, a, epsilon);
-        Arc arc = new Arc(b, b + FastMath.PI, epsilon);
-        ArcsSet.Split split = set.split(arc);
-        Assert.assertEquals(set.getSize(), split.getPlus().getSize(),  epsilon);
-        Assert.assertNull(split.getMinus());
-    }
-
-    @Test
-    public void testSideSplitConsistency() {
-        double  epsilon = 1.0e-6;
-        double  a       = 4.725;
-        ArcsSet set     = new ArcsSet(a, a + 0.5, epsilon);
-        Arc     arc     = new Arc(a + 0.5 * epsilon, a + 1, epsilon);
-        ArcsSet.Split split = set.split(arc);
-        Assert.assertNotNull(split.getMinus());
-        Assert.assertNull(split.getPlus());
-        Assert.assertEquals(Side.MINUS, set.split(arc).getSide());
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/spherical/oned/LimitAngleTest.java b/src/test/java/org/apache/commons/math4/geometry/spherical/oned/LimitAngleTest.java
deleted file mode 100644
index eb50bd9..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/spherical/oned/LimitAngleTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.spherical.oned;
-
-import org.apache.commons.math4.geometry.spherical.oned.LimitAngle;
-import org.apache.commons.math4.geometry.spherical.oned.S1Point;
-import org.apache.commons.math4.util.MathUtils;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class LimitAngleTest {
-
-    @Test
-    public void testReversedLimit() {
-        for (int k = -2; k < 3; ++k) {
-            LimitAngle l  = new LimitAngle(new S1Point(1.0 + k * MathUtils.TWO_PI), false, 1.0e-10);
-            Assert.assertEquals(l.getLocation().getAlpha(), l.getReverse().getLocation().getAlpha(), 1.0e-10);
-            Assert.assertEquals(l.getTolerance(), l.getReverse().getTolerance(), 1.0e-10);
-            Assert.assertTrue(l.sameOrientationAs(l));
-            Assert.assertFalse(l.sameOrientationAs(l.getReverse()));
-            Assert.assertEquals(MathUtils.TWO_PI, l.wholeSpace().getSize(), 1.0e-10);
-            Assert.assertEquals(MathUtils.TWO_PI, l.getReverse().wholeSpace().getSize(), 1.0e-10);
-        }
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/spherical/oned/S1PointTest.java b/src/test/java/org/apache/commons/math4/geometry/spherical/oned/S1PointTest.java
deleted file mode 100644
index 4356f31..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/spherical/oned/S1PointTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.spherical.oned;
-
-import org.apache.commons.math4.exception.MathUnsupportedOperationException;
-import org.apache.commons.math4.geometry.spherical.oned.S1Point;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class S1PointTest {
-
-    @Test
-    public void testS1Point() {
-        for (int k = -2; k < 3; ++k) {
-            S1Point p = new S1Point(1.0 + k * MathUtils.TWO_PI);
-            Assert.assertEquals(FastMath.cos(1.0), p.getVector().getX(), 1.0e-10);
-            Assert.assertEquals(FastMath.sin(1.0), p.getVector().getY(), 1.0e-10);
-            Assert.assertFalse(p.isNaN());
-        }
-    }
-
-    @Test
-    public void testNaN() {
-        Assert.assertTrue(S1Point.NaN.isNaN());
-        Assert.assertTrue(S1Point.NaN.equals(new S1Point(Double.NaN)));
-        Assert.assertFalse(new S1Point(1.0).equals(S1Point.NaN));
-    }
-
-    @Test
-    public void testEquals() {
-        S1Point a = new S1Point(1.0);
-        S1Point b = new S1Point(1.0);
-        Assert.assertEquals(a.hashCode(), b.hashCode());
-        Assert.assertFalse(a == b);
-        Assert.assertTrue(a.equals(b));
-        Assert.assertTrue(a.equals(a));
-        Assert.assertFalse(a.equals('a'));
-    }
-
-    @Test
-    public void testDistance() {
-        S1Point a = new S1Point(1.0);
-        S1Point b = new S1Point(a.getAlpha() + 0.5 * FastMath.PI);
-        Assert.assertEquals(0.5 * FastMath.PI, a.distance(b), 1.0e-10);
-    }
-
-    @Test
-    public void testSpace() {
-        S1Point a = new S1Point(1.0);
-        Assert.assertTrue(a.getSpace() instanceof Sphere1D);
-        Assert.assertEquals(1, a.getSpace().getDimension());
-        try {
-            a.getSpace().getSubSpace();
-            Assert.fail("an exception should have been thrown");
-        } catch (MathUnsupportedOperationException muoe) {
-            // expected
-        }
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/spherical/oned/Sphere1Test.java b/src/test/java/org/apache/commons/math4/geometry/spherical/oned/Sphere1Test.java
deleted file mode 100644
index e137f14..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/spherical/oned/Sphere1Test.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.spherical.oned;
-
-import org.apache.commons.math4.TestUtils;
-import org.apache.commons.math4.geometry.Space;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class Sphere1Test {
-
-    @Test
-    public void testDimension() {
-        Assert.assertEquals(1, Sphere1D.getInstance().getDimension());
-    }
-
-    @Test(expected=Sphere1D.NoSubSpaceException.class)
-    public void testSubSpace() {
-        Sphere1D.getInstance().getSubSpace();
-    }
-
-    @Test
-    public void testSerialization() {
-        Space s1 = Sphere1D.getInstance();
-        Space deserialized = (Space) TestUtils.serializeAndRecover(s1);
-        Assert.assertTrue(s1 == deserialized);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/spherical/twod/CircleTest.java b/src/test/java/org/apache/commons/math4/geometry/spherical/twod/CircleTest.java
deleted file mode 100644
index 0cc3d70..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/spherical/twod/CircleTest.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.apache.commons.rng.UniformRandomProvider;
-import org.apache.commons.rng.simple.RandomSource;
-import org.apache.commons.rng.sampling.UnitSphereSampler;
-import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
-import org.apache.commons.math4.geometry.euclidean.threed.RotationConvention;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.geometry.partitioning.Transform;
-import org.apache.commons.math4.geometry.spherical.oned.Arc;
-import org.apache.commons.math4.geometry.spherical.oned.LimitAngle;
-import org.apache.commons.math4.geometry.spherical.oned.S1Point;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.apache.commons.math4.geometry.spherical.oned.SubLimitAngle;
-import org.apache.commons.math4.geometry.spherical.twod.Circle;
-import org.apache.commons.math4.geometry.spherical.twod.S2Point;
-import org.apache.commons.math4.geometry.spherical.twod.Sphere2D;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-
-public class CircleTest {
-
-    @Test
-    public void testEquator() {
-        Circle circle = new Circle(new Cartesian3D(0, 0, 1000), 1.0e-10).copySelf();
-        Assert.assertEquals(Cartesian3D.PLUS_K, circle.getPole());
-        Assert.assertEquals(1.0e-10, circle.getTolerance(), 1.0e-20);
-        circle.revertSelf();
-        Assert.assertEquals(Cartesian3D.MINUS_K, circle.getPole());
-        Assert.assertEquals(Cartesian3D.PLUS_K, circle.getReverse().getPole());
-        Assert.assertEquals(Cartesian3D.MINUS_K, circle.getPole());
-    }
-
-    @Test
-    public void testXY() {
-        Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10);
-        Assert.assertEquals(0.0, circle.getPointAt(0).distance(circle.getXAxis()), 1.0e-10);
-        Assert.assertEquals(0.0, circle.getPointAt(0.5 * FastMath.PI).distance(circle.getYAxis()), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, Cartesian3D.angle(circle.getXAxis(), circle.getYAxis()), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, Cartesian3D.angle(circle.getXAxis(), circle.getPole()), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, Cartesian3D.angle(circle.getPole(), circle.getYAxis()), 1.0e-10);
-        Assert.assertEquals(0.0,
-                            circle.getPole().distance(Cartesian3D.crossProduct(circle.getXAxis(), circle.getYAxis())),
-                            1.0e-10);
-    }
-
-    @Test
-    public void testReverse() {
-        Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10);
-        Circle reversed = circle.getReverse();
-        Assert.assertEquals(0.0, reversed.getPointAt(0).distance(reversed.getXAxis()), 1.0e-10);
-        Assert.assertEquals(0.0, reversed.getPointAt(0.5 * FastMath.PI).distance(reversed.getYAxis()), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, Cartesian3D.angle(reversed.getXAxis(), reversed.getYAxis()), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, Cartesian3D.angle(reversed.getXAxis(), reversed.getPole()), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, Cartesian3D.angle(reversed.getPole(), reversed.getYAxis()), 1.0e-10);
-        Assert.assertEquals(0.0,
-                            reversed.getPole().distance(Cartesian3D.crossProduct(reversed.getXAxis(), reversed.getYAxis())),
-                            1.0e-10);
-
-        Assert.assertEquals(0, Cartesian3D.angle(circle.getXAxis(), reversed.getXAxis()), 1.0e-10);
-        Assert.assertEquals(FastMath.PI, Cartesian3D.angle(circle.getYAxis(), reversed.getYAxis()), 1.0e-10);
-        Assert.assertEquals(FastMath.PI, Cartesian3D.angle(circle.getPole(), reversed.getPole()), 1.0e-10);
-
-        Assert.assertTrue(circle.sameOrientationAs(circle));
-        Assert.assertFalse(circle.sameOrientationAs(reversed));
-
-    }
-
-    @Test
-    public void testPhase() {
-        Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10);
-        Cartesian3D p = new Cartesian3D(1, 2, -4);
-        Cartesian3D samePhase = circle.getPointAt(circle.getPhase(p));
-        Assert.assertEquals(0.0,
-                            Cartesian3D.angle(Cartesian3D.crossProduct(circle.getPole(), p),
-                                           Cartesian3D.crossProduct(circle.getPole(), samePhase)),
-                            1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, Cartesian3D.angle(circle.getPole(), samePhase), 1.0e-10);
-        Assert.assertEquals(circle.getPhase(p), circle.getPhase(samePhase), 1.0e-10);
-        Assert.assertEquals(0.0, circle.getPhase(circle.getXAxis()), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, circle.getPhase(circle.getYAxis()), 1.0e-10);
-
-    }
-
-    @Test
-    public void testSubSpace() {
-        Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10);
-        Assert.assertEquals(0.0, circle.toSubSpace(new S2Point(circle.getXAxis())).getAlpha(), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, circle.toSubSpace(new S2Point(circle.getYAxis())).getAlpha(), 1.0e-10);
-        Cartesian3D p = new Cartesian3D(1, 2, -4);
-        Assert.assertEquals(circle.getPhase(p), circle.toSubSpace(new S2Point(p)).getAlpha(), 1.0e-10);
-    }
-
-    @Test
-    public void testSpace() {
-        Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10);
-        for (double alpha = 0; alpha < MathUtils.TWO_PI; alpha += 0.1) {
-            Cartesian3D p = new Cartesian3D(FastMath.cos(alpha), circle.getXAxis(),
-                                      FastMath.sin(alpha), circle.getYAxis());
-            Cartesian3D q = circle.toSpace(new S1Point(alpha)).getVector();
-            Assert.assertEquals(0.0, p.distance(q), 1.0e-10);
-            Assert.assertEquals(0.5 * FastMath.PI, Cartesian3D.angle(circle.getPole(), q), 1.0e-10);
-        }
-    }
-
-    @Test
-    public void testOffset() {
-        Circle circle = new Circle(Cartesian3D.PLUS_K, 1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(new S2Point(Cartesian3D.PLUS_I)),  1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(new S2Point(Cartesian3D.MINUS_I)), 1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(new S2Point(Cartesian3D.PLUS_J)),  1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(new S2Point(Cartesian3D.MINUS_J)), 1.0e-10);
-        Assert.assertEquals(-0.5 * FastMath.PI, circle.getOffset(new S2Point(Cartesian3D.PLUS_K)),  1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, circle.getOffset(new S2Point(Cartesian3D.MINUS_K)), 1.0e-10);
-
-    }
-
-    @Test
-    public void testInsideArc() {
-        UnitSphereSampler sphRandom = new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
-                                                                                   0xbfd34e92231bbcfel));
-        for (int i = 0; i < 100; ++i) {
-            Circle c1 = new Circle(new Cartesian3D(sphRandom.nextVector()), 1.0e-10);
-            Circle c2 = new Circle(new Cartesian3D(sphRandom.nextVector()), 1.0e-10);
-            checkArcIsInside(c1, c2);
-            checkArcIsInside(c2, c1);
-        }
-    }
-
-    private void checkArcIsInside(final Circle arcCircle, final Circle otherCircle) {
-        Arc arc = arcCircle.getInsideArc(otherCircle);
-        Assert.assertEquals(FastMath.PI, arc.getSize(), 1.0e-10);
-        for (double alpha = arc.getInf(); alpha < arc.getSup(); alpha += 0.1) {
-            Assert.assertTrue(otherCircle.getOffset(arcCircle.getPointAt(alpha)) <= 2.0e-15);
-        }
-        for (double alpha = arc.getSup(); alpha < arc.getInf() + MathUtils.TWO_PI; alpha += 0.1) {
-            Assert.assertTrue(otherCircle.getOffset(arcCircle.getPointAt(alpha)) >= -2.0e-15);
-        }
-    }
-
-    @Test
-    public void testTransform() {
-        UniformRandomProvider random = RandomSource.create(RandomSource.WELL_1024_A,
-                                                           0x16992fc4294bf2f1l);
-        UnitSphereSampler sphRandom = new UnitSphereSampler(3, random);
-        for (int i = 0; i < 100; ++i) {
-
-            Rotation r = new Rotation(new Cartesian3D(sphRandom.nextVector()),
-                                      FastMath.PI * random.nextDouble(),
-                                      RotationConvention.VECTOR_OPERATOR);
-            Transform<Sphere2D, Sphere1D> t = Circle.getTransform(r);
-
-            S2Point  p = new S2Point(new Cartesian3D(sphRandom.nextVector()));
-            S2Point tp = (S2Point) t.apply(p);
-            Assert.assertEquals(0.0, r.applyTo(p.getVector()).distance(tp.getVector()), 1.0e-10);
-
-            Circle  c = new Circle(new Cartesian3D(sphRandom.nextVector()), 1.0e-10);
-            Circle tc = (Circle) t.apply(c);
-            Assert.assertEquals(0.0, r.applyTo(c.getPole()).distance(tc.getPole()),   1.0e-10);
-            Assert.assertEquals(0.0, r.applyTo(c.getXAxis()).distance(tc.getXAxis()), 1.0e-10);
-            Assert.assertEquals(0.0, r.applyTo(c.getYAxis()).distance(tc.getYAxis()), 1.0e-10);
-            Assert.assertEquals(c.getTolerance(), ((Circle) t.apply(c)).getTolerance(), 1.0e-10);
-
-            SubLimitAngle  sub = new LimitAngle(new S1Point(MathUtils.TWO_PI * random.nextDouble()),
-                                                random.nextBoolean(), 1.0e-10).wholeHyperplane();
-            Cartesian3D psub = c.getPointAt(((LimitAngle) sub.getHyperplane()).getLocation().getAlpha());
-            SubLimitAngle tsub = (SubLimitAngle) t.apply(sub, c, tc);
-            Cartesian3D ptsub = tc.getPointAt(((LimitAngle) tsub.getHyperplane()).getLocation().getAlpha());
-            Assert.assertEquals(0.0, r.applyTo(psub).distance(ptsub), 1.0e-10);
-
-        }
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/spherical/twod/S2PointTest.java b/src/test/java/org/apache/commons/math4/geometry/spherical/twod/S2PointTest.java
deleted file mode 100644
index 2b410bd..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/spherical/twod/S2PointTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import org.apache.commons.math4.exception.OutOfRangeException;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.apache.commons.math4.geometry.spherical.twod.S2Point;
-import org.apache.commons.math4.geometry.spherical.twod.Sphere2D;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class S2PointTest {
-
-
-    @Test
-    public void testS2Point() {
-        for (int k = -2; k < 3; ++k) {
-            S2Point p = new S2Point(1.0 + k * MathUtils.TWO_PI, 1.4);
-            Assert.assertEquals(1.0 + k * MathUtils.TWO_PI, p.getTheta(), 1.0e-10);
-            Assert.assertEquals(1.4, p.getPhi(), 1.0e-10);
-            Assert.assertEquals(FastMath.cos(1.0) * FastMath.sin(1.4), p.getVector().getX(), 1.0e-10);
-            Assert.assertEquals(FastMath.sin(1.0) * FastMath.sin(1.4), p.getVector().getY(), 1.0e-10);
-            Assert.assertEquals(FastMath.cos(1.4), p.getVector().getZ(), 1.0e-10);
-            Assert.assertFalse(p.isNaN());
-        }
-    }
-
-    @Test(expected=OutOfRangeException.class)
-    public void testNegativePolarAngle() {
-        new S2Point(1.0, -1.0);
-    }
-
-    @Test(expected=OutOfRangeException.class)
-    public void testTooLargePolarAngle() {
-        new S2Point(1.0, 3.5);
-    }
-
-    @Test
-    public void testNaN() {
-        Assert.assertTrue(S2Point.NaN.isNaN());
-        Assert.assertTrue(S2Point.NaN.equals(new S2Point(Double.NaN, 1.0)));
-        Assert.assertFalse(new S2Point(1.0, 1.3).equals(S2Point.NaN));
-    }
-
-    @Test
-    public void testEquals() {
-        S2Point a = new S2Point(1.0, 1.0);
-        S2Point b = new S2Point(1.0, 1.0);
-        Assert.assertEquals(a.hashCode(), b.hashCode());
-        Assert.assertFalse(a == b);
-        Assert.assertTrue(a.equals(b));
-        Assert.assertTrue(a.equals(a));
-        Assert.assertFalse(a.equals('a'));
-    }
-
-    @Test
-    public void testDistance() {
-        S2Point a = new S2Point(1.0, 0.5 * FastMath.PI);
-        S2Point b = new S2Point(a.getTheta() + 0.5 * FastMath.PI, a.getPhi());
-        Assert.assertEquals(0.5 * FastMath.PI, a.distance(b), 1.0e-10);
-        Assert.assertEquals(FastMath.PI, a.distance(a.negate()), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, S2Point.MINUS_I.distance(S2Point.MINUS_K), 1.0e-10);
-        Assert.assertEquals(0.0, new S2Point(1.0, 0).distance(new S2Point(2.0, 0)), 1.0e-10);
-    }
-
-    @Test
-    public void testSpace() {
-        S2Point a = new S2Point(1.0, 1.0);
-        Assert.assertTrue(a.getSpace() instanceof Sphere2D);
-        Assert.assertEquals(2, a.getSpace().getDimension());
-        Assert.assertTrue(a.getSpace().getSubSpace() instanceof Sphere1D);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/spherical/twod/SphericalPolygonsSetTest.java b/src/test/java/org/apache/commons/math4/geometry/spherical/twod/SphericalPolygonsSetTest.java
deleted file mode 100644
index 74bcf6f..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/spherical/twod/SphericalPolygonsSetTest.java
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.junit.Assert;
-import org.junit.Test;
-import org.apache.commons.rng.UniformRandomProvider;
-import org.apache.commons.rng.simple.RandomSource;
-import org.apache.commons.rng.sampling.UnitSphereSampler;
-import org.apache.commons.math4.geometry.enclosing.EnclosingBall;
-import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.geometry.partitioning.RegionFactory;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
-import org.apache.commons.math4.geometry.partitioning.Region.Location;
-import org.apache.commons.math4.geometry.spherical.oned.ArcsSet;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.apache.commons.math4.geometry.spherical.twod.Circle;
-import org.apache.commons.math4.geometry.spherical.twod.Edge;
-import org.apache.commons.math4.geometry.spherical.twod.S2Point;
-import org.apache.commons.math4.geometry.spherical.twod.Sphere2D;
-import org.apache.commons.math4.geometry.spherical.twod.SphericalPolygonsSet;
-import org.apache.commons.math4.geometry.spherical.twod.SubCircle;
-import org.apache.commons.math4.geometry.spherical.twod.Vertex;
-import org.apache.commons.math4.util.FastMath;
-import org.apache.commons.math4.util.MathUtils;
-
-public class SphericalPolygonsSetTest {
-
-    @Test
-    public void testFullSphere() {
-        SphericalPolygonsSet full = new SphericalPolygonsSet(1.0e-10);
-        UnitSphereSampler random =
-                new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
-                                                             0x852fd2a0ed8d2f6dl));
-        for (int i = 0; i < 1000; ++i) {
-            Cartesian3D v = new Cartesian3D(random.nextVector());
-            Assert.assertEquals(Location.INSIDE, full.checkPoint(new S2Point(v)));
-        }
-        Assert.assertEquals(4 * FastMath.PI, new SphericalPolygonsSet(0.01, new S2Point[0]).getSize(), 1.0e-10);
-        Assert.assertEquals(0, new SphericalPolygonsSet(0.01, new S2Point[0]).getBoundarySize(), 1.0e-10);
-        Assert.assertEquals(0, full.getBoundaryLoops().size());
-        Assert.assertTrue(full.getEnclosingCap().getRadius() > 0);
-        Assert.assertTrue(Double.isInfinite(full.getEnclosingCap().getRadius()));
-    }
-
-    @Test
-    public void testEmpty() {
-        SphericalPolygonsSet empty =
-            (SphericalPolygonsSet) new RegionFactory<Sphere2D>().getComplement(new SphericalPolygonsSet(1.0e-10));
-        UnitSphereSampler random =
-                new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
-                                                             0x76d9205d6167b6ddl));
-        for (int i = 0; i < 1000; ++i) {
-            Cartesian3D v = new Cartesian3D(random.nextVector());
-            Assert.assertEquals(Location.OUTSIDE, empty.checkPoint(new S2Point(v)));
-        }
-        Assert.assertEquals(0, empty.getSize(), 1.0e-10);
-        Assert.assertEquals(0, empty.getBoundarySize(), 1.0e-10);
-        Assert.assertEquals(0, empty.getBoundaryLoops().size());
-        Assert.assertTrue(empty.getEnclosingCap().getRadius() < 0);
-        Assert.assertTrue(Double.isInfinite(empty.getEnclosingCap().getRadius()));
-    }
-
-    @Test
-    public void testSouthHemisphere() {
-        double tol = 0.01;
-        double sinTol = FastMath.sin(tol);
-        SphericalPolygonsSet south = new SphericalPolygonsSet(Cartesian3D.MINUS_K, tol);
-        UnitSphereSampler random =
-                new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
-                                                             0x6b9d4a6ad90d7b0bl));
-        for (int i = 0; i < 1000; ++i) {
-            Cartesian3D v = new Cartesian3D(random.nextVector());
-            if (v.getZ() < -sinTol) {
-                Assert.assertEquals(Location.INSIDE, south.checkPoint(new S2Point(v)));
-            } else if (v.getZ() > sinTol) {
-                Assert.assertEquals(Location.OUTSIDE, south.checkPoint(new S2Point(v)));
-            } else {
-                Assert.assertEquals(Location.BOUNDARY, south.checkPoint(new S2Point(v)));
-            }
-        }
-        Assert.assertEquals(1, south.getBoundaryLoops().size());
-
-        EnclosingBall<Sphere2D, S2Point> southCap = south.getEnclosingCap();
-        Assert.assertEquals(0.0, S2Point.MINUS_K.distance(southCap.getCenter()), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, southCap.getRadius(), 1.0e-10);
-
-        EnclosingBall<Sphere2D, S2Point> northCap =
-                ((SphericalPolygonsSet) new RegionFactory<Sphere2D>().getComplement(south)).getEnclosingCap();
-        Assert.assertEquals(0.0, S2Point.PLUS_K.distance(northCap.getCenter()), 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, northCap.getRadius(), 1.0e-10);
-
-    }
-
-    @Test
-    public void testPositiveOctantByIntersection() {
-        double tol = 0.01;
-        double sinTol = FastMath.sin(tol);
-        RegionFactory<Sphere2D> factory = new RegionFactory<>();
-        SphericalPolygonsSet plusX = new SphericalPolygonsSet(Cartesian3D.PLUS_I, tol);
-        SphericalPolygonsSet plusY = new SphericalPolygonsSet(Cartesian3D.PLUS_J, tol);
-        SphericalPolygonsSet plusZ = new SphericalPolygonsSet(Cartesian3D.PLUS_K, tol);
-        SphericalPolygonsSet octant =
-                (SphericalPolygonsSet) factory.intersection(factory.intersection(plusX, plusY), plusZ);
-        UnitSphereSampler random =
-                new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
-                                                             0x9c9802fde3cbcf25l));
-        for (int i = 0; i < 1000; ++i) {
-            Cartesian3D v = new Cartesian3D(random.nextVector());
-            if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) {
-                Assert.assertEquals(Location.INSIDE, octant.checkPoint(new S2Point(v)));
-            } else if ((v.getX() < -sinTol) || (v.getY() < -sinTol) || (v.getZ() < -sinTol)) {
-                Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(new S2Point(v)));
-            } else {
-                Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(new S2Point(v)));
-            }
-        }
-
-        List<Vertex> loops = octant.getBoundaryLoops();
-        Assert.assertEquals(1, loops.size());
-        boolean xPFound = false;
-        boolean yPFound = false;
-        boolean zPFound = false;
-        boolean xVFound = false;
-        boolean yVFound = false;
-        boolean zVFound = false;
-        Vertex first = loops.get(0);
-        int count = 0;
-        for (Vertex v = first; count == 0 || v != first; v = v.getOutgoing().getEnd()) {
-            ++count;
-            Edge e = v.getIncoming();
-            Assert.assertTrue(v == e.getStart().getOutgoing().getEnd());
-            xPFound = xPFound || e.getCircle().getPole().distance(Cartesian3D.PLUS_I) < 1.0e-10;
-            yPFound = yPFound || e.getCircle().getPole().distance(Cartesian3D.PLUS_J) < 1.0e-10;
-            zPFound = zPFound || e.getCircle().getPole().distance(Cartesian3D.PLUS_K) < 1.0e-10;
-            Assert.assertEquals(0.5 * FastMath.PI, e.getLength(), 1.0e-10);
-            xVFound = xVFound || v.getLocation().getVector().distance(Cartesian3D.PLUS_I) < 1.0e-10;
-            yVFound = yVFound || v.getLocation().getVector().distance(Cartesian3D.PLUS_J) < 1.0e-10;
-            zVFound = zVFound || v.getLocation().getVector().distance(Cartesian3D.PLUS_K) < 1.0e-10;
-        }
-        Assert.assertTrue(xPFound);
-        Assert.assertTrue(yPFound);
-        Assert.assertTrue(zPFound);
-        Assert.assertTrue(xVFound);
-        Assert.assertTrue(yVFound);
-        Assert.assertTrue(zVFound);
-        Assert.assertEquals(3, count);
-
-        Assert.assertEquals(0.0,
-                            ((S2Point) octant.getBarycenter()).distance(new S2Point(new Cartesian3D(1, 1, 1))),
-                            1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, octant.getSize(), 1.0e-10);
-
-        EnclosingBall<Sphere2D, S2Point> cap = octant.getEnclosingCap();
-        Assert.assertEquals(0.0, octant.getBarycenter().distance(cap.getCenter()), 1.0e-10);
-        Assert.assertEquals(FastMath.acos(1.0 / FastMath.sqrt(3)), cap.getRadius(), 1.0e-10);
-
-        EnclosingBall<Sphere2D, S2Point> reversedCap =
-                ((SphericalPolygonsSet) factory.getComplement(octant)).getEnclosingCap();
-        Assert.assertEquals(0, reversedCap.getCenter().distance(new S2Point(new Cartesian3D(-1, -1, -1))), 1.0e-10);
-        Assert.assertEquals(FastMath.PI - FastMath.asin(1.0 / FastMath.sqrt(3)), reversedCap.getRadius(), 1.0e-10);
-
-    }
-
-    @Test
-    public void testPositiveOctantByVertices() {
-        double tol = 0.01;
-        double sinTol = FastMath.sin(tol);
-        SphericalPolygonsSet octant = new SphericalPolygonsSet(tol, S2Point.PLUS_I, S2Point.PLUS_J, S2Point.PLUS_K);
-        UnitSphereSampler random =
-                new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
-                                                             0xb8fc5acc91044308l));
-        for (int i = 0; i < 1000; ++i) {
-            Cartesian3D v = new Cartesian3D(random.nextVector());
-            if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) {
-                Assert.assertEquals(Location.INSIDE, octant.checkPoint(new S2Point(v)));
-            } else if ((v.getX() < -sinTol) || (v.getY() < -sinTol) || (v.getZ() < -sinTol)) {
-                Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(new S2Point(v)));
-            } else {
-                Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(new S2Point(v)));
-            }
-        }
-    }
-
-    @Test
-    public void testNonConvex() {
-        double tol = 0.01;
-        double sinTol = FastMath.sin(tol);
-        RegionFactory<Sphere2D> factory = new RegionFactory<>();
-        SphericalPolygonsSet plusX = new SphericalPolygonsSet(Cartesian3D.PLUS_I, tol);
-        SphericalPolygonsSet plusY = new SphericalPolygonsSet(Cartesian3D.PLUS_J, tol);
-        SphericalPolygonsSet plusZ = new SphericalPolygonsSet(Cartesian3D.PLUS_K, tol);
-        SphericalPolygonsSet threeOctants =
-                (SphericalPolygonsSet) factory.difference(plusZ, factory.intersection(plusX, plusY));
-
-        UnitSphereSampler random =
-                new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
-                                                             0x9c9802fde3cbcf25l));
-        for (int i = 0; i < 1000; ++i) {
-            Cartesian3D v = new Cartesian3D(random.nextVector());
-            if (((v.getX() < -sinTol) || (v.getY() < -sinTol)) && (v.getZ() > sinTol)) {
-                Assert.assertEquals(Location.INSIDE, threeOctants.checkPoint(new S2Point(v)));
-            } else if (((v.getX() > sinTol) && (v.getY() > sinTol)) || (v.getZ() < -sinTol)) {
-                Assert.assertEquals(Location.OUTSIDE, threeOctants.checkPoint(new S2Point(v)));
-            } else {
-                Assert.assertEquals(Location.BOUNDARY, threeOctants.checkPoint(new S2Point(v)));
-            }
-        }
-
-        List<Vertex> loops = threeOctants.getBoundaryLoops();
-        Assert.assertEquals(1, loops.size());
-        boolean xPFound = false;
-        boolean yPFound = false;
-        boolean zPFound = false;
-        boolean xVFound = false;
-        boolean yVFound = false;
-        boolean zVFound = false;
-        Vertex first = loops.get(0);
-        int count = 0;
-        double sumPoleX = 0;
-        double sumPoleY = 0;
-        double sumPoleZ = 0;
-        for (Vertex v = first; count == 0 || v != first; v = v.getOutgoing().getEnd()) {
-            ++count;
-            Edge e = v.getIncoming();
-            Assert.assertTrue(v == e.getStart().getOutgoing().getEnd());
-            if (e.getCircle().getPole().distance(Cartesian3D.MINUS_I) < 1.0e-10) {
-                xPFound = true;
-                sumPoleX += e.getLength();
-            } else if (e.getCircle().getPole().distance(Cartesian3D.MINUS_J) < 1.0e-10) {
-                yPFound = true;
-                sumPoleY += e.getLength();
-            } else {
-                Assert.assertEquals(0.0, e.getCircle().getPole().distance(Cartesian3D.PLUS_K), 1.0e-10);
-                zPFound = true;
-                sumPoleZ += e.getLength();
-            }
-            xVFound = xVFound || v.getLocation().getVector().distance(Cartesian3D.PLUS_I) < 1.0e-10;
-            yVFound = yVFound || v.getLocation().getVector().distance(Cartesian3D.PLUS_J) < 1.0e-10;
-            zVFound = zVFound || v.getLocation().getVector().distance(Cartesian3D.PLUS_K) < 1.0e-10;
-        }
-        Assert.assertTrue(xPFound);
-        Assert.assertTrue(yPFound);
-        Assert.assertTrue(zPFound);
-        Assert.assertTrue(xVFound);
-        Assert.assertTrue(yVFound);
-        Assert.assertTrue(zVFound);
-        Assert.assertEquals(0.5 * FastMath.PI, sumPoleX, 1.0e-10);
-        Assert.assertEquals(0.5 * FastMath.PI, sumPoleY, 1.0e-10);
-        Assert.assertEquals(1.5 * FastMath.PI, sumPoleZ, 1.0e-10);
-
-        Assert.assertEquals(1.5 * FastMath.PI, threeOctants.getSize(), 1.0e-10);
-
-    }
-
-    @Test
-    public void testModeratlyComplexShape() {
-        double tol = 0.01;
-        List<SubHyperplane<Sphere2D>> boundary = new ArrayList<>();
-        boundary.add(create(Cartesian3D.MINUS_J, Cartesian3D.PLUS_I,  Cartesian3D.PLUS_K,  tol, 0.0, 0.5 * FastMath.PI));
-        boundary.add(create(Cartesian3D.MINUS_I, Cartesian3D.PLUS_K,  Cartesian3D.PLUS_J,  tol, 0.0, 0.5 * FastMath.PI));
-        boundary.add(create(Cartesian3D.PLUS_K,  Cartesian3D.PLUS_J,  Cartesian3D.MINUS_I, tol, 0.0, 0.5 * FastMath.PI));
-        boundary.add(create(Cartesian3D.MINUS_J, Cartesian3D.MINUS_I, Cartesian3D.MINUS_K, tol, 0.0, 0.5 * FastMath.PI));
-        boundary.add(create(Cartesian3D.MINUS_I, Cartesian3D.MINUS_K, Cartesian3D.MINUS_J, tol, 0.0, 0.5 * FastMath.PI));
-        boundary.add(create(Cartesian3D.PLUS_K,  Cartesian3D.MINUS_J, Cartesian3D.PLUS_I,  tol, 0.0, 0.5 * FastMath.PI));
-        SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, tol);
-
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Cartesian3D( 1,  1,  1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(new Cartesian3D(-1,  1,  1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(new Cartesian3D(-1, -1,  1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(new Cartesian3D( 1, -1,  1).normalize())));
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Cartesian3D( 1,  1, -1).normalize())));
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Cartesian3D(-1,  1, -1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(new Cartesian3D(-1, -1, -1).normalize())));
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Cartesian3D( 1, -1, -1).normalize())));
-
-        Assert.assertEquals(MathUtils.TWO_PI, polygon.getSize(), 1.0e-10);
-        Assert.assertEquals(3 * FastMath.PI, polygon.getBoundarySize(), 1.0e-10);
-
-        List<Vertex> loops = polygon.getBoundaryLoops();
-        Assert.assertEquals(1, loops.size());
-        boolean pXFound = false;
-        boolean mXFound = false;
-        boolean pYFound = false;
-        boolean mYFound = false;
-        boolean pZFound = false;
-        boolean mZFound = false;
-        Vertex first = loops.get(0);
-        int count = 0;
-        for (Vertex v = first; count == 0 || v != first; v = v.getOutgoing().getEnd()) {
-            ++count;
-            Edge e = v.getIncoming();
-            Assert.assertTrue(v == e.getStart().getOutgoing().getEnd());
-            pXFound = pXFound || v.getLocation().getVector().distance(Cartesian3D.PLUS_I)  < 1.0e-10;
-            mXFound = mXFound || v.getLocation().getVector().distance(Cartesian3D.MINUS_I) < 1.0e-10;
-            pYFound = pYFound || v.getLocation().getVector().distance(Cartesian3D.PLUS_J)  < 1.0e-10;
-            mYFound = mYFound || v.getLocation().getVector().distance(Cartesian3D.MINUS_J) < 1.0e-10;
-            pZFound = pZFound || v.getLocation().getVector().distance(Cartesian3D.PLUS_K)  < 1.0e-10;
-            mZFound = mZFound || v.getLocation().getVector().distance(Cartesian3D.MINUS_K) < 1.0e-10;
-            Assert.assertEquals(0.5 * FastMath.PI, e.getLength(), 1.0e-10);
-        }
-        Assert.assertTrue(pXFound);
-        Assert.assertTrue(mXFound);
-        Assert.assertTrue(pYFound);
-        Assert.assertTrue(mYFound);
-        Assert.assertTrue(pZFound);
-        Assert.assertTrue(mZFound);
-        Assert.assertEquals(6, count);
-
-    }
-
-    @Test
-    public void testSeveralParts() {
-        double tol = 0.01;
-        double sinTol = FastMath.sin(tol);
-        List<SubHyperplane<Sphere2D>> boundary = new ArrayList<>();
-
-        // first part: +X, +Y, +Z octant
-        boundary.add(create(Cartesian3D.PLUS_J,  Cartesian3D.PLUS_K,  Cartesian3D.PLUS_I,  tol, 0.0, 0.5 * FastMath.PI));
-        boundary.add(create(Cartesian3D.PLUS_K,  Cartesian3D.PLUS_I,  Cartesian3D.PLUS_J,  tol, 0.0, 0.5 * FastMath.PI));
-        boundary.add(create(Cartesian3D.PLUS_I,  Cartesian3D.PLUS_J,  Cartesian3D.PLUS_K,  tol, 0.0, 0.5 * FastMath.PI));
-
-        // first part: -X, -Y, -Z octant
-        boundary.add(create(Cartesian3D.MINUS_J, Cartesian3D.MINUS_I, Cartesian3D.MINUS_K, tol, 0.0, 0.5 * FastMath.PI));
-        boundary.add(create(Cartesian3D.MINUS_I, Cartesian3D.MINUS_K, Cartesian3D.MINUS_J, tol, 0.0, 0.5 * FastMath.PI));
-        boundary.add(create(Cartesian3D.MINUS_K, Cartesian3D.MINUS_J, Cartesian3D.MINUS_I,  tol, 0.0, 0.5 * FastMath.PI));
-
-        SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, tol);
-
-        UnitSphereSampler random =
-                new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
-                                                             0xcc5ce49949e0d3ecl));
-        for (int i = 0; i < 1000; ++i) {
-            Cartesian3D v = new Cartesian3D(random.nextVector());
-            if ((v.getX() < -sinTol) && (v.getY() < -sinTol) && (v.getZ() < -sinTol)) {
-                Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(v)));
-            } else if ((v.getX() < sinTol) && (v.getY() < sinTol) && (v.getZ() < sinTol)) {
-                Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(new S2Point(v)));
-            } else if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) {
-                Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(v)));
-            } else if ((v.getX() > -sinTol) && (v.getY() > -sinTol) && (v.getZ() > -sinTol)) {
-                Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(new S2Point(v)));
-            } else {
-                Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(v)));
-            }
-        }
-
-        Assert.assertEquals(FastMath.PI, polygon.getSize(), 1.0e-10);
-        Assert.assertEquals(3 * FastMath.PI, polygon.getBoundarySize(), 1.0e-10);
-
-        // there should be two separate boundary loops
-        Assert.assertEquals(2, polygon.getBoundaryLoops().size());
-
-    }
-
-    @Test
-    public void testPartWithHole() {
-        double tol = 0.01;
-        double alpha = 0.7;
-        S2Point center = new S2Point(new Cartesian3D(1, 1, 1));
-        SphericalPolygonsSet hexa = new SphericalPolygonsSet(center.getVector(), Cartesian3D.PLUS_K, alpha, 6, tol);
-        SphericalPolygonsSet hole  = new SphericalPolygonsSet(tol,
-                                                              new S2Point(FastMath.PI / 6, FastMath.PI / 3),
-                                                              new S2Point(FastMath.PI / 3, FastMath.PI / 3),
-                                                              new S2Point(FastMath.PI / 4, FastMath.PI / 6));
-        SphericalPolygonsSet hexaWithHole =
-                (SphericalPolygonsSet) new RegionFactory<Sphere2D>().difference(hexa, hole);
-
-        for (double phi = center.getPhi() - alpha + 0.1; phi < center.getPhi() + alpha - 0.1; phi += 0.07) {
-            Location l = hexaWithHole.checkPoint(new S2Point(FastMath.PI / 4, phi));
-            if (phi < FastMath.PI / 6 || phi > FastMath.PI / 3) {
-                Assert.assertEquals(Location.INSIDE,  l);
-            } else {
-                Assert.assertEquals(Location.OUTSIDE, l);
-            }
-        }
-
-        // there should be two separate boundary loops
-        Assert.assertEquals(2, hexaWithHole.getBoundaryLoops().size());
-
-        Assert.assertEquals(hexa.getBoundarySize() + hole.getBoundarySize(), hexaWithHole.getBoundarySize(), 1.0e-10);
-        Assert.assertEquals(hexa.getSize() - hole.getSize(), hexaWithHole.getSize(), 1.0e-10);
-
-    }
-
-    @Test
-    public void testConcentricSubParts() {
-        double tol = 0.001;
-        Cartesian3D center = new Cartesian3D(1, 1, 1);
-        SphericalPolygonsSet hexaOut   = new SphericalPolygonsSet(center, Cartesian3D.PLUS_K, 0.9,  6, tol);
-        SphericalPolygonsSet hexaIn    = new SphericalPolygonsSet(center, Cartesian3D.PLUS_K, 0.8,  6, tol);
-        SphericalPolygonsSet pentaOut  = new SphericalPolygonsSet(center, Cartesian3D.PLUS_K, 0.7,  5, tol);
-        SphericalPolygonsSet pentaIn   = new SphericalPolygonsSet(center, Cartesian3D.PLUS_K, 0.6,  5, tol);
-        SphericalPolygonsSet quadriOut = new SphericalPolygonsSet(center, Cartesian3D.PLUS_K, 0.5,  4, tol);
-        SphericalPolygonsSet quadriIn  = new SphericalPolygonsSet(center, Cartesian3D.PLUS_K, 0.4,  4, tol);
-        SphericalPolygonsSet triOut    = new SphericalPolygonsSet(center, Cartesian3D.PLUS_K, 0.25, 3, tol);
-        SphericalPolygonsSet triIn     = new SphericalPolygonsSet(center, Cartesian3D.PLUS_K, 0.15, 3, tol);
-
-        RegionFactory<Sphere2D> factory = new RegionFactory<>();
-        SphericalPolygonsSet hexa   = (SphericalPolygonsSet) factory.difference(hexaOut,   hexaIn);
-        SphericalPolygonsSet penta  = (SphericalPolygonsSet) factory.difference(pentaOut,  pentaIn);
-        SphericalPolygonsSet quadri = (SphericalPolygonsSet) factory.difference(quadriOut, quadriIn);
-        SphericalPolygonsSet tri    = (SphericalPolygonsSet) factory.difference(triOut,    triIn);
-        SphericalPolygonsSet concentric =
-                (SphericalPolygonsSet) factory.union(factory.union(hexa, penta), factory.union(quadri, tri));
-
-        // there should be two separate boundary loops
-        Assert.assertEquals(8, concentric.getBoundaryLoops().size());
-
-        Assert.assertEquals(hexaOut.getBoundarySize()   + hexaIn.getBoundarySize()   +
-                            pentaOut.getBoundarySize()  + pentaIn.getBoundarySize()  +
-                            quadriOut.getBoundarySize() + quadriIn.getBoundarySize() +
-                            triOut.getBoundarySize()    + triIn.getBoundarySize(),
-                            concentric.getBoundarySize(), 1.0e-10);
-        Assert.assertEquals(hexaOut.getSize()   - hexaIn.getSize()   +
-                            pentaOut.getSize()  - pentaIn.getSize()  +
-                            quadriOut.getSize() - quadriIn.getSize() +
-                            triOut.getSize()    - triIn.getSize(),
-                            concentric.getSize(), 1.0e-10);
-
-        // we expect lots of sign changes as we traverse all concentric rings
-        double phi = new S2Point(center).getPhi();
-        Assert.assertEquals(+0.207, concentric.projectToBoundary(new S2Point(-0.60,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(-0.048, concentric.projectToBoundary(new S2Point(-0.21,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(+0.027, concentric.projectToBoundary(new S2Point(-0.10,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(-0.041, concentric.projectToBoundary(new S2Point( 0.01,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(+0.049, concentric.projectToBoundary(new S2Point( 0.16,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(-0.038, concentric.projectToBoundary(new S2Point( 0.29,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(+0.097, concentric.projectToBoundary(new S2Point( 0.48,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(-0.022, concentric.projectToBoundary(new S2Point( 0.64,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(+0.072, concentric.projectToBoundary(new S2Point( 0.79,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(-0.022, concentric.projectToBoundary(new S2Point( 0.93,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(+0.091, concentric.projectToBoundary(new S2Point( 1.08,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(-0.037, concentric.projectToBoundary(new S2Point( 1.28,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(+0.051, concentric.projectToBoundary(new S2Point( 1.40,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(-0.041, concentric.projectToBoundary(new S2Point( 1.55,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(+0.027, concentric.projectToBoundary(new S2Point( 1.67,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(-0.044, concentric.projectToBoundary(new S2Point( 1.79,  phi)).getOffset(), 0.01);
-        Assert.assertEquals(+0.201, concentric.projectToBoundary(new S2Point( 2.16,  phi)).getOffset(), 0.01);
-
-    }
-
-    @Test
-    public void testGeographicalMap() {
-
-        SphericalPolygonsSet continental = buildSimpleZone(new double[][] {
-          { 51.14850,  2.51357 }, { 50.94660,  1.63900 }, { 50.12717,  1.33876 }, { 49.34737, -0.98946 },
-          { 49.77634, -1.93349 }, { 48.64442, -1.61651 }, { 48.90169, -3.29581 }, { 48.68416, -4.59234 },
-          { 47.95495, -4.49155 }, { 47.57032, -2.96327 }, { 46.01491, -1.19379 }, { 44.02261, -1.38422 },
-          { 43.42280, -1.90135 }, { 43.03401, -1.50277 }, { 42.34338,  1.82679 }, { 42.47301,  2.98599 },
-          { 43.07520,  3.10041 }, { 43.39965,  4.55696 }, { 43.12889,  6.52924 }, { 43.69384,  7.43518 },
-          { 44.12790,  7.54959 }, { 45.02851,  6.74995 }, { 45.33309,  7.09665 }, { 46.42967,  6.50009 },
-          { 46.27298,  6.02260 }, { 46.72577,  6.03738 }, { 47.62058,  7.46675 }, { 49.01778,  8.09927 },
-          { 49.20195,  6.65822 }, { 49.44266,  5.89775 }, { 49.98537,  4.79922 }
-        });
-        SphericalPolygonsSet corsica = buildSimpleZone(new double[][] {
-          { 42.15249,  9.56001 }, { 43.00998,  9.39000 }, { 42.62812,  8.74600 }, { 42.25651,  8.54421 },
-          { 41.58361,  8.77572 }, { 41.38000,  9.22975 }
-        });
-        RegionFactory<Sphere2D> factory = new RegionFactory<>();
-        SphericalPolygonsSet zone = (SphericalPolygonsSet) factory.union(continental, corsica);
-        EnclosingBall<Sphere2D, S2Point> enclosing = zone.getEnclosingCap();
-        Cartesian3D enclosingCenter = ((S2Point) enclosing.getCenter()).getVector();
-
-        double step = FastMath.toRadians(0.1);
-        for (Vertex loopStart : zone.getBoundaryLoops()) {
-            int count = 0;
-            for (Vertex v = loopStart; count == 0 || v != loopStart; v = v.getOutgoing().getEnd()) {
-                ++count;
-                for (int i = 0; i < FastMath.ceil(v.getOutgoing().getLength() / step); ++i) {
-                    Cartesian3D p = v.getOutgoing().getPointAt(i * step);
-                    Assert.assertTrue(Cartesian3D.angle(p, enclosingCenter) <= enclosing.getRadius());
-                }
-            }
-        }
-
-        S2Point supportPointA = s2Point(48.68416, -4.59234);
-        S2Point supportPointB = s2Point(41.38000,  9.22975);
-        Assert.assertEquals(enclosing.getRadius(), supportPointA.distance(enclosing.getCenter()), 1.0e-10);
-        Assert.assertEquals(enclosing.getRadius(), supportPointB.distance(enclosing.getCenter()), 1.0e-10);
-        Assert.assertEquals(0.5 * supportPointA.distance(supportPointB), enclosing.getRadius(), 1.0e-10);
-        Assert.assertEquals(2, enclosing.getSupportSize());
-
-        EnclosingBall<Sphere2D, S2Point> continentalInscribed =
-                ((SphericalPolygonsSet) factory.getComplement(continental)).getEnclosingCap();
-        Cartesian3D continentalCenter = ((S2Point) continentalInscribed.getCenter()).getVector();
-        Assert.assertEquals(2.2, FastMath.toDegrees(FastMath.PI - continentalInscribed.getRadius()), 0.1);
-        for (Vertex loopStart : continental.getBoundaryLoops()) {
-            int count = 0;
-            for (Vertex v = loopStart; count == 0 || v != loopStart; v = v.getOutgoing().getEnd()) {
-                ++count;
-                for (int i = 0; i < FastMath.ceil(v.getOutgoing().getLength() / step); ++i) {
-                    Cartesian3D p = v.getOutgoing().getPointAt(i * step);
-                    Assert.assertTrue(Cartesian3D.angle(p, continentalCenter) <= continentalInscribed.getRadius());
-                }
-            }
-        }
-
-        EnclosingBall<Sphere2D, S2Point> corsicaInscribed =
-                ((SphericalPolygonsSet) factory.getComplement(corsica)).getEnclosingCap();
-        Cartesian3D corsicaCenter = ((S2Point) corsicaInscribed.getCenter()).getVector();
-        Assert.assertEquals(0.34, FastMath.toDegrees(FastMath.PI - corsicaInscribed.getRadius()), 0.01);
-        for (Vertex loopStart : corsica.getBoundaryLoops()) {
-            int count = 0;
-            for (Vertex v = loopStart; count == 0 || v != loopStart; v = v.getOutgoing().getEnd()) {
-                ++count;
-                for (int i = 0; i < FastMath.ceil(v.getOutgoing().getLength() / step); ++i) {
-                    Cartesian3D p = v.getOutgoing().getPointAt(i * step);
-                    Assert.assertTrue(Cartesian3D.angle(p, corsicaCenter) <= corsicaInscribed.getRadius());
-                }
-            }
-        }
-
-    }
-
-    private SubCircle create(Cartesian3D pole, Cartesian3D x, Cartesian3D y,
-                             double tolerance, double ... limits) {
-        RegionFactory<Sphere1D> factory = new RegionFactory<>();
-        Circle circle = new Circle(pole, tolerance);
-        Circle phased =
-                (Circle) Circle.getTransform(new Rotation(circle.getXAxis(), circle.getYAxis(), x, y)).apply(circle);
-        ArcsSet set = (ArcsSet) factory.getComplement(new ArcsSet(tolerance));
-        for (int i = 0; i < limits.length; i += 2) {
-            set = (ArcsSet) factory.union(set, new ArcsSet(limits[i], limits[i + 1], tolerance));
-        }
-        return new SubCircle(phased, set);
-    }
-
-    private SphericalPolygonsSet buildSimpleZone(double[][] points) {
-        final S2Point[] vertices = new S2Point[points.length];
-        for (int i = 0; i < points.length; ++i) {
-            vertices[i] = s2Point(points[i][0], points[i][1]);
-        }
-        return new SphericalPolygonsSet(1.0e-10, vertices);
-    }
-
-    private S2Point s2Point(double latitude, double longitude) {
-        return new S2Point(FastMath.toRadians(longitude), FastMath.toRadians(90.0 - latitude));
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/geometry/spherical/twod/SubCircleTest.java b/src/test/java/org/apache/commons/math4/geometry/spherical/twod/SubCircleTest.java
deleted file mode 100644
index f3bfd8a..0000000
--- a/src/test/java/org/apache/commons/math4/geometry/spherical/twod/SubCircleTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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.spherical.twod;
-
-import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
-import org.apache.commons.math4.geometry.partitioning.RegionFactory;
-import org.apache.commons.math4.geometry.partitioning.Side;
-import org.apache.commons.math4.geometry.partitioning.SubHyperplane.SplitSubHyperplane;
-import org.apache.commons.math4.geometry.spherical.oned.ArcsSet;
-import org.apache.commons.math4.geometry.spherical.oned.Sphere1D;
-import org.apache.commons.math4.geometry.spherical.twod.Circle;
-import org.apache.commons.math4.geometry.spherical.twod.Sphere2D;
-import org.apache.commons.math4.geometry.spherical.twod.SubCircle;
-import org.apache.commons.math4.util.MathUtils;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SubCircleTest {
-
-    @Test
-    public void testFullCircle() {
-        Circle circle = new Circle(Cartesian3D.PLUS_K, 1.0e-10);
-        SubCircle set = circle.wholeHyperplane();
-        Assert.assertEquals(MathUtils.TWO_PI, set.getSize(), 1.0e-10);
-        Assert.assertTrue(circle == set.getHyperplane());
-        Assert.assertTrue(circle != set.copySelf().getHyperplane());
-    }
-
-    @Test
-    public void testSide() {
-
-        Circle xzPlane = new Circle(Cartesian3D.PLUS_J, 1.0e-10);
-
-        SubCircle sc1 = create(Cartesian3D.PLUS_K, Cartesian3D.PLUS_I, Cartesian3D.PLUS_J, 1.0e-10, 1.0, 3.0, 5.0, 6.0);
-        Assert.assertEquals(Side.BOTH, sc1.split(xzPlane).getSide());
-
-        SubCircle sc2 = create(Cartesian3D.PLUS_K, Cartesian3D.PLUS_I, Cartesian3D.PLUS_J, 1.0e-10, 1.0, 3.0);
-        Assert.assertEquals(Side.MINUS, sc2.split(xzPlane).getSide());
-
-        SubCircle sc3 = create(Cartesian3D.PLUS_K, Cartesian3D.PLUS_I, Cartesian3D.PLUS_J, 1.0e-10, 5.0, 6.0);
-        Assert.assertEquals(Side.PLUS, sc3.split(xzPlane).getSide());
-
-        SubCircle sc4 = create(Cartesian3D.PLUS_J, Cartesian3D.PLUS_K, Cartesian3D.PLUS_I, 1.0e-10, 5.0, 6.0);
-        Assert.assertEquals(Side.HYPER, sc4.split(xzPlane).getSide());
-
-        SubCircle sc5 = create(Cartesian3D.MINUS_J, Cartesian3D.PLUS_I, Cartesian3D.PLUS_K, 1.0e-10, 5.0, 6.0);
-        Assert.assertEquals(Side.HYPER, sc5.split(xzPlane).getSide());
-
-    }
-
-    @Test
-    public void testSPlit() {
-
-        Circle xzPlane = new Circle(Cartesian3D.PLUS_J, 1.0e-10);
-
-        SubCircle sc1 = create(Cartesian3D.PLUS_K, Cartesian3D.PLUS_I, Cartesian3D.PLUS_J, 1.0e-10, 1.0, 3.0, 5.0, 6.0);
-        SplitSubHyperplane<Sphere2D> split1 = sc1.split(xzPlane);
-        ArcsSet plus1  = (ArcsSet) ((SubCircle) split1.getPlus()).getRemainingRegion();
-        ArcsSet minus1 = (ArcsSet) ((SubCircle) split1.getMinus()).getRemainingRegion();
-        Assert.assertEquals(1, plus1.asList().size());
-        Assert.assertEquals(5.0, plus1.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, plus1.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(1, minus1.asList().size());
-        Assert.assertEquals(1.0, minus1.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, minus1.asList().get(0).getSup(), 1.0e-10);
-
-        SubCircle sc2 = create(Cartesian3D.PLUS_K, Cartesian3D.PLUS_I, Cartesian3D.PLUS_J, 1.0e-10, 1.0, 3.0);
-        SplitSubHyperplane<Sphere2D> split2 = sc2.split(xzPlane);
-        Assert.assertNull(split2.getPlus());
-        ArcsSet minus2 = (ArcsSet) ((SubCircle) split2.getMinus()).getRemainingRegion();
-        Assert.assertEquals(1, minus2.asList().size());
-        Assert.assertEquals(1.0, minus2.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, minus2.asList().get(0).getSup(), 1.0e-10);
-
-        SubCircle sc3 = create(Cartesian3D.PLUS_K, Cartesian3D.PLUS_I, Cartesian3D.PLUS_J, 1.0e-10, 5.0, 6.0);
-        SplitSubHyperplane<Sphere2D> split3 = sc3.split(xzPlane);
-        ArcsSet plus3  = (ArcsSet) ((SubCircle) split3.getPlus()).getRemainingRegion();
-        Assert.assertEquals(1, plus3.asList().size());
-        Assert.assertEquals(5.0, plus3.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, plus3.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertNull(split3.getMinus());
-
-        SubCircle sc4 = create(Cartesian3D.PLUS_J, Cartesian3D.PLUS_K, Cartesian3D.PLUS_I, 1.0e-10, 5.0, 6.0);
-        SplitSubHyperplane<Sphere2D> split4 = sc4.split(xzPlane);
-        Assert.assertEquals(Side.HYPER, sc4.split(xzPlane).getSide());
-        Assert.assertNull(split4.getPlus());
-        Assert.assertNull(split4.getMinus());
-
-        SubCircle sc5 = create(Cartesian3D.MINUS_J, Cartesian3D.PLUS_I, Cartesian3D.PLUS_K, 1.0e-10, 5.0, 6.0);
-        SplitSubHyperplane<Sphere2D> split5 = sc5.split(xzPlane);
-        Assert.assertEquals(Side.HYPER, sc5.split(xzPlane).getSide());
-        Assert.assertNull(split5.getPlus());
-        Assert.assertNull(split5.getMinus());
-
-    }
-
-    @Test
-    public void testSideSplitConsistency() {
-
-        double tolerance = 1.0e-6;
-        Circle hyperplane = new Circle(new Cartesian3D(9.738804529764676E-5, -0.6772824575010357, -0.7357230887208355),
-                                       tolerance);
-        SubCircle sub = new SubCircle(new Circle(new Cartesian3D(2.1793884139073498E-4, 0.9790647032675541, -0.20354915700704285),
-                                                 tolerance),
-                                      new ArcsSet(4.7121441684170700, 4.7125386635004760, tolerance));
-        SplitSubHyperplane<Sphere2D> split = sub.split(hyperplane);
-        Assert.assertNotNull(split.getMinus());
-        Assert.assertNull(split.getPlus());
-        Assert.assertEquals(Side.MINUS, sub.split(hyperplane).getSide());
-
-    }
-
-    private SubCircle create(Cartesian3D pole, Cartesian3D x, Cartesian3D y,
-                             double tolerance, double ... limits) {
-        RegionFactory<Sphere1D> factory = new RegionFactory<>();
-        Circle circle = new Circle(pole, tolerance);
-        Circle phased =
-                (Circle) Circle.getTransform(new Rotation(circle.getXAxis(), circle.getYAxis(), x, y)).apply(circle);
-        ArcsSet set = (ArcsSet) factory.getComplement(new ArcsSet(tolerance));
-        for (int i = 0; i < limits.length; i += 2) {
-            set = (ArcsSet) factory.union(set, new ArcsSet(limits[i], limits[i + 1], tolerance));
-        }
-        return new SubCircle(phased, set);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/MultiStartMultivariateOptimizerTest.java b/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/MultiStartMultivariateOptimizerTest.java
index 7128fcb..1ac321d 100644
--- a/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/MultiStartMultivariateOptimizerTest.java
+++ b/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/MultiStartMultivariateOptimizerTest.java
@@ -16,8 +16,8 @@
  */
 package org.apache.commons.math4.optim.nonlinear.scalar;
 
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.math4.analysis.MultivariateFunction;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
 import org.apache.commons.math4.optim.InitialGuess;
 import org.apache.commons.math4.optim.MaxEval;
 import org.apache.commons.math4.optim.PointValuePair;
@@ -72,7 +72,7 @@
         Assert.assertEquals(nbStarts, optima.length);
         for (PointValuePair o : optima) {
             // we check the results of all intermediate restarts here (there are 10 such results)
-            Cartesian2D center = new Cartesian2D(o.getPointRef()[0], o.getPointRef()[1]);
+            Vector2D center = Vector2D.of(o.getPointRef()[0], o.getPointRef()[1]);
             Assert.assertEquals(69.9597, circle.getRadius(center), 1e-3);
             Assert.assertEquals(96.07535, center.getX(), 1.4e-3);
             Assert.assertEquals(48.1349, center.getY(), 5e-3);
diff --git a/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/gradient/CircleScalar.java b/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/gradient/CircleScalar.java
index be0e494..cc1a7fb 100644
--- a/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/gradient/CircleScalar.java
+++ b/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/gradient/CircleScalar.java
@@ -19,9 +19,9 @@
 
 import java.util.ArrayList;
 
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.math4.analysis.MultivariateFunction;
 import org.apache.commons.math4.analysis.MultivariateVectorFunction;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
 import org.apache.commons.math4.optim.nonlinear.scalar.ObjectiveFunction;
 import org.apache.commons.math4.optim.nonlinear.scalar.ObjectiveFunctionGradient;
 
@@ -29,19 +29,19 @@
  * Class used in the tests.
  */
 public class CircleScalar {
-    private ArrayList<Cartesian2D> points;
+    private ArrayList<Vector2D> points;
 
     public CircleScalar() {
         points  = new ArrayList<>();
     }
 
     public void addPoint(double px, double py) {
-        points.add(new Cartesian2D(px, py));
+        points.add(Vector2D.of(px, py));
     }
 
-    public double getRadius(Cartesian2D center) {
+    public double getRadius(Vector2D center) {
         double r = 0;
-        for (Cartesian2D point : points) {
+        for (Vector2D point : points) {
             r += point.distance(center);
         }
         return r / points.size();
@@ -51,10 +51,10 @@
         return new ObjectiveFunction(new MultivariateFunction() {
                 @Override
                 public double value(double[] params)  {
-                    Cartesian2D center = new Cartesian2D(params[0], params[1]);
+                    Vector2D center = Vector2D.of(params[0], params[1]);
                     double radius = getRadius(center);
                     double sum = 0;
-                    for (Cartesian2D point : points) {
+                    for (Vector2D point : points) {
                         double di = point.distance(center) - radius;
                         sum += di * di;
                     }
@@ -67,12 +67,12 @@
         return new ObjectiveFunctionGradient(new MultivariateVectorFunction() {
                 @Override
                 public double[] value(double[] params) {
-                    Cartesian2D center = new Cartesian2D(params[0], params[1]);
+                    Vector2D center = Vector2D.of(params[0], params[1]);
                     double radius = getRadius(center);
                     // gradient of the sum of squared residuals
                     double dJdX = 0;
                     double dJdY = 0;
-                    for (Cartesian2D pk : points) {
+                    for (Vector2D pk : points) {
                         double dk = pk.distance(center);
                         dJdX += (center.getX() - pk.getX()) * (dk - radius) / dk;
                         dJdY += (center.getY() - pk.getY()) * (dk - radius) / dk;
diff --git a/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/gradient/NonLinearConjugateGradientOptimizerTest.java b/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/gradient/NonLinearConjugateGradientOptimizerTest.java
index df10e64..6c5a151 100644
--- a/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/gradient/NonLinearConjugateGradientOptimizerTest.java
+++ b/src/test/java/org/apache/commons/math4/optim/nonlinear/scalar/gradient/NonLinearConjugateGradientOptimizerTest.java
@@ -17,10 +17,10 @@
 
 package org.apache.commons.math4.optim.nonlinear.scalar.gradient;
 
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.math4.analysis.MultivariateFunction;
 import org.apache.commons.math4.analysis.MultivariateVectorFunction;
 import org.apache.commons.math4.exception.MathUnsupportedOperationException;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
 import org.apache.commons.math4.linear.BlockRealMatrix;
 import org.apache.commons.math4.linear.RealMatrix;
 import org.apache.commons.math4.optim.InitialGuess;
@@ -431,7 +431,7 @@
                                  problem.getObjectiveFunctionGradient(),
                                  GoalType.MINIMIZE,
                                  new InitialGuess(new double[] { 98.680, 47.345 }));
-        Cartesian2D center = new Cartesian2D(optimum.getPointRef()[0], optimum.getPointRef()[1]);
+        Vector2D center = Vector2D.of(optimum.getPointRef()[0], optimum.getPointRef()[1]);
         Assert.assertEquals(69.960161753, problem.getRadius(center), 1.0e-8);
         Assert.assertEquals(96.075902096, center.getX(), 1.0e-7);
         Assert.assertEquals(48.135167894, center.getY(), 1.0e-6);