You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2018/07/06 22:41:47 UTC

[commons-geometry] branch GEOMETRY-3__TBR created (now 2331c8a)

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

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


      at 2331c8a  GEOMETRY-3: simplifying parse and format functionality; renaming Coordinates.Factory?D interfaces to be more generic RealFunction interfaces

This branch includes the following new commits:

     new e97c535  GEOMETRY-3: making euclidean point and vector constructors private
     new f255ccc  GEOMETRY-3: adding generic coordinate format and parsing classes
     new aaf6960  GEOMETRY-3: adding euclidean parse methods; converting S1Point and S2Point to valjos; addressing some checkstyle issues
     new 519a17a  GEOMETRY-2: removing Serializable from top-level interface and placing at concrete class level, per issue comments
     new 6ecc77d  Merge branch 'master' into geometry-3
     new 9cdec03  GEOMETRY-3: replacing class internal use of factory method with calls to constructor
     new 7e50148  GEOMETRY-3: adding @FunctionalInterface to Coordinates.Factory?D interfaces
     new 2331c8a  GEOMETRY-3: simplifying parse and format functionality; renaming Coordinates.Factory?D interfaces to be more generic RealFunction interfaces

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



[commons-geometry] 03/08: GEOMETRY-3: adding euclidean parse methods; converting S1Point and S2Point to valjos; addressing some checkstyle issues

Posted by er...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit aaf6960e0d7ac9b9cfd616c3e8e4dedaaf080bd6
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Sat Jun 2 23:12:40 2018 -0400

    GEOMETRY-3: adding euclidean parse methods; converting S1Point and S2Point to valjos; addressing some checkstyle issues
---
 .../core/util/AbstractCoordinateParser.java        |  46 +++++---
 .../commons/geometry/core/util/Coordinates.java    |  30 ++---
 .../geometry/core/util/SimpleCoordinateFormat.java |  61 +++++++---
 .../commons/geometry/core/util/package-info.java   |  23 ++++
 .../core/util/SimpleCoordinateFormatTest.java      | 127 ++++++++++++--------
 .../commons/geometry/euclidean/oned/Point1D.java   |  31 ++++-
 .../commons/geometry/euclidean/oned/Vector1D.java  |  31 ++++-
 .../commons/geometry/euclidean/threed/Point3D.java |  31 ++++-
 .../geometry/euclidean/threed/Vector3D.java        |  33 +++++-
 .../commons/geometry/euclidean/twod/Point2D.java   |  31 ++++-
 .../commons/geometry/euclidean/twod/Vector2D.java  |  31 ++++-
 .../geometry/euclidean/oned/Point1DTest.java       |  32 +++++
 .../geometry/euclidean/oned/Vector1DTest.java      |  32 +++++
 .../geometry/euclidean/threed/Point3DTest.java     |  32 ++++-
 .../geometry/euclidean/threed/Vector3DTest.java    |  33 +++++-
 .../geometry/euclidean/twod/Point2DTest.java       |  32 ++++-
 .../geometry/euclidean/twod/Vector2DTest.java      |  33 +++++-
 .../commons/geometry/spherical/oned/ArcsSet.java   |  33 +++---
 .../commons/geometry/spherical/oned/S1Point.java   |  63 +++++++---
 .../commons/geometry/spherical/package-info.java   |  23 ++++
 .../commons/geometry/spherical/twod/Circle.java    |   7 +-
 .../commons/geometry/spherical/twod/Edge.java      |   6 +-
 .../geometry/spherical/twod/EdgesBuilder.java      |   4 +-
 .../spherical/twod/PropertiesComputer.java         |   2 +-
 .../commons/geometry/spherical/twod/S2Point.java   | 126 ++++++++++++--------
 .../spherical/twod/SphericalPolygonsSet.java       |  16 +--
 .../geometry/spherical/SphericalTestUtils.java     |   2 +-
 .../geometry/spherical/oned/ArcsSetTest.java       | 130 ++++++++++-----------
 .../geometry/spherical/oned/LimitAngleTest.java    |   2 +-
 .../geometry/spherical/oned/S1PointTest.java       |  56 +++++++--
 .../geometry/spherical/twod/CircleTest.java        |  34 +++---
 .../geometry/spherical/twod/S2PointTest.java       |  67 ++++++++---
 .../spherical/twod/SphericalPolygonsSetTest.java   | 106 ++++++++---------
 33 files changed, 984 insertions(+), 362 deletions(-)

diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java
index ec906bc..ceb8527 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java
@@ -114,7 +114,8 @@ public abstract class AbstractCoordinateParser {
             return value;
         }
         catch (NumberFormatException exc) {
-            throw new CoordinateParseException("Failed to parse number from string at index " + startIdx + ": " + substr, exc);
+            fail(String.format("unable to parse number from string \"%s\"", substr), str, pos, exc);
+            return 0.0; // for the compiler
         }
     }
 
@@ -133,8 +134,8 @@ public abstract class AbstractCoordinateParser {
         }
     }
 
-    /** Ends a parse operation by ensuring that all non-whitespace characters in the string have been parsed. An exception
-     * is thrown if extra content is found.
+    /** Ends a parse operation by ensuring that all non-whitespace characters in the string have been parsed. An
+     * exception is thrown if extra content is found.
      * @param str the string being parsed
      * @param pos the current parsing position
      * @throws IllegalArgumentException if extra non-whitespace content is found past the current parsing position
@@ -142,7 +143,7 @@ public abstract class AbstractCoordinateParser {
     protected void endParse(String str, ParsePosition pos) throws IllegalArgumentException {
         consumeWhitespace(str, pos);
         if (pos.getIndex() != str.length()) {
-            throw new CoordinateParseException("Failed to parse string: unexpected content at index " + pos.getIndex());
+            fail("unexpected content", str, pos);
         }
     }
 
@@ -209,11 +210,35 @@ public abstract class AbstractCoordinateParser {
             final int idx = pos.getIndex();
             final String actualSeq = str.substring(idx, Math.min(str.length(), idx + seq.length()));
 
-            throw new CoordinateParseException("Failed to parse string: expected \"" + seq +
-                    "\" but found \"" + actualSeq + "\" at index " + idx);
+            fail(String.format("expected \"%s\" but found \"%s\"", seq, actualSeq), str, pos);
         }
     }
 
+    /** Aborts the current parsing operation by throwing an {@link IllegalArgumentException} with an informative
+     * error message.
+     * @param msg the error message
+     * @param str the string being parsed
+     * @param pos the current parse position
+     * @throws IllegalArgumentException the exception signaling a parse failure
+     */
+    protected void fail(String msg, String str, ParsePosition pos) throws IllegalArgumentException {
+        fail(msg, str, pos, null);
+    }
+
+    /** Aborts the current parsing operation by throwing an {@link IllegalArgumentException} with an informative
+     * error message.
+     * @param msg the error message
+     * @param str the string being parsed
+     * @param pos the current parse position
+     * @param cause the original cause of the error
+     * @throws IllegalArgumentException the exception signaling a parse failure
+     */
+    protected void fail(String msg, String str, ParsePosition pos, Throwable cause) throws IllegalArgumentException {
+        String fullMsg = String.format("Failed to parse string \"%s\" at index %d: %s", str, pos.getIndex(), msg);
+
+        throw new CoordinateParseException(fullMsg, cause);
+    }
+
     /** Exception class for errors occurring during coordinate parsing.
      */
     private static class CoordinateParseException extends IllegalArgumentException {
@@ -222,17 +247,10 @@ public abstract class AbstractCoordinateParser {
         private static final long serialVersionUID = 1494716029613981959L;
 
         /** Simple constructor.
-         * @param msg the exception message.
-         */
-        public CoordinateParseException(String msg) {
-            super(msg);
-        }
-
-        /** Simple constructor with cause.
          * @param msg the exception message
          * @param cause the exception root cause
          */
-        public CoordinateParseException(String msg, Throwable cause) {
+        CoordinateParseException(String msg, Throwable cause) {
             super(msg, cause);
         }
     }
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java
index fcafd4f..8ea6c77 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java
@@ -20,43 +20,43 @@ package org.apache.commons.geometry.core.util;
  */
 public class Coordinates {
 
-    /** Interface for classes that create new instances of a type from a single coordinate value.
+    /** Interface for classes that create objects from a single coordinate value.
      * @param <T> The type created by this factory.
      */
-    public static interface Factory1D<T> {
+    public interface Factory1D<T> {
 
         /** Creates a new instance of type T from the given coordinate value.
-         * @param v the first coordinate value
+         * @param a the coordinate value
          * @return a new instance of type T
          */
-        T create(double v);
+        T create(double a);
     }
 
-    /** Interface for classes that create new instances of a type from two coordinate values.
+    /** Interface for classes that create objects from two coordinate values.
      * @param <T> The type created by this factory.
      */
-    public static interface Factory2D<T> {
+    public interface Factory2D<T> {
 
         /** Creates a new instance of type T from the given coordinate values.
-         * @param v1 the first coordinate value
-         * @param v2 the second coordinate value
+         * @param a1 the first coordinate value
+         * @param a2 the second coordinate value
          * @return a new instance of type T
          */
-        T create(double v1, double v2);
+        T create(double a1, double a2);
     }
 
-    /** Interface for classes that create new instances of a type from three coordinate values.
+    /** Interface for classes that create objects from three coordinate values.
      * @param <T> The type created by this factory.
      */
-    public static interface Factory3D<T> {
+    public interface Factory3D<T> {
 
         /** Creates a new instance of type T from the given coordinate values.
-         * @param v1 the first coordinate value
-         * @param v2 the second coordinate value
-         * @param v3 the third coordinate value
+         * @param a1 the first coordinate value
+         * @param a2 the second coordinate value
+         * @param a3 the third coordinate value
          * @return a new instance of type T
          */
-        T create(double v1, double v2, double v3);
+        T create(double a1, double a2, double a3);
     }
 
     /** Private constructor. */
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java
index fd66e45..6a4eb09 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java
@@ -28,6 +28,14 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser {
     /** Space character */
     private static final String SPACE = " ";
 
+    /** Static instance configured with default values for working with points. */
+    private static final SimpleCoordinateFormat DEFAULT_POINT_FORMAT =
+            new SimpleCoordinateFormat(DEFAULT_SEPARATOR, "(", ")");
+
+    /** Static instance configured with default values for working with vectors. */
+    private static final SimpleCoordinateFormat DEFAULT_VECTOR_FORMAT =
+            new SimpleCoordinateFormat(DEFAULT_SEPARATOR, "{", "}");
+
     /** Creates a new format instance with the default separator value and the given
      * tuple prefix and suffix.
      * @param prefix coordinate tuple prefix; may be null
@@ -47,17 +55,17 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser {
     }
 
     /** Returns a 1D coordinate tuple string with the given value.
-     * @param v coordinate value
+     * @param a coordinate value
      * @return 1D coordinate tuple string
      */
-    public String format1D(double v) {
+    public String format(double a) {
         StringBuilder sb = new StringBuilder();
 
         if (getPrefix() != null) {
             sb.append(getPrefix());
         }
 
-        sb.append(v);
+        sb.append(a);
 
         if (getSuffix() != null) {
             sb.append(getSuffix());
@@ -67,21 +75,21 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser {
     }
 
     /** Returns a 2D coordinate tuple string with the given values.
-     * @param v1 first coordinate value
-     * @param v2 second coordinate value
+     * @param a1 first coordinate value
+     * @param a2 second coordinate value
      * @return 2D coordinate tuple string
      */
-    public String format2D(double v1, double v2) {
+    public String format(double a1, double a2) {
         StringBuilder sb = new StringBuilder();
 
         if (getPrefix() != null) {
             sb.append(getPrefix());
         }
 
-        sb.append(v1);
+        sb.append(a1);
         sb.append(getSeparator());
         sb.append(SPACE);
-        sb.append(v2);
+        sb.append(a2);
 
         if (getSuffix() != null) {
             sb.append(getSuffix());
@@ -91,25 +99,25 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser {
     }
 
     /** Returns a 3D coordinate tuple string with the given values.
-     * @param v1 first coordinate value
-     * @param v2 second coordinate value
-     * @param v3 third coordinate value
+     * @param a1 first coordinate value
+     * @param a2 second coordinate value
+     * @param a3 third coordinate value
      * @return 3D coordinate tuple string
      */
-    public String format3D(double v1, double v2, double v3) {
+    public String format(double a1, double a2, double a3) {
         StringBuilder sb = new StringBuilder();
 
         if (getPrefix() != null) {
             sb.append(getPrefix());
         }
 
-        sb.append(v1);
+        sb.append(a1);
         sb.append(getSeparator());
         sb.append(SPACE);
-        sb.append(v2);
+        sb.append(a2);
         sb.append(getSeparator());
         sb.append(SPACE);
-        sb.append(v3);
+        sb.append(a3);
 
         if (getSuffix() != null) {
             sb.append(getSuffix());
@@ -120,12 +128,13 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser {
 
     /** Parses the given string as a 1D coordinate tuple and passes the coordinate value to the
      * given factory. The object created by the factory is returned.
+     * @param <T> The type created by {@code factory}
      * @param str the string to be parsed
      * @param factory object that will be passed the parsed coordinate value
      * @return object created by {@code factory}
      * @throws IllegalArgumentException if the input string format is invalid
      */
-    public <T> T parse1D(String str, Coordinates.Factory1D<T> factory) throws IllegalArgumentException {
+    public <T> T parse(String str, Coordinates.Factory1D<T> factory) throws IllegalArgumentException {
         final ParsePosition pos = new ParsePosition(0);
 
         readPrefix(str, pos);
@@ -138,12 +147,13 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser {
 
     /** Parses the given string as a 2D coordinate tuple and passes the coordinate values to the
      * given factory. The object created by the factory is returned.
+     * @param <T> The type created by {@code factory}
      * @param str the string to be parsed
      * @param factory object that will be passed the parsed coordinate values
      * @return object created by {@code factory}
      * @throws IllegalArgumentException if the input string format is invalid
      */
-    public <T> T parse2D(String str, Coordinates.Factory2D<T> factory) throws IllegalArgumentException {
+    public <T> T parse(String str, Coordinates.Factory2D<T> factory) throws IllegalArgumentException {
         final ParsePosition pos = new ParsePosition(0);
 
         readPrefix(str, pos);
@@ -157,12 +167,13 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser {
 
     /** Parses the given string as a 3D coordinate tuple and passes the coordinate values to the
      * given factory. The object created by the factory is returned.
+     * @param <T> The type created by {@code factory}
      * @param str the string to be parsed
      * @param factory object that will be passed the parsed coordinate values
      * @return object created by {@code factory}
      * @throws IllegalArgumentException if the input string format is invalid
      */
-    public <T> T parse3D(String str, Coordinates.Factory3D<T> factory) throws IllegalArgumentException {
+    public <T> T parse(String str, Coordinates.Factory3D<T> factory) throws IllegalArgumentException {
         ParsePosition pos = new ParsePosition(0);
 
         readPrefix(str, pos);
@@ -174,4 +185,18 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser {
 
         return factory.create(v1, v2, v3);
     }
+
+    /** Returns a default instance for working with points.
+     * @return instance configured with default values for points
+     */
+    public static SimpleCoordinateFormat getPointFormat() {
+        return DEFAULT_POINT_FORMAT;
+    }
+
+    /** Returns a default instance for working with vectors.
+     * @return instance configured with default values for vectors.
+     */
+    public static SimpleCoordinateFormat getVectorFormat() {
+        return DEFAULT_VECTOR_FORMAT;
+    }
 }
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/package-info.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/package-info.java
new file mode 100644
index 0000000..526cca0
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ *
+ * <p>
+ * This package contains common geometry utilities.
+ * </p>
+ */
+package org.apache.commons.geometry.core.util;
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java
index 820d3f6..23202d7 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java
@@ -23,7 +23,6 @@ public class SimpleCoordinateFormatTest {
 
     private static final double EPS = 1e-10;
 
-    private static final String COMMA = ",";
     private static final String OPEN_PAREN = "(";
     private static final String CLOSE_PAREN = ")";
 
@@ -80,7 +79,7 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("{", "}");
 
         // assert
-        Assert.assertEquals(COMMA, formatter.getSeparator());
+        Assert.assertEquals(",", formatter.getSeparator());
         Assert.assertEquals("{", formatter.getPrefix());
         Assert.assertEquals("}", formatter.getSuffix());
     }
@@ -91,11 +90,11 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
-        Assert.assertEquals("(1.0)", formatter.format1D(1.0));
-        Assert.assertEquals("(-1.0)", formatter.format1D(-1.0));
-        Assert.assertEquals("(NaN)", formatter.format1D(Double.NaN));
-        Assert.assertEquals("(-Infinity)", formatter.format1D(Double.NEGATIVE_INFINITY));
-        Assert.assertEquals("(Infinity)", formatter.format1D(Double.POSITIVE_INFINITY));
+        Assert.assertEquals("(1.0)", formatter.format(1.0));
+        Assert.assertEquals("(-1.0)", formatter.format(-1.0));
+        Assert.assertEquals("(NaN)", formatter.format(Double.NaN));
+        Assert.assertEquals("(-Infinity)", formatter.format(Double.NEGATIVE_INFINITY));
+        Assert.assertEquals("(Infinity)", formatter.format(Double.POSITIVE_INFINITY));
     }
 
     @Test
@@ -104,11 +103,11 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
 
         // act/assert
-        Assert.assertEquals("1.0", formatter.format1D(1.0));
-        Assert.assertEquals("-1.0", formatter.format1D(-1.0));
-        Assert.assertEquals("NaN", formatter.format1D(Double.NaN));
-        Assert.assertEquals("-Infinity", formatter.format1D(Double.NEGATIVE_INFINITY));
-        Assert.assertEquals("Infinity", formatter.format1D(Double.POSITIVE_INFINITY));
+        Assert.assertEquals("1.0", formatter.format(1.0));
+        Assert.assertEquals("-1.0", formatter.format(-1.0));
+        Assert.assertEquals("NaN", formatter.format(Double.NaN));
+        Assert.assertEquals("-Infinity", formatter.format(Double.NEGATIVE_INFINITY));
+        Assert.assertEquals("Infinity", formatter.format(Double.POSITIVE_INFINITY));
     }
 
     @Test
@@ -117,10 +116,10 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
-        Assert.assertEquals("(1.0, -1.0)", formatter.format2D(1.0, -1.0));
-        Assert.assertEquals("(-1.0, 1.0)", formatter.format2D(-1.0, 1.0));
-        Assert.assertEquals("(NaN, -Infinity)", formatter.format2D(Double.NaN, Double.NEGATIVE_INFINITY));
-        Assert.assertEquals("(-Infinity, Infinity)", formatter.format2D(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+        Assert.assertEquals("(1.0, -1.0)", formatter.format(1.0, -1.0));
+        Assert.assertEquals("(-1.0, 1.0)", formatter.format(-1.0, 1.0));
+        Assert.assertEquals("(NaN, -Infinity)", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY));
+        Assert.assertEquals("(-Infinity, Infinity)", formatter.format(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
     }
 
     @Test
@@ -129,10 +128,10 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
 
         // act/assert
-        Assert.assertEquals("1.0, -1.0", formatter.format2D(1.0, -1.0));
-        Assert.assertEquals("-1.0, 1.0", formatter.format2D(-1.0, 1.0));
-        Assert.assertEquals("NaN, -Infinity", formatter.format2D(Double.NaN, Double.NEGATIVE_INFINITY));
-        Assert.assertEquals("-Infinity, Infinity", formatter.format2D(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+        Assert.assertEquals("1.0, -1.0", formatter.format(1.0, -1.0));
+        Assert.assertEquals("-1.0, 1.0", formatter.format(-1.0, 1.0));
+        Assert.assertEquals("NaN, -Infinity", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY));
+        Assert.assertEquals("-Infinity, Infinity", formatter.format(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
     }
 
     @Test
@@ -141,9 +140,9 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
-        Assert.assertEquals("(1.0, 0.0, -1.0)", formatter.format3D(1.0, 0.0, -1.0));
-        Assert.assertEquals("(-1.0, 1.0, 0.0)", formatter.format3D(-1.0, 1.0, 0.0));
-        Assert.assertEquals("(NaN, -Infinity, Infinity)", formatter.format3D(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+        Assert.assertEquals("(1.0, 0.0, -1.0)", formatter.format(1.0, 0.0, -1.0));
+        Assert.assertEquals("(-1.0, 1.0, 0.0)", formatter.format(-1.0, 1.0, 0.0));
+        Assert.assertEquals("(NaN, -Infinity, Infinity)", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
     }
 
     @Test
@@ -152,9 +151,9 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
 
         // act/assert
-        Assert.assertEquals("1.0, 0.0, -1.0", formatter.format3D(1.0, 0.0, -1.0));
-        Assert.assertEquals("-1.0, 1.0, 0.0", formatter.format3D(-1.0, 1.0, 0.0));
-        Assert.assertEquals("NaN, -Infinity, Infinity", formatter.format3D(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+        Assert.assertEquals("1.0, 0.0, -1.0", formatter.format(1.0, 0.0, -1.0));
+        Assert.assertEquals("-1.0, 1.0, 0.0", formatter.format(-1.0, 1.0, 0.0));
+        Assert.assertEquals("NaN, -Infinity, Infinity", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
     }
 
     @Test
@@ -163,9 +162,9 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("||", "<<", ">>");
 
         // act/assert
-        Assert.assertEquals("<<1.0>>", formatter.format1D(1.0));
-        Assert.assertEquals("<<1.0|| 2.0>>", formatter.format2D(1.0, 2.0));
-        Assert.assertEquals("<<1.0|| 2.0|| 3.0>>", formatter.format3D(1.0, 2.0, 3.0));
+        Assert.assertEquals("<<1.0>>", formatter.format(1.0));
+        Assert.assertEquals("<<1.0|| 2.0>>", formatter.format(1.0, 2.0));
+        Assert.assertEquals("<<1.0|| 2.0|| 3.0>>", formatter.format(1.0, 2.0, 3.0));
     }
 
     @Test
@@ -226,12 +225,12 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
-        checkParse1DFailure(formatter, "", "expected \"(\" but found \"\" at index 0");
-        checkParse1DFailure(formatter, "(1 ", "expected \")\" but found \"\" at index 3");
+        checkParse1DFailure(formatter, "", "index 0: expected \"(\" but found \"\"");
+        checkParse1DFailure(formatter, "(1 ", "index 3: expected \")\" but found \"\"");
 
-        checkParse1DFailure(formatter, "(abc)", "Failed to parse number from string at index 1: abc");
+        checkParse1DFailure(formatter, "(abc)", "unable to parse number from string \"abc\"");
 
-        checkParse1DFailure(formatter, "(1) 1", "unexpected content at index 4");
+        checkParse1DFailure(formatter, "(1) 1", "index 4: unexpected content");
     }
 
     @Test
@@ -288,12 +287,12 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
-        checkParse2DFailure(formatter, "", "expected \"(\" but found \"\" at index 0");
-        checkParse2DFailure(formatter, "(1, 2 ", "expected \")\" but found \"\" at index 6");
+        checkParse2DFailure(formatter, "", "index 0: expected \"(\" but found \"\"");
+        checkParse2DFailure(formatter, "(1, 2 ", "index 6: expected \")\" but found \"\"");
 
-        checkParse2DFailure(formatter, "(0,abc)", "Failed to parse number from string at index 3: abc");
+        checkParse2DFailure(formatter, "(0,abc)", "index 3: unable to parse number from string \"abc\"");
 
-        checkParse2DFailure(formatter, "(1, 2) 1", "unexpected content at index 7");
+        checkParse2DFailure(formatter, "(1, 2) 1", "index 7: unexpected content");
     }
 
     @Test
@@ -348,12 +347,12 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
-        checkParse3DFailure(formatter, "", "expected \"(\" but found \"\" at index 0");
-        checkParse3DFailure(formatter, "(1, 2, 3", "expected \")\" but found \"\" at index 8");
+        checkParse3DFailure(formatter, "", "index 0: expected \"(\" but found \"\"");
+        checkParse3DFailure(formatter, "(1, 2, 3", "index 8: expected \")\" but found \"\"");
 
-        checkParse3DFailure(formatter, "(0,0,abc)", "Failed to parse number from string at index 5: abc");
+        checkParse3DFailure(formatter, "(0,0,abc)", "index 5: unable to parse number from string \"abc\"");
 
-        checkParse3DFailure(formatter, "(1, 2, 3) 1", "unexpected content at index 10");
+        checkParse3DFailure(formatter, "(1, 2, 3) 1", "index 10: unexpected content");
     }
 
     @Test
@@ -373,21 +372,47 @@ public class SimpleCoordinateFormatTest {
         SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("||", "<<", ">>");
 
         // act/assert
-        checkParse1DFailure(formatter, "<", "expected \"<<\" but found \"<\" at index 0");
-        checkParse1DFailure(formatter, "<1.0>>", "expected \"<<\" but found \"<1\" at index 0");
-        checkParse2DFailure(formatter, "<<1.0| 2.0>>", "Failed to parse number from string at index 2: 1.0| 2.0");
-        checkParse3DFailure(formatter, "<<1.0|| 2.0|| 3.0>", "Failed to parse number from string at index 13:  3.0>");
+        checkParse1DFailure(formatter, "<", "index 0: expected \"<<\" but found \"<\"");
+        checkParse1DFailure(formatter, "<1.0>>", "index 0: expected \"<<\" but found \"<1\"");
+        checkParse2DFailure(formatter, "<<1.0| 2.0>>", "index 2: unable to parse number from string \"1.0| 2.0\"");
+        checkParse3DFailure(formatter, "<<1.0|| 2.0|| 3.0>", "index 13: unable to parse number from string \" 3.0>\"");
+    }
+
+    @Test
+    public void testDefaultPointFormat() {
+        // act
+        SimpleCoordinateFormat formatter = SimpleCoordinateFormat.getPointFormat();
+
+        // assert
+        Assert.assertEquals(",", formatter.getSeparator());
+        Assert.assertEquals("(", formatter.getPrefix());
+        Assert.assertEquals(")", formatter.getSuffix());
+
+        Assert.assertEquals("(1.0, 2.0)", formatter.format(1, 2));
+    }
+
+    @Test
+    public void testDefaultVectorFormat() {
+        // act
+        SimpleCoordinateFormat formatter = SimpleCoordinateFormat.getVectorFormat();
+
+        // assert
+        Assert.assertEquals(",", formatter.getSeparator());
+        Assert.assertEquals("{", formatter.getPrefix());
+        Assert.assertEquals("}", formatter.getSuffix());
+
+        Assert.assertEquals("{1.0, 2.0}", formatter.format(1, 2));
     }
 
     private void checkParse1D(SimpleCoordinateFormat formatter, String str, double v) {
-        Stub1D result = formatter.parse1D(str, FACTORY_1D);
+        Stub1D result = formatter.parse(str, FACTORY_1D);
 
         Assert.assertEquals(v, result.v, EPS);
     }
 
     private void checkParse1DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) {
         try {
-            formatter.parse1D(str, FACTORY_1D);
+            formatter.parse(str, FACTORY_1D);
             Assert.fail("Operation should have failed");
         }
         catch (IllegalArgumentException exc) {
@@ -398,7 +423,7 @@ public class SimpleCoordinateFormatTest {
     }
 
     private void checkParse2D(SimpleCoordinateFormat formatter, String str, double v1, double v2) {
-        Stub2D result = formatter.parse2D(str, FACTORY_2D);
+        Stub2D result = formatter.parse(str, FACTORY_2D);
 
         Assert.assertEquals(v1, result.v1, EPS);
         Assert.assertEquals(v2, result.v2, EPS);
@@ -406,7 +431,7 @@ public class SimpleCoordinateFormatTest {
 
     private void checkParse2DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) {
         try {
-            formatter.parse2D(str, FACTORY_2D);
+            formatter.parse(str, FACTORY_2D);
             Assert.fail("Operation should have failed");
         }
         catch (IllegalArgumentException exc) {
@@ -417,7 +442,7 @@ public class SimpleCoordinateFormatTest {
     }
 
     private void checkParse3D(SimpleCoordinateFormat formatter, String str, double v1, double v2, double v3) {
-        Stub3D result = formatter.parse3D(str, FACTORY_3D);
+        Stub3D result = formatter.parse(str, FACTORY_3D);
 
         Assert.assertEquals(v1, result.v1, EPS);
         Assert.assertEquals(v2, result.v2, EPS);
@@ -426,7 +451,7 @@ public class SimpleCoordinateFormatTest {
 
     private void checkParse3DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) {
         try {
-            formatter.parse3D(str, FACTORY_3D);
+            formatter.parse(str, FACTORY_3D);
             Assert.fail("Operation should have failed");
         }
         catch (IllegalArgumentException exc) {
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
index 75f4cb8..c6e6910 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.geometry.euclidean.oned;
 
+import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
 import org.apache.commons.geometry.euclidean.EuclideanPoint;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
@@ -46,6 +48,16 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D
     /** Serializable UID. */
     private static final long serialVersionUID = 7556674948671647925L;
 
+    /** Factory for delegating instance creation. */
+    private static Coordinates.Factory1D<Point1D> FACTORY = new Coordinates.Factory1D<Point1D>() {
+
+        /** {@inheritDoc} */
+        @Override
+        public Point1D create(double a) {
+            return new Point1D(a);
+        }
+    };
+
     /** Simple constructor.
      * @param x abscissa (coordinate value)
      */
@@ -136,7 +148,7 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return "(" + getX() + ")";
+        return SimpleCoordinateFormat.getPointFormat().format(getX());
     }
 
     /** Returns a point with the given coordinate value.
@@ -155,6 +167,23 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D
         return new Point1D(value.getX());
     }
 
+    /** Parses the given string and returns a new point instance. The expected string
+     * format is the same as that returned by {@link #toString()}.
+     * @param str the string to parse
+     * @return point instance represented by the string
+     * @throws IllegalArgumentException if the given string has an invalid format
+     */
+    public static Point1D parse(String str) throws IllegalArgumentException {
+        return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY);
+    }
+
+    /** Returns a factory object that can be used to created new point instances.
+     * @return point factory instance
+     */
+    public static Coordinates.Factory1D<Point1D> getFactory() {
+        return FACTORY;
+    }
+
     /** Returns a point with coordinates calculated by multiplying each input coordinate
      * with its corresponding factor and adding the results.
      *
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
index 8455441..5d79379 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.geometry.euclidean.oned;
 
+import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
 import org.apache.commons.geometry.euclidean.EuclideanVector;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
@@ -46,6 +48,16 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
     /** Serializable UID. */
     private static final long serialVersionUID = 1582116020164328846L;
 
+    /** Factory for delegating instance creation. */
+    private static Coordinates.Factory1D<Vector1D> FACTORY = new Coordinates.Factory1D<Vector1D>() {
+
+        /** {@inheritDoc} */
+        @Override
+        public Vector1D create(double a) {
+            return new Vector1D(a);
+        }
+    };
+
     /** Simple constructor.
      * @param x abscissa (coordinate value)
      */
@@ -220,7 +232,7 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return "{" + getX() + "}";
+        return SimpleCoordinateFormat.getVectorFormat().format(getX());
     }
 
     /** Returns a vector with the given coordinate value.
@@ -239,6 +251,23 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
         return new Vector1D(value.getX());
     }
 
+    /** Parses the given string and returns a new vector instance. The expected string
+     * format is the same as that returned by {@link #toString()}.
+     * @param str the string to parse
+     * @return vector instance represented by the string
+     * @throws IllegalArgumentException if the given string has an invalid format
+     */
+    public static Vector1D parse(String str) throws IllegalArgumentException {
+        return SimpleCoordinateFormat.getVectorFormat().parse(str, FACTORY);
+    }
+
+    /** Returns a factory object that can be used to created new vector instances.
+     * @return vector factory instance
+     */
+    public static Coordinates.Factory1D<Vector1D> getFactory() {
+        return FACTORY;
+    }
+
     /** Returns a vector consisting of the linear combination of the inputs.
      * <p>
      * A linear combination is the sum of all of the inputs multiplied by their
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
index 05af242..2093292 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
@@ -17,6 +17,8 @@
 
 package org.apache.commons.geometry.euclidean.threed;
 
+import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
 import org.apache.commons.geometry.euclidean.EuclideanPoint;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
@@ -44,6 +46,16 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
     /** Serializable version identifier. */
     private static final long serialVersionUID = 1313493323784566947L;
 
+    /** Factory for delegating instance creation. */
+    private static Coordinates.Factory3D<Point3D> FACTORY = new Coordinates.Factory3D<Point3D>() {
+
+        /** {@inheritDoc} */
+        @Override
+        public Point3D create(double a1, double a2, double a3) {
+            return new Point3D(a1, a2, a3);
+        }
+    };
+
     /** Simple constructor.
      * Build a point from its coordinates
      * @param x abscissa
@@ -145,7 +157,7 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return "(" + getX() + "; " + getY() + "; " + getZ() + ")";
+        return SimpleCoordinateFormat.getPointFormat().format(getX(), getY(), getZ());
     }
 
     /** Returns a point with the given coordinate values
@@ -178,6 +190,23 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
         return new Point3D(p[0], p[1], p[2]);
     }
 
+    /** Parses the given string and returns a new point instance. The expected string
+     * format is the same as that returned by {@link #toString()}.
+     * @param str the string to parse
+     * @return point instance represented by the string
+     * @throws IllegalArgumentException if the given string has an invalid format
+     */
+    public static Point3D parse(String str) throws IllegalArgumentException {
+        return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY);
+    }
+
+    /** Returns a factory object that can be used to created new point instances.
+     * @return point factory instance
+     */
+    public static Coordinates.Factory3D<Point3D> getFactory() {
+        return FACTORY;
+    }
+
     /** Returns a point with coordinates calculated by multiplying each input coordinate
      * with its corresponding factor and adding the results.
      *
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
index f50816a..85246ab 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
@@ -16,13 +16,15 @@
  */
 package org.apache.commons.geometry.euclidean.threed;
 
+import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
 import org.apache.commons.geometry.euclidean.EuclideanVector;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
 /** This class represents a vector in three-dimensional Euclidean space.
  * Instances of this class are guaranteed to be immutable.
  */
-public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Vector3D> {
+public final class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Vector3D> {
 
     /** Zero (null) vector (coordinates: 0, 0, 0). */
     public static final Vector3D ZERO   = Vector3D.of(0, 0, 0);
@@ -64,6 +66,16 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
     /** Error message when norms are zero. */
     private static final String ZERO_NORM_MSG = "Norm is zero";
 
+    /** Factory for delegating instance creation. */
+    private static Coordinates.Factory3D<Vector3D> FACTORY = new Coordinates.Factory3D<Vector3D>() {
+
+        /** {@inheritDoc} */
+        @Override
+        public Vector3D create(double a1, double a2, double a3) {
+            return new Vector3D(a1, a2, a3);
+        }
+    };
+
     /** Simple constructor.
      * Build a vector from its coordinates
      * @param x abscissa
@@ -373,7 +385,7 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return "{" + getX() + "; " + getY() + "; " + getZ() + "}";
+        return SimpleCoordinateFormat.getVectorFormat().format(getX(), getY(), getZ());
     }
 
     /** Computes the dot product between to vectors. This method simply
@@ -458,6 +470,23 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
         return new Vector3D(x, y, z);
     }
 
+    /** Parses the given string and returns a new vector instance. The expected string
+     * format is the same as that returned by {@link #toString()}.
+     * @param str the string to parse
+     * @return vector instance represented by the string
+     * @throws IllegalArgumentException if the given string has an invalid format
+     */
+    public static Vector3D parse(String str) throws IllegalArgumentException {
+        return SimpleCoordinateFormat.getVectorFormat().parse(str, FACTORY);
+    }
+
+    /** Returns a factory object that can be used to created new vector instances.
+     * @return vector factory instance
+     */
+    public static Coordinates.Factory3D<Vector3D> getFactory() {
+        return FACTORY;
+    }
+
     /** Returns a vector consisting of the linear combination of the inputs.
      * <p>
      * A linear combination is the sum of all of the inputs multiplied by their
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
index 376d970..4175d11 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.geometry.euclidean.twod;
 
+import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
 import org.apache.commons.geometry.euclidean.EuclideanPoint;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
@@ -43,6 +45,16 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D
     /** Serializable UID. */
     private static final long serialVersionUID = 266938651998679754L;
 
+    /** Factory for delegating instance creation. */
+    private static Coordinates.Factory2D<Point2D> FACTORY = new Coordinates.Factory2D<Point2D>() {
+
+        /** {@inheritDoc} */
+        @Override
+        public Point2D create(double a1, double a2) {
+            return new Point2D(a1, a2);
+        }
+    };
+
     /** Simple constructor.
      * Build a point from its coordinates
      * @param x abscissa
@@ -134,7 +146,7 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return "(" + getX() + "; " + getY() + ")";
+        return SimpleCoordinateFormat.getPointFormat().format(getX(), getY());
     }
 
     /** Returns a point with the given coordinate values
@@ -166,6 +178,23 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D
         return new Point2D(p[0], p[1]);
     }
 
+    /** Parses the given string and returns a new point instance. The expected string
+     * format is the same as that returned by {@link #toString()}.
+     * @param str the string to parse
+     * @return point instance represented by the string
+     * @throws IllegalArgumentException if the given string has an invalid format
+     */
+    public static Point2D parse(String str) throws IllegalArgumentException {
+        return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY);
+    }
+
+    /** Returns a factory object that can be used to created new point instances.
+     * @return point factory instance
+     */
+    public static Coordinates.Factory2D<Point2D> getFactory() {
+        return FACTORY;
+    }
+
     /** Returns a point with coordinates calculated by multiplying each input coordinate
      * with its corresponding factor and adding the results.
      *
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
index 98ac4bc..e6285b1 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.geometry.euclidean.twod;
 
+import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
 import org.apache.commons.geometry.euclidean.EuclideanVector;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
@@ -58,6 +60,16 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
     /** Error message when norms are zero. */
     private static final String ZERO_NORM_MSG = "Norm is zero";
 
+    /** Factory for delegating instance creation. */
+    private static Coordinates.Factory2D<Vector2D> FACTORY = new Coordinates.Factory2D<Vector2D>() {
+
+        /** {@inheritDoc} */
+        @Override
+        public Vector2D create(double a1, double a2) {
+            return new Vector2D(a1, a2);
+        }
+    };
+
     /** Simple constructor.
      * @param x abscissa (first coordinate)
      * @param y ordinate (second coordinate)
@@ -311,7 +323,7 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return "{" + getX() + "; " + getY() + "}";
+        return SimpleCoordinateFormat.getVectorFormat().format(getX(), getY());
     }
 
     /** Computes the dot product between to vectors. This method simply
@@ -365,6 +377,23 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
         return new Vector2D(v[0], v[1]);
     }
 
+    /** Parses the given string and returns a new vector instance. The expected string
+     * format is the same as that returned by {@link #toString()}.
+     * @param str the string to parse
+     * @return vector instance represented by the string
+     * @throws IllegalArgumentException if the given string has an invalid format
+     */
+    public static Vector2D parse(String str) throws IllegalArgumentException {
+        return SimpleCoordinateFormat.getVectorFormat().parse(str, FACTORY);
+    }
+
+    /** Returns a factory object that can be used to created new vector instances.
+     * @return vector factory instance
+     */
+    public static Coordinates.Factory2D<Vector2D> getFactory() {
+        return FACTORY;
+    }
+
     /** Returns a vector consisting of the linear combination of the inputs.
      * <p>
      * A linear combination is the sum of all of the inputs multiplied by their
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
index f17af96..bcde081 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
@@ -19,6 +19,7 @@ package org.apache.commons.geometry.euclidean.oned;
 
 import java.util.regex.Pattern;
 
+import org.apache.commons.geometry.core.util.Coordinates;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
@@ -183,6 +184,27 @@ public class Point1DTest {
     }
 
     @Test
+    public void testParse() {
+        // act/assert
+        checkPoint(Point1D.parse("(1)"), 1);
+        checkPoint(Point1D.parse("(-1)"), -1);
+
+        checkPoint(Point1D.parse("(0.01)"), 1e-2);
+        checkPoint(Point1D.parse("(-1e-3)"), -1e-3);
+
+        checkPoint(Point1D.parse("(NaN)"), Double.NaN);
+
+        checkPoint(Point1D.parse(Point1D.ZERO.toString()), 0);
+        checkPoint(Point1D.parse(Point1D.ONE.toString()), 1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParse_failure() {
+        // act/assert
+        Point1D.parse("abc");
+    }
+
+    @Test
     public void testOf() {
         // act/assert
         checkPoint(Point1D.of(0), 0.0);
@@ -207,6 +229,16 @@ public class Point1DTest {
     }
 
     @Test
+    public void testGetFactory() {
+        // act
+        Coordinates.Factory1D<Point1D> factory = Point1D.getFactory();
+
+        // assert
+        checkPoint(factory.create(1), 1);
+        checkPoint(factory.create(-1), -1);
+    }
+
+    @Test
     public void testVectorCombination() {
         // act/assert
         checkPoint(Point1D.vectorCombination(2, Point1D.of(3)), 6);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
index fa757ab..7184476 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
@@ -2,6 +2,7 @@ package org.apache.commons.geometry.euclidean.oned;
 
 import java.util.regex.Pattern;
 
+import org.apache.commons.geometry.core.util.Coordinates;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
@@ -291,6 +292,27 @@ public class Vector1DTest {
     }
 
     @Test
+    public void testParse() {
+        // act/assert
+        checkVector(Vector1D.parse("{1}"), 1);
+        checkVector(Vector1D.parse("{-1}"), -1);
+
+        checkVector(Vector1D.parse("{0.01}"), 1e-2);
+        checkVector(Vector1D.parse("{-1e-3}"), -1e-3);
+
+        checkVector(Vector1D.parse("{NaN}"), Double.NaN);
+
+        checkVector(Vector1D.parse(Vector1D.ZERO.toString()), 0);
+        checkVector(Vector1D.parse(Vector1D.ONE.toString()), 1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParse_failure() {
+        // act/assert
+        Vector1D.parse("abc");
+    }
+
+    @Test
     public void testOf() {
         // act/assert
         checkVector(Vector1D.of(0), 0.0);
@@ -315,6 +337,16 @@ public class Vector1DTest {
     }
 
     @Test
+    public void testGetFactory() {
+        // act
+        Coordinates.Factory1D<Vector1D> factory = Vector1D.getFactory();
+
+        // assert
+        checkVector(factory.create(1), 1);
+        checkVector(factory.create(-1), -1);
+    }
+
+    @Test
     public void testLinearCombination() {
         // act/assert
         checkVector(Vector1D.linearCombination(2, Vector1D.of(3)), 6);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java
index fa4cf3f..d20d918 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java
@@ -18,6 +18,7 @@ package org.apache.commons.geometry.euclidean.threed;
 
 import java.util.regex.Pattern;
 
+import org.apache.commons.geometry.core.util.Coordinates;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
@@ -173,7 +174,7 @@ public class Point3DTest {
     public void testToString() {
         // arrange
         Point3D p = Point3D.of(1, 2, 3);
-        Pattern pattern = Pattern.compile("\\(1.{0,2}; 2.{0,2}; 3.{0,2}\\)");
+        Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}, 3.{0,2}\\)");
 
         // act
         String str = p.toString();
@@ -184,6 +185,25 @@ public class Point3DTest {
     }
 
     @Test
+    public void testParse() {
+        // act/assert
+        checkPoint(Point3D.parse("(1, 2, 0)"), 1, 2, 0);
+        checkPoint(Point3D.parse("(-1, -2, 0)"), -1, -2, 0);
+
+        checkPoint(Point3D.parse("(0.01, -1e-3, 1e3)"), 1e-2, -1e-3, 1e3);
+
+        checkPoint(Point3D.parse("(NaN, -Infinity, Infinity)"), Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+
+        checkPoint(Point3D.parse(Point3D.ZERO.toString()), 0, 0, 0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParse_failure() {
+        // act/assert
+        Point3D.parse("abc");
+    }
+
+    @Test
     public void testOf() {
         // act/assert
         checkPoint(Point3D.of(1, 2, 3), 1, 2, 3);
@@ -223,6 +243,16 @@ public class Point3DTest {
     }
 
     @Test
+    public void testGetFactory() {
+        // act
+        Coordinates.Factory3D<Point3D> factory = Point3D.getFactory();
+
+        // assert
+        checkPoint(factory.create(1, 2, 3), 1, 2, 3);
+        checkPoint(factory.create(-1, -2, -3), -1, -2, -3);
+    }
+
+    @Test
     public void testVectorCombination1() {
         // arrange
         Point3D p1 = Point3D.of(1, 2, 3);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
index f2b4fcc..c9b3cf9 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
@@ -20,6 +20,7 @@ package org.apache.commons.geometry.euclidean.threed;
 import java.util.regex.Pattern;
 
 import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.util.Coordinates;
 import org.apache.commons.numbers.core.Precision;
 import org.apache.commons.rng.UniformRandomProvider;
 import org.apache.commons.rng.simple.RandomSource;
@@ -618,7 +619,7 @@ public class Vector3DTest {
     public void testToString() {
         // arrange
         Vector3D v = Vector3D.of(1, 2, 3);
-        Pattern pattern = Pattern.compile("\\{1.{0,2}; 2.{0,2}; 3.{0,2}\\}");
+        Pattern pattern = Pattern.compile("\\{1.{0,2}, 2.{0,2}, 3.{0,2}\\}");
 
         // act
         String str = v.toString();
@@ -629,6 +630,26 @@ public class Vector3DTest {
     }
 
     @Test
+    public void testParse() {
+        // act/assert
+        checkVector(Vector3D.parse("{1, 2, 3}"), 1, 2, 3);
+        checkVector(Vector3D.parse("{-1, -2, -3}"), -1, -2, -3);
+
+        checkVector(Vector3D.parse("{0.01, -1e-3, 0}"), 1e-2, -1e-3, 0);
+
+        checkVector(Vector3D.parse("{NaN, -Infinity, Infinity}"), Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+
+        checkVector(Vector3D.parse(Vector3D.ZERO.toString()), 0, 0, 0);
+        checkVector(Vector3D.parse(Vector3D.MINUS_X.toString()), -1, 0, 0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParse_failure() {
+        // act/assert
+        Vector3D.parse("abc");
+    }
+
+    @Test
     public void testOf() {
         // act/assert
         checkVector(Vector3D.of(1, 2, 3), 1, 2, 3);
@@ -668,6 +689,16 @@ public class Vector3DTest {
     }
 
     @Test
+    public void testGetFactory() {
+        // act
+        Coordinates.Factory3D<Vector3D> factory = Vector3D.getFactory();
+
+        // assert
+        checkVector(factory.create(1, 2, 3), 1, 2, 3);
+        checkVector(factory.create(-1, -2, -3), -1, -2, -3);
+    }
+
+    @Test
     public void testLinearCombination1() {
         // arrange
         Vector3D p1 = Vector3D.of(1, 2, 3);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java
index 6892198..20d95ad 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java
@@ -18,6 +18,7 @@ package org.apache.commons.geometry.euclidean.twod;
 
 import java.util.regex.Pattern;
 
+import org.apache.commons.geometry.core.util.Coordinates;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
@@ -156,7 +157,7 @@ public class Point2DTest {
     public void testToString() {
         // arrange
         Point2D p = Point2D.of(1, 2);
-        Pattern pattern = Pattern.compile("\\(1.{0,2}; 2.{0,2}\\)");
+        Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}\\)");
 
         // act
         String str = p.toString();
@@ -167,6 +168,25 @@ public class Point2DTest {
     }
 
     @Test
+    public void testParse() {
+        // act/assert
+        checkPoint(Point2D.parse("(1, 2)"), 1, 2);
+        checkPoint(Point2D.parse("(-1, -2)"), -1, -2);
+
+        checkPoint(Point2D.parse("(0.01, -1e-3)"), 1e-2, -1e-3);
+
+        checkPoint(Point2D.parse("(NaN, -Infinity)"), Double.NaN, Double.NEGATIVE_INFINITY);
+
+        checkPoint(Point2D.parse(Point2D.ZERO.toString()), 0, 0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParse_failure() {
+        // act/assert
+        Point2D.parse("abc");
+    }
+
+    @Test
     public void testOf() {
         // act/assert
         checkPoint(Point2D.of(0, 1), 0, 1);
@@ -200,6 +220,16 @@ public class Point2DTest {
     }
 
     @Test
+    public void testGetFactory() {
+        // act
+        Coordinates.Factory2D<Point2D> factory = Point2D.getFactory();
+
+        // assert
+        checkPoint(factory.create(1, 2), 1, 2);
+        checkPoint(factory.create(-1, -2), -1, -2);
+    }
+
+    @Test
     public void testVectorCombination1() {
         // arrange
         Point2D p1 = Point2D.of(1, 2);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
index 7882e7d..13208c0 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
@@ -3,6 +3,7 @@ package org.apache.commons.geometry.euclidean.twod;
 import java.util.regex.Pattern;
 
 import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.util.Coordinates;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
@@ -420,7 +421,7 @@ public class Vector2DTest {
     public void testToString() {
         // arrange
         Vector2D v = Vector2D.of(1, 2);
-        Pattern pattern = Pattern.compile("\\{1.{0,2}; 2.{0,2}\\}");
+        Pattern pattern = Pattern.compile("\\{1.{0,2}, 2.{0,2}\\}");
 
         // act
         String str = v.toString();
@@ -431,6 +432,26 @@ public class Vector2DTest {
     }
 
     @Test
+    public void testParse() {
+        // act/assert
+        checkVector(Vector2D.parse("{1, 2}"), 1, 2);
+        checkVector(Vector2D.parse("{-1, -2}"), -1, -2);
+
+        checkVector(Vector2D.parse("{0.01, -1e-3}"), 1e-2, -1e-3);
+
+        checkVector(Vector2D.parse("{NaN, -Infinity}"), Double.NaN, Double.NEGATIVE_INFINITY);
+
+        checkVector(Vector2D.parse(Vector2D.ZERO.toString()), 0, 0);
+        checkVector(Vector2D.parse(Vector2D.MINUS_X.toString()), -1, 0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParse_failure() {
+        // act/assert
+        Vector2D.parse("abc");
+    }
+
+    @Test
     public void testOf() {
         // act/assert
         checkVector(Vector2D.of(0, 1), 0, 1);
@@ -464,6 +485,16 @@ public class Vector2DTest {
     }
 
     @Test
+    public void testGetFactory() {
+        // act
+        Coordinates.Factory2D<Vector2D> factory = Vector2D.getFactory();
+
+        // assert
+        checkVector(factory.create(1, 2), 1, 2);
+        checkVector(factory.create(-1, -2), -1, -2);
+    }
+
+    @Test
     public void testLinearCombination1() {
         // arrange
         Vector2D p1 = Vector2D.of(1, 2);
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
index 2445857..676a88b 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
@@ -42,6 +42,9 @@ import org.apache.commons.numbers.core.Precision;
  */
 public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterable<double[]> {
 
+    /** Message used for internal errors. */
+    private static final String INTERNAL_ERROR_MESSAGE = "Please file a bug report";
+
     /** Build an arcs set representing the whole circle.
      * @param tolerance tolerance below which close sub-arcs are merged together
      */
@@ -135,12 +138,12 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
         final double normalizedLower = PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(lower);
         final double normalizedUpper = normalizedLower + (upper - lower);
         final SubHyperplane<S1Point> lowerCut =
-                new LimitAngle(new S1Point(normalizedLower), false, tolerance).wholeHyperplane();
+                new LimitAngle(S1Point.of(normalizedLower), false, tolerance).wholeHyperplane();
 
         if (normalizedUpper <= Geometry.TWO_PI) {
             // simple arc starting after 0 and ending before 2 \pi
             final SubHyperplane<S1Point> upperCut =
-                    new LimitAngle(new S1Point(normalizedUpper), true, tolerance).wholeHyperplane();
+                    new LimitAngle(S1Point.of(normalizedUpper), true, tolerance).wholeHyperplane();
             return new BSPTree<>(lowerCut,
                                          new BSPTree<S1Point>(Boolean.FALSE),
                                          new BSPTree<>(upperCut,
@@ -151,7 +154,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
         } else {
             // arc wrapping around 2 \pi
             final SubHyperplane<S1Point> upperCut =
-                    new LimitAngle(new S1Point(normalizedUpper - Geometry.TWO_PI), true, tolerance).wholeHyperplane();
+                    new LimitAngle(S1Point.of(normalizedUpper - Geometry.TWO_PI), true, tolerance).wholeHyperplane();
             return new BSPTree<>(lowerCut,
                                          new BSPTree<>(upperCut,
                                                                new BSPTree<S1Point>(Boolean.FALSE),
@@ -459,7 +462,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
             if (Precision.equals(size, Geometry.TWO_PI, 0)) {
                 setBarycenter(S1Point.NaN);
             } else if (size >= Precision.SAFE_MIN) {
-                setBarycenter(new S1Point(sum / (2 * size)));
+                setBarycenter(S1Point.of(sum / (2 * size)));
             } else {
                 final LimitAngle limit = (LimitAngle) getTree(false).getCut().getHyperplane();
                 setBarycenter(limit.getLocation());
@@ -495,9 +498,9 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
                         final double previousOffset = alpha - previous;
                         final double currentOffset  = a[0] - alpha;
                         if (previousOffset < currentOffset) {
-                            return new BoundaryProjection<>(point, new S1Point(previous), previousOffset);
+                            return new BoundaryProjection<>(point, S1Point.of(previous), previousOffset);
                         } else {
-                            return new BoundaryProjection<>(point, new S1Point(a[0]), currentOffset);
+                            return new BoundaryProjection<>(point, S1Point.of(a[0]), currentOffset);
                         }
                     }
                 } else if (alpha <= a[1]) {
@@ -506,9 +509,9 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
                     final double offset0 = a[0] - alpha;
                     final double offset1 = alpha - a[1];
                     if (offset0 < offset1) {
-                        return new BoundaryProjection<>(point, new S1Point(a[1]), offset1);
+                        return new BoundaryProjection<>(point, S1Point.of(a[1]), offset1);
                     } else {
-                        return new BoundaryProjection<>(point, new S1Point(a[0]), offset0);
+                        return new BoundaryProjection<>(point, S1Point.of(a[0]), offset0);
                     }
                 }
             }
@@ -529,18 +532,18 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
                 final double previousOffset = alpha - (previous - Geometry.TWO_PI);
                 final double currentOffset  = first - alpha;
                 if (previousOffset < currentOffset) {
-                    return new BoundaryProjection<>(point, new S1Point(previous), previousOffset);
+                    return new BoundaryProjection<>(point, S1Point.of(previous), previousOffset);
                 } else {
-                    return new BoundaryProjection<>(point, new S1Point(first), currentOffset);
+                    return new BoundaryProjection<>(point, S1Point.of(first), currentOffset);
                 }
             } else {
                 // the test point is between last and 2\pi
                 final double previousOffset = alpha - previous;
                 final double currentOffset  = first + Geometry.TWO_PI - alpha;
                 if (previousOffset < currentOffset) {
-                    return new BoundaryProjection<>(point, new S1Point(previous), previousOffset);
+                    return new BoundaryProjection<>(point, S1Point.of(previous), previousOffset);
                 } else {
-                    return new BoundaryProjection<>(point, new S1Point(first), currentOffset);
+                    return new BoundaryProjection<>(point, S1Point.of(first), currentOffset);
                 }
             }
 
@@ -652,7 +655,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
                 }
                 if (end == null) {
                     // this should never happen
-                    throw new IllegalStateException("Please file a bug report");
+                    throw new IllegalStateException(INTERNAL_ERROR_MESSAGE);
                 }
 
                 // we have identified the last arc
@@ -787,11 +790,11 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
      */
     private void addArcLimit(final BSPTree<S1Point> tree, final double alpha, final boolean isStart) {
 
-        final LimitAngle limit = new LimitAngle(new S1Point(alpha), !isStart, getTolerance());
+        final LimitAngle limit = new LimitAngle(S1Point.of(alpha), !isStart, getTolerance());
         final BSPTree<S1Point> node = tree.getCell(limit.getLocation(), getTolerance());
         if (node.getCut() != null) {
             // this should never happen
-            throw new IllegalStateException("Please file a bug report");
+            throw new IllegalStateException(INTERNAL_ERROR_MESSAGE);
         }
 
         node.insertCut(limit);
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
index 8f7b19c..c2f6d86 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
@@ -17,13 +17,15 @@
 package org.apache.commons.geometry.spherical.oned;
 
 import org.apache.commons.geometry.core.Point;
+import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
 import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.numbers.angle.PlaneAngleRadians;
 
 /** This class represents a point on the 1-sphere.
  * <p>Instances of this class are guaranteed to be immutable.</p>
  */
-public class S1Point implements Point<S1Point> {
+public final class S1Point implements Point<S1Point> {
 
    // CHECKSTYLE: stop ConstantName
     /** A vector with all coordinates set to NaN. */
@@ -33,22 +35,22 @@ public class S1Point implements Point<S1Point> {
     /** Serializable UID. */
     private static final long serialVersionUID = 20131218L;
 
-    /** Azimuthal angle \( \alpha \). */
+    /** Factory for delegating instance creation. */
+    private static Coordinates.Factory1D<S1Point> FACTORY = new Coordinates.Factory1D<S1Point>() {
+
+        /** {@inheritDoc} */
+        @Override
+        public S1Point create(double a) {
+            return S1Point.of(a);
+        }
+    };
+
+    /** Azimuthal angle in radians \( \alpha \). */
     private final double alpha;
 
     /** Corresponding 2D normalized vector. */
     private final Vector2D 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),
-             Vector2D.of(Math.cos(alpha), Math.sin(alpha)));
-    }
-
     /** Build a point from its internal components.
      * @param alpha azimuthal angle \( \alpha \)
      * @param vector corresponding vector
@@ -58,7 +60,7 @@ public class S1Point implements Point<S1Point> {
         this.vector = vector;
     }
 
-    /** Get the azimuthal angle \( \alpha \).
+    /** Get the azimuthal angle in radians \( \alpha \).
      * @return azimuthal angle \( \alpha \)
      * @see #S1Point(double)
      */
@@ -159,4 +161,39 @@ public class S1Point implements Point<S1Point> {
         }
         return 1759 * Double.hashCode(alpha);
     }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return SimpleCoordinateFormat.getPointFormat().format(getAlpha());
+    }
+
+    /** Creates a new point instance from the given azimuthal coordinate value.
+     * @param alpha azimuthal angle in radians \( \alpha \)
+     * @return point instance with the given azimuth coordinate value
+     * @see #getAlpha()
+     */
+    public static S1Point of(double alpha) {
+        double normalizedAlpha = PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(alpha);
+        Vector2D vector = Vector2D.of(Math.cos(normalizedAlpha), Math.sin(normalizedAlpha));
+
+        return new S1Point(normalizedAlpha, vector);
+    }
+
+    /** Parses the given string and returns a new point instance. The expected string
+     * format is the same as that returned by {@link #toString()}.
+     * @param str the string to parse
+     * @return point instance represented by the string
+     * @throws IllegalArgumentException if the given string has an invalid format
+     */
+    public static S1Point parse(String str) throws IllegalArgumentException {
+        return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY);
+    }
+
+    /** Returns a factory object that can be used to created new point instances.
+     * @return point factory instance
+     */
+    public static Coordinates.Factory1D<S1Point> getFactory() {
+        return FACTORY;
+    }
 }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/package-info.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/package-info.java
new file mode 100644
index 0000000..020a968
--- /dev/null
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ *
+ * <p>
+ * Base package for spherical geometry components.
+ * </p>
+ */
+package org.apache.commons.geometry.spherical;
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java
index 28d4e02..3b017ca 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java
@@ -16,7 +16,6 @@
  */
 package org.apache.commons.geometry.spherical.twod;
 
-import org.apache.commons.geometry.core.Point;
 import org.apache.commons.geometry.core.partitioning.Embedding;
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
@@ -147,7 +146,7 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point>
      */
     @Override
     public S1Point toSubSpace(final S2Point point) {
-        return new S1Point(getPhase(point.getVector()));
+        return S1Point.of(getPhase(point.getVector()));
     }
 
     /** Get the phase angle of a direction.
@@ -169,7 +168,7 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point>
      */
     @Override
     public S2Point toSpace(final S1Point point) {
-        return new S2Point(getPointAt(point.getAlpha()));
+        return S2Point.of(getPointAt(point.getAlpha()));
     }
 
     /** Get a circle point from its phase around the circle.
@@ -307,7 +306,7 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point>
         /** {@inheritDoc} */
         @Override
         public S2Point apply(final S2Point point) {
-            return new S2Point(rotation.applyTo(point.getVector()));
+            return S2Point.of(rotation.applyTo(point.getVector()));
         }
 
         /** {@inheritDoc} */
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java
index 997d051..609408a 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java
@@ -148,7 +148,7 @@ public class Edge {
             if (unwrappedEnd >= 0) {
                 // the start of the edge is inside the circle
                 previousVertex = addSubEdge(previousVertex,
-                                            new Vertex(new S2Point(circle.getPointAt(edgeStart + unwrappedEnd))),
+                                            new Vertex(S2Point.of(circle.getPointAt(edgeStart + unwrappedEnd))),
                                             unwrappedEnd, insideList, splitCircle);
                 alreadyManagedLength = unwrappedEnd;
             }
@@ -166,7 +166,7 @@ public class Edge {
             } else {
                 // the edge is long enough to enter inside the circle
                 previousVertex = addSubEdge(previousVertex,
-                                            new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeStart))),
+                                            new Vertex(S2Point.of(circle.getPointAt(edgeStart + arcRelativeStart))),
                                             arcRelativeStart - alreadyManagedLength, outsideList, splitCircle);
                 alreadyManagedLength = arcRelativeStart;
 
@@ -177,7 +177,7 @@ public class Edge {
                 } else {
                     // the edge is long enough to exit outside of the circle
                     previousVertex = addSubEdge(previousVertex,
-                                                new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeStart))),
+                                                new Vertex(S2Point.of(circle.getPointAt(edgeStart + arcRelativeStart))),
                                                 arcRelativeStart - alreadyManagedLength, insideList, splitCircle);
                     alreadyManagedLength = arcRelativeStart;
                     previousVertex = addSubEdge(previousVertex, end,
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java
index 47b6d39..085f9c5 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java
@@ -91,8 +91,8 @@ class EdgesBuilder implements BSPTreeVisitor<S2Point> {
         final Circle circle  = (Circle) sub.getHyperplane();
         final List<Arc> arcs = ((ArcsSet) sub.getRemainingRegion()).asList();
         for (final Arc a : arcs) {
-            final Vertex start = new Vertex(circle.toSpace(new S1Point(a.getInf())));
-            final Vertex end   = new Vertex(circle.toSpace(new S1Point(a.getSup())));
+            final Vertex start = new Vertex(circle.toSpace(S1Point.of(a.getInf())));
+            final Vertex end   = new Vertex(circle.toSpace(S1Point.of(a.getSup())));
             start.bindWith(circle);
             end.bindWith(circle);
             final Edge edge;
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java
index 2cbcb03..258b17e 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java
@@ -160,7 +160,7 @@ class PropertiesComputer implements BSPTreeVisitor<S2Point> {
         if (summedBarycenter.getNormSq() == 0) {
             return S2Point.NaN;
         } else {
-            return new S2Point(summedBarycenter);
+            return S2Point.of(summedBarycenter);
         }
     }
 
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
index 567e666..a0c7499 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
@@ -17,6 +17,8 @@
 package org.apache.commons.geometry.spherical.twod;
 
 import org.apache.commons.geometry.core.Point;
+import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
 
 /** This class represents a point on the 2-sphere.
@@ -29,7 +31,7 @@ import org.apache.commons.geometry.euclidean.threed.Vector3D;
  * </p>
  * <p>Instances of this class are guaranteed to be immutable.</p>
  */
-public class S2Point implements Point<S2Point> {
+public final class S2Point implements Point<S2Point> {
 
     /** +I (coordinates: \( \theta = 0, \varphi = \pi/2 \)). */
     public static final S2Point PLUS_I = new S2Point(0, 0.5 * Math.PI, Vector3D.PLUS_X);
@@ -57,6 +59,16 @@ public class S2Point implements Point<S2Point> {
     /** Serializable UID. */
     private static final long serialVersionUID = 20131218L;
 
+    /** Factory for delegating instance creation. */
+    private static Coordinates.Factory2D<S2Point> FACTORY = new Coordinates.Factory2D<S2Point>() {
+
+        /** {@inheritDoc} */
+        @Override
+        public S2Point create(double a1, double a2) {
+            return S2Point.of(a1, a2);
+        }
+    };
+
     /** Azimuthal angle \( \theta \) in the x-y plane. */
     private final double theta;
 
@@ -66,29 +78,6 @@ public class S2Point implements Point<S2Point> {
     /** Corresponding 3D normalized vector. */
     private final Vector3D 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 IllegalArgumentException if \( \varphi \) is not in the [\( 0; \pi \)] range
-     */
-    public S2Point(final double theta, final double phi)
-        throws IllegalArgumentException {
-        this(theta, phi, vector(theta, phi));
-    }
-
-    /** Simple constructor.
-     * Build a vector from its underlying 3D vector
-     * @param vector 3D vector
-     * @exception IllegalArgumentException if vector norm is zero
-     */
-    public S2Point(final Vector3D vector) throws IllegalArgumentException {
-        this(Math.atan2(vector.getY(), vector.getX()), Vector3D.PLUS_Z.angle(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 \)
@@ -100,28 +89,6 @@ public class S2Point implements Point<S2Point> {
         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 IllegalArgumentException if \( \varphi \) is not in the [\( 0; \pi \)] range
-     */
-    private static Vector3D vector(final double theta, final double phi)
-       throws IllegalArgumentException {
-
-        if (phi < 0 || phi > Math.PI) {
-            throw new IllegalArgumentException(phi + " is out of [" + 0 + ", " + Math.PI + "] range");
-        }
-
-        final double cosTheta = Math.cos(theta);
-        final double sinTheta = Math.sin(theta);
-        final double cosPhi   = Math.cos(phi);
-        final double sinPhi   = Math.sin(phi);
-
-        return Vector3D.of(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)
@@ -236,4 +203,71 @@ public class S2Point implements Point<S2Point> {
         }
         return 134 * (37 * Double.hashCode(theta) +  Double.hashCode(phi));
     }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return SimpleCoordinateFormat.getPointFormat().format(getTheta(), getPhi());
+    }
+
+    /** Build a vector from its spherical coordinates
+     * @param theta azimuthal angle \( \theta \) in the x-y plane
+     * @param phi polar angle \( \varphi \)
+     * @return point instance with the given coordinates
+     * @see #getTheta()
+     * @see #getPhi()
+     * @exception IllegalArgumentException if \( \varphi \) is not in the [\( 0; \pi \)] range
+     */
+    public static S2Point of(final double theta, final double phi) {
+        return new S2Point(theta, phi, vector(theta, phi));
+    }
+
+    /** Build a point from its underlying 3D vector
+     * @param vector 3D vector
+     * @return point instance with the coordinates determined by the given 3D vector
+     * @exception IllegalArgumentException if vector norm is zero
+     */
+    public static S2Point of(final Vector3D vector) {
+        return new S2Point(Math.atan2(vector.getY(), vector.getX()),
+                Vector3D.PLUS_Z.angle(vector),
+                vector.normalize());
+    }
+
+    /** 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 IllegalArgumentException if \( \varphi \) is not in the [\( 0; \pi \)] range
+     */
+    private static Vector3D vector(final double theta, final double phi)
+       throws IllegalArgumentException {
+
+        if (phi < 0 || phi > Math.PI) {
+            throw new IllegalArgumentException(phi + " is out of [" + 0 + ", " + Math.PI + "] range");
+        }
+
+        final double cosTheta = Math.cos(theta);
+        final double sinTheta = Math.sin(theta);
+        final double cosPhi   = Math.cos(phi);
+        final double sinPhi   = Math.sin(phi);
+
+        return Vector3D.of(cosTheta * sinPhi, sinTheta * sinPhi, cosPhi);
+    }
+
+    /** Parses the given string and returns a new point instance. The expected string
+     * format is the same as that returned by {@link #toString()}.
+     * @param str the string to parse
+     * @return point instance represented by the string
+     * @throws IllegalArgumentException if the given string has an invalid format
+     */
+    public static S2Point parse(String str) throws IllegalArgumentException {
+        return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY);
+    }
+
+    /** Returns a factory object that can be used to created new point instances.
+     * @return point factory instance
+     */
+    public static Coordinates.Factory2D<S2Point> getFactory() {
+        return FACTORY;
+    }
 }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java
index fd22d6b..d9e3eeb 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java
@@ -161,11 +161,11 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
         final S2Point[] array = new S2Point[n];
         final Rotation r0 = new Rotation(Vector3D.crossProduct(center, meridian),
                                          outsideRadius, RotationConvention.VECTOR_OPERATOR);
-        array[0] = new S2Point(r0.applyTo(center));
+        array[0] = S2Point.of(r0.applyTo(center));
 
         final Rotation r = new Rotation(center, Geometry.TWO_PI / n, RotationConvention.VECTOR_OPERATOR);
         for (int i = 1; i < n; ++i) {
-            array[i] = new S2Point(r.applyTo(array[i - 1].getVector()));
+            array[i] = S2Point.of(r.applyTo(array[i - 1].getVector()));
         }
 
         return array;
@@ -325,7 +325,7 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
             if (tree.getCut() == null && (Boolean) tree.getAttribute()) {
                 // the instance covers the whole space
                 setSize(4 * Math.PI);
-                setBarycenter(new S2Point(0, 0));
+                setBarycenter(S2Point.of(0, 0));
             } else {
                 setSize(0);
                 setBarycenter(S2Point.NaN);
@@ -478,13 +478,13 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
         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(),
+            return new EnclosingBall<>(S2Point.of(circle.getPole()).negate(),
                                                         0.5 * Math.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()),
+            return new EnclosingBall<>(S2Point.of(circle.getPole()),
                                                         0.5 * Math.PI);
         }
 
@@ -517,7 +517,7 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
             EnclosingBall<S2Point> enclosingS2 =
                     new EnclosingBall<>(S2Point.PLUS_K, Double.POSITIVE_INFINITY);
             for (Point3D outsidePoint : getOutsidePoints()) {
-                final S2Point outsideS2 = new S2Point(outsidePoint.asVector());
+                final S2Point outsideS2 = S2Point.of(outsidePoint.asVector());
                 final BoundaryProjection<S2Point> projection = projectToBoundary(outsideS2);
                 if (Math.PI - projection.getOffset() < enclosingS2.getRadius()) {
                     enclosingS2 = new EnclosingBall<>(outsideS2.negate(),
@@ -529,11 +529,11 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
         }
         final S2Point[] support = new S2Point[support3D.length];
         for (int i = 0; i < support3D.length; ++i) {
-            support[i] = new S2Point(support3D[i].asVector());
+            support[i] = S2Point.of(support3D[i].asVector());
         }
 
         final EnclosingBall<S2Point> enclosingS2 =
-                new EnclosingBall<>(new S2Point(enclosing3D.getCenter().asVector()),
+                new EnclosingBall<>(S2Point.of(enclosing3D.getCenter().asVector()),
                                                      Math.acos((1 + h * h - r * r) / (2 * h)),
                                                      support);
 
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java
index b5a1211..a43bc3d 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java
@@ -89,7 +89,7 @@ public class SphericalTestUtils {
             @Override
             protected LimitAngle parseHyperplane()
                 throws IOException, ParseException {
-                return new LimitAngle(new S1Point(getNumber()), getBoolean(), getNumber());
+                return new LimitAngle(S1Point.of(getNumber()), getBoolean(), getNumber());
             }
 
         };
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java
index 3b59551..a6bab1a 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java
@@ -39,12 +39,12 @@ public class ArcsSetTest {
         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(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(2.3)));
+        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(5.7)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(1.2)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(8.5)));
+        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(S1Point.of(8.7)));
+        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(S1Point.of(3.0)));
         Assert.assertEquals(1, set.asList().size());
         Assert.assertEquals(2.3, set.asList().get(0).getInf(), 1.0e-10);
         Assert.assertEquals(5.7, set.asList().get(0).getSup(), 1.0e-10);
@@ -55,12 +55,12 @@ public class ArcsSetTest {
         ArcsSet set = new ArcsSet(5.7 - Geometry.TWO_PI, 2.3, 1.0e-10);
         Assert.assertEquals(Geometry.TWO_PI - 3.4, set.getSize(), 1.0e-10);
         Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
-        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(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(2.3)));
+        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(5.7)));
+        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(S1Point.of(1.2)));
+        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(S1Point.of(8.5)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(8.7)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(3.0)));
         Assert.assertEquals(1, set.asList().size());
         Assert.assertEquals(5.7, set.asList().get(0).getInf(), 1.0e-10);
         Assert.assertEquals(2.3 + Geometry.TWO_PI, set.asList().get(0).getSup(), 1.0e-10);
@@ -72,7 +72,7 @@ public class ArcsSetTest {
         Arc     arc = new Arc(1.5 * Math.PI, 2.5 * Math.PI, 1.0e-10);
         ArcsSet.Split split = set.split(arc);
         for (double alpha = 0.0; alpha <= Geometry.TWO_PI; alpha += 0.01) {
-            S1Point p = new S1Point(alpha);
+            S1Point p = S1Point.of(alpha);
             if (alpha < 0.5 * Math.PI || alpha > 1.5 * Math.PI) {
                 Assert.assertEquals(Location.OUTSIDE, split.getPlus().checkPoint(p));
                 Assert.assertEquals(Location.INSIDE,  split.getMinus().checkPoint(p));
@@ -89,7 +89,7 @@ public class ArcsSetTest {
         Arc     arc = new Arc(Math.PI, Geometry.TWO_PI, 1.0e-10);
         ArcsSet.Split split = set.split(arc);
         for (double alpha = 0.01; alpha < Geometry.TWO_PI; alpha += 0.01) {
-            S1Point p = new S1Point(alpha);
+            S1Point p = S1Point.of(alpha);
             if (alpha > Math.PI) {
                 Assert.assertEquals(Location.OUTSIDE, split.getPlus().checkPoint(p));
                 Assert.assertEquals(Location.INSIDE,  split.getMinus().checkPoint(p));
@@ -99,11 +99,11 @@ public class ArcsSetTest {
             }
         }
 
-        S1Point zero = new S1Point(0.0);
+        S1Point zero = S1Point.of(0.0);
         Assert.assertEquals(Location.BOUNDARY,  split.getPlus().checkPoint(zero));
         Assert.assertEquals(Location.BOUNDARY,  split.getMinus().checkPoint(zero));
 
-        S1Point pi = new S1Point(Math.PI);
+        S1Point pi = S1Point.of(Math.PI);
         Assert.assertEquals(Location.BOUNDARY,  split.getPlus().checkPoint(pi));
         Assert.assertEquals(Location.BOUNDARY,  split.getMinus().checkPoint(pi));
 
@@ -118,9 +118,9 @@ public class ArcsSetTest {
     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)));
+        Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(9.0)));
         for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
-            Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(alpha)));
+            Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(alpha)));
         }
         Assert.assertEquals(1, set.asList().size());
         Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
@@ -132,9 +132,9 @@ public class ArcsSetTest {
     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)));
+        Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(9.0)));
         for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
-            Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(alpha)));
+            Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(alpha)));
         }
         Assert.assertEquals(1, set.asList().size());
         Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
@@ -163,8 +163,8 @@ public class ArcsSetTest {
     @Test
     public void testSpecialConstruction() {
         List<SubHyperplane<S1Point>> boundary = new ArrayList<>();
-        boundary.add(new LimitAngle(new S1Point(0.0), false, 1.0e-10).wholeHyperplane());
-        boundary.add(new LimitAngle(new S1Point(Geometry.TWO_PI - 1.0e-11), true, 1.0e-10).wholeHyperplane());
+        boundary.add(new LimitAngle(S1Point.of(0.0), false, 1.0e-10).wholeHyperplane());
+        boundary.add(new LimitAngle(S1Point.of(Geometry.TWO_PI - 1.0e-11), true, 1.0e-10).wholeHyperplane());
         ArcsSet set = new ArcsSet(boundary, 1.0e-10);
         Assert.assertEquals(Geometry.TWO_PI, set.getSize(), 1.0e-10);
         Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
@@ -190,20 +190,20 @@ public class ArcsSetTest {
 
         ArcsSet aMb = (ArcsSet) new RegionFactory<S1Point>().difference(a, b);
         for (int k = -2; k < 3; ++k) {
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(0.0 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(0.9 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(1.0 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(1.1 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(2.9 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(3.0 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(3.1 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(4.9 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(5.0 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(5.1 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(5.9 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(6.0 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(6.1 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(6.2 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(S1Point.of(0.0 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(S1Point.of(0.9 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(1.0 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(S1Point.of(1.1 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(S1Point.of(2.9 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(3.0 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(S1Point.of(3.1 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(S1Point.of(4.9 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(5.0 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(S1Point.of(5.1 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(S1Point.of(5.9 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(6.0 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(S1Point.of(6.1 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(S1Point.of(6.2 + k * Geometry.TWO_PI)));
         }
 
         List<Arc> aMbList = aMb.asList();
@@ -236,19 +236,19 @@ public class ArcsSetTest {
 
         ArcsSet aMb = (ArcsSet) new RegionFactory<S1Point>().intersection(a, b);
         for (int k = -2; k < 3; ++k) {
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(0.0 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(1.0 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(1.1 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(2.9 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(3.0 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(3.1 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(4.9 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(5.0 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(5.1 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(new S1Point(5.4 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(5.5 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(5.6 + k * Geometry.TWO_PI)));
-            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(new S1Point(6.2 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(S1Point.of(0.0 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(1.0 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(S1Point.of(1.1 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(S1Point.of(2.9 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(3.0 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(S1Point.of(3.1 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(S1Point.of(4.9 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(5.0 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(S1Point.of(5.1 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.INSIDE,   aMb.checkPoint(S1Point.of(5.4 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(5.5 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(S1Point.of(5.6 + k * Geometry.TWO_PI)));
+            Assert.assertEquals(Location.OUTSIDE,  aMb.checkPoint(S1Point.of(6.2 + k * Geometry.TWO_PI)));
         }
 
         List<Arc> aMbList = aMb.asList();
@@ -270,15 +270,15 @@ public class ArcsSetTest {
                                                               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)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(0.0)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(4.0)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(6.0)));
+        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(S1Point.of(1.2)));
+        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(S1Point.of(5.25)));
+        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(0.5)));
+        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(3.0)));
+        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(5.0)));
+        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(5.5)));
 
         List<Arc> list = set.asList();
         Assert.assertEquals(2, list.size());
@@ -337,8 +337,8 @@ public class ArcsSetTest {
     @Test
     public void testShiftedAngles() {
         for (int k = -2; k < 3; ++k) {
-            SubLimitAngle l1  = new LimitAngle(new S1Point(1.0 + k * Geometry.TWO_PI), false, 1.0e-10).wholeHyperplane();
-            SubLimitAngle l2  = new LimitAngle(new S1Point(1.5 + k * Geometry.TWO_PI), true,  1.0e-10).wholeHyperplane();
+            SubLimitAngle l1  = new LimitAngle(S1Point.of(1.0 + k * Geometry.TWO_PI), false, 1.0e-10).wholeHyperplane();
+            SubLimitAngle l2  = new LimitAngle(S1Point.of(1.5 + k * Geometry.TWO_PI), true,  1.0e-10).wholeHyperplane();
             ArcsSet set = new ArcsSet(new BSPTree<>(l1,
                                                             new BSPTree<S1Point>(Boolean.FALSE),
                                                             new BSPTree<>(l2,
@@ -349,9 +349,9 @@ public class ArcsSetTest {
                                       1.0e-10);
             for (double alpha = 1.0e-6; alpha < Geometry.TWO_PI; alpha += 0.001) {
                 if (alpha < 1 || alpha > 1.5) {
-                    Assert.assertEquals(Location.OUTSIDE, set.checkPoint(new S1Point(alpha)));
+                    Assert.assertEquals(Location.OUTSIDE, set.checkPoint(S1Point.of(alpha)));
                 } else {
-                    Assert.assertEquals(Location.INSIDE,  set.checkPoint(new S1Point(alpha)));
+                    Assert.assertEquals(Location.INSIDE,  set.checkPoint(S1Point.of(alpha)));
                 }
             }
         }
@@ -360,9 +360,9 @@ public class ArcsSetTest {
 
     @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();
+        SubLimitAngle l1 = new LimitAngle(S1Point.of(1.0), false, 1.0e-10).wholeHyperplane();
+        SubLimitAngle l2 = new LimitAngle(S1Point.of(2.0), true,  1.0e-10).wholeHyperplane();
+        SubLimitAngle l3 = new LimitAngle(S1Point.of(3.0), false, 1.0e-10).wholeHyperplane();
         new ArcsSet(new BSPTree<>(l1,
                                           new BSPTree<S1Point>(Boolean.FALSE),
                                           new BSPTree<>(l2,
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java
index 454979a..f9a9b3b 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java
@@ -25,7 +25,7 @@ public class LimitAngleTest {
     @Test
     public void testReversedLimit() {
         for (int k = -2; k < 3; ++k) {
-            LimitAngle l  = new LimitAngle(new S1Point(1.0 + k * Geometry.TWO_PI), false, 1.0e-10);
+            LimitAngle l  = new LimitAngle(S1Point.of(1.0 + k * Geometry.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));
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java
index 8b0b989..eac954d 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java
@@ -17,17 +17,20 @@
 package org.apache.commons.geometry.spherical.oned;
 
 import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.util.Coordinates;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class S1PointTest {
 
+    private static final double EPS = 1e-10;
+
     @Test
     public void testS1Point() {
         for (int k = -2; k < 3; ++k) {
-            S1Point p = new S1Point(1.0 + k * Geometry.TWO_PI);
-            Assert.assertEquals(Math.cos(1.0), p.getVector().getX(), 1.0e-10);
-            Assert.assertEquals(Math.sin(1.0), p.getVector().getY(), 1.0e-10);
+            S1Point p = S1Point.of(1.0 + k * Geometry.TWO_PI);
+            Assert.assertEquals(Math.cos(1.0), p.getVector().getX(), EPS);
+            Assert.assertEquals(Math.sin(1.0), p.getVector().getY(), EPS);
             Assert.assertFalse(p.isNaN());
         }
     }
@@ -35,14 +38,14 @@ public class S1PointTest {
     @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));
+        Assert.assertTrue(S1Point.NaN.equals(S1Point.of(Double.NaN)));
+        Assert.assertFalse(S1Point.of(1.0).equals(S1Point.NaN));
     }
 
     @Test
     public void testEquals() {
-        S1Point a = new S1Point(1.0);
-        S1Point b = new S1Point(1.0);
+        S1Point a = S1Point.of(1.0);
+        S1Point b = S1Point.of(1.0);
         Assert.assertEquals(a.hashCode(), b.hashCode());
         Assert.assertFalse(a == b);
         Assert.assertTrue(a.equals(b));
@@ -52,9 +55,44 @@ public class S1PointTest {
 
     @Test
     public void testDistance() {
-        S1Point a = new S1Point(1.0);
-        S1Point b = new S1Point(a.getAlpha() + 0.5 * Math.PI);
+        S1Point a = S1Point.of(1.0);
+        S1Point b = S1Point.of(a.getAlpha() + 0.5 * Math.PI);
         Assert.assertEquals(0.5 * Math.PI, a.distance(b), 1.0e-10);
     }
 
+    @Test
+    public void testToString() {
+        // act/assert
+        Assert.assertEquals("(0.0)", S1Point.of(0.0).toString());
+        Assert.assertEquals("(1.0)", S1Point.of(1.0).toString());
+    }
+
+    @Test
+    public void testParse() {
+        // act/assert
+        checkPoint(S1Point.parse("(0)"), 0.0);
+        checkPoint(S1Point.parse("(1)"), 1.0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParse_failure() {
+        // act/assert
+        S1Point.parse("abc");
+    }
+
+    @Test
+    public void testGetFactory() {
+        // act
+        Coordinates.Factory1D<S1Point> factory = S1Point.getFactory();
+
+        // assert
+        checkPoint(factory.create(0), 0);
+        checkPoint(factory.create(1), 1);
+        checkPoint(factory.create(Geometry.TWO_PI), 0);
+    }
+
+    private void checkPoint(S1Point p, double alpha) {
+        Assert.assertEquals(alpha, p.getAlpha(), EPS);
+    }
+
 }
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java
index a958dcf..7b9ad53 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java
@@ -47,7 +47,7 @@ public class CircleTest {
 
     @Test
     public void testXY() {
-        Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10);
+        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10);
         Assert.assertEquals(0.0, circle.getPointAt(0).distance(circle.getXAxis()), 1.0e-10);
         Assert.assertEquals(0.0, circle.getPointAt(0.5 * Math.PI).distance(circle.getYAxis()), 1.0e-10);
         Assert.assertEquals(0.5 * Math.PI, Vector3D.angle(circle.getXAxis(), circle.getYAxis()), 1.0e-10);
@@ -60,7 +60,7 @@ public class CircleTest {
 
     @Test
     public void testReverse() {
-        Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10);
+        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-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 * Math.PI).distance(reversed.getYAxis()), 1.0e-10);
@@ -82,7 +82,7 @@ public class CircleTest {
 
     @Test
     public void testPhase() {
-        Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10);
+        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10);
         Vector3D p = Vector3D.of(1, 2, -4);
         Vector3D samePhase = circle.getPointAt(circle.getPhase(p));
         Assert.assertEquals(0.0,
@@ -98,20 +98,20 @@ public class CircleTest {
 
     @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 * Math.PI, circle.toSubSpace(new S2Point(circle.getYAxis())).getAlpha(), 1.0e-10);
+        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10);
+        Assert.assertEquals(0.0, circle.toSubSpace(S2Point.of(circle.getXAxis())).getAlpha(), 1.0e-10);
+        Assert.assertEquals(0.5 * Math.PI, circle.toSubSpace(S2Point.of(circle.getYAxis())).getAlpha(), 1.0e-10);
         Vector3D p = Vector3D.of(1, 2, -4);
-        Assert.assertEquals(circle.getPhase(p), circle.toSubSpace(new S2Point(p)).getAlpha(), 1.0e-10);
+        Assert.assertEquals(circle.getPhase(p), circle.toSubSpace(S2Point.of(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);
+        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10);
         for (double alpha = 0; alpha < Geometry.TWO_PI; alpha += 0.1) {
             Vector3D p = Vector3D.linearCombination(Math.cos(alpha), circle.getXAxis(),
                                       Math.sin(alpha), circle.getYAxis());
-            Vector3D q = circle.toSpace(new S1Point(alpha)).getVector();
+            Vector3D q = circle.toSpace(S1Point.of(alpha)).getVector();
             Assert.assertEquals(0.0, p.distance(q), 1.0e-10);
             Assert.assertEquals(0.5 * Math.PI, Vector3D.angle(circle.getPole(), q), 1.0e-10);
         }
@@ -120,12 +120,12 @@ public class CircleTest {
     @Test
     public void testOffset() {
         Circle circle = new Circle(Vector3D.PLUS_Z, 1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(new S2Point(Vector3D.PLUS_X)),  1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(new S2Point(Vector3D.MINUS_X)), 1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(new S2Point(Vector3D.PLUS_Y)),  1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(new S2Point(Vector3D.MINUS_Y)), 1.0e-10);
-        Assert.assertEquals(-0.5 * Math.PI, circle.getOffset(new S2Point(Vector3D.PLUS_Z)),  1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, circle.getOffset(new S2Point(Vector3D.MINUS_Z)), 1.0e-10);
+        Assert.assertEquals(0.0,                circle.getOffset(S2Point.of(Vector3D.PLUS_X)),  1.0e-10);
+        Assert.assertEquals(0.0,                circle.getOffset(S2Point.of(Vector3D.MINUS_X)), 1.0e-10);
+        Assert.assertEquals(0.0,                circle.getOffset(S2Point.of(Vector3D.PLUS_Y)),  1.0e-10);
+        Assert.assertEquals(0.0,                circle.getOffset(S2Point.of(Vector3D.MINUS_Y)), 1.0e-10);
+        Assert.assertEquals(-0.5 * Math.PI, circle.getOffset(S2Point.of(Vector3D.PLUS_Z)),  1.0e-10);
+        Assert.assertEquals(0.5 * Math.PI, circle.getOffset(S2Point.of(Vector3D.MINUS_Z)), 1.0e-10);
 
     }
 
@@ -164,7 +164,7 @@ public class CircleTest {
                                       RotationConvention.VECTOR_OPERATOR);
             Transform<S2Point, S1Point> t = Circle.getTransform(r);
 
-            S2Point  p = new S2Point(Vector3D.of(sphRandom.nextVector()));
+            S2Point  p = S2Point.of(Vector3D.of(sphRandom.nextVector()));
             S2Point tp = t.apply(p);
             Assert.assertEquals(0.0, r.applyTo(p.getVector()).distance(tp.getVector()), 1.0e-10);
 
@@ -175,7 +175,7 @@ public class CircleTest {
             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(Geometry.TWO_PI * random.nextDouble()),
+            SubLimitAngle  sub = new LimitAngle(S1Point.of(Geometry.TWO_PI * random.nextDouble()),
                                                 random.nextBoolean(), 1.0e-10).wholeHyperplane();
             Vector3D psub = c.getPointAt(((LimitAngle) sub.getHyperplane()).getLocation().getAlpha());
             SubLimitAngle tsub = (SubLimitAngle) t.apply(sub, c, tc);
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java
index bbf5891..1661921 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java
@@ -18,45 +18,48 @@ package org.apache.commons.geometry.spherical.twod;
 
 
 import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.util.Coordinates;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class S2PointTest {
 
+    private static final double EPS = 1e-10;
+
     @Test
     public void testS2Point() {
         for (int k = -2; k < 3; ++k) {
-            S2Point p = new S2Point(1.0 + k * Geometry.TWO_PI, 1.4);
-            Assert.assertEquals(1.0 + k * Geometry.TWO_PI, p.getTheta(), 1.0e-10);
-            Assert.assertEquals(1.4, p.getPhi(), 1.0e-10);
-            Assert.assertEquals(Math.cos(1.0) * Math.sin(1.4), p.getVector().getX(), 1.0e-10);
-            Assert.assertEquals(Math.sin(1.0) * Math.sin(1.4), p.getVector().getY(), 1.0e-10);
-            Assert.assertEquals(Math.cos(1.4), p.getVector().getZ(), 1.0e-10);
+            S2Point p = S2Point.of(1.0 + k * Geometry.TWO_PI, 1.4);
+            Assert.assertEquals(1.0 + k * Geometry.TWO_PI, p.getTheta(), EPS);
+            Assert.assertEquals(1.4, p.getPhi(), EPS);
+            Assert.assertEquals(Math.cos(1.0) * Math.sin(1.4), p.getVector().getX(), EPS);
+            Assert.assertEquals(Math.sin(1.0) * Math.sin(1.4), p.getVector().getY(), EPS);
+            Assert.assertEquals(Math.cos(1.4), p.getVector().getZ(), EPS);
             Assert.assertFalse(p.isNaN());
         }
     }
 
     @Test(expected=IllegalArgumentException.class)
     public void testNegativePolarAngle() {
-        new S2Point(1.0, -1.0);
+        S2Point.of(1.0, -1.0);
     }
 
     @Test(expected=IllegalArgumentException.class)
     public void testTooLargePolarAngle() {
-        new S2Point(1.0, 3.5);
+        S2Point.of(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));
+        Assert.assertTrue(S2Point.NaN.equals(S2Point.of(Double.NaN, 1.0)));
+        Assert.assertFalse(S2Point.of(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);
+        S2Point a = S2Point.of(1.0, 1.0);
+        S2Point b = S2Point.of(1.0, 1.0);
         Assert.assertEquals(a.hashCode(), b.hashCode());
         Assert.assertFalse(a == b);
         Assert.assertTrue(a.equals(b));
@@ -66,12 +69,46 @@ public class S2PointTest {
 
     @Test
     public void testDistance() {
-        S2Point a = new S2Point(1.0, 0.5 * Math.PI);
-        S2Point b = new S2Point(a.getTheta() + 0.5 * Math.PI, a.getPhi());
+        S2Point a = S2Point.of(1.0, 0.5 * Math.PI);
+        S2Point b = S2Point.of(a.getTheta() + 0.5 * Math.PI, a.getPhi());
         Assert.assertEquals(0.5 * Math.PI, a.distance(b), 1.0e-10);
         Assert.assertEquals(Math.PI, a.distance(a.negate()), 1.0e-10);
         Assert.assertEquals(0.5 * Math.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);
+        Assert.assertEquals(0.0, S2Point.of(1.0, 0).distance(S2Point.of(2.0, 0)), 1.0e-10);
+    }
+
+    @Test
+    public void testToString() {
+        // act/assert
+        Assert.assertEquals("(0.0, 0.0)", S2Point.of(0.0, 0.0).toString());
+        Assert.assertEquals("(1.0, 2.0)", S2Point.of(1.0, 2.0).toString());
+    }
+
+    @Test
+    public void testParse() {
+        // act/assert
+        checkPoint(S2Point.parse("(0,0)"), 0.0, 0.0);
+        checkPoint(S2Point.parse("(1,2)"), 1.0, 2.0);
     }
 
+    @Test(expected = IllegalArgumentException.class)
+    public void testParse_failure() {
+        // act/assert
+        S2Point.parse("abc");
+    }
+
+    @Test
+    public void testGetFactory() {
+        // act
+        Coordinates.Factory2D<S2Point> factory = S2Point.getFactory();
+
+        // assert
+        checkPoint(factory.create(0, 0), 0, 0);
+        checkPoint(factory.create(1, 2), 1, 2);
+    }
+
+    private void checkPoint(S2Point p, double theta, double phi) {
+        Assert.assertEquals(theta, p.getTheta(), EPS);
+        Assert.assertEquals(phi, p.getPhi(), EPS);
+    }
 }
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java
index 0f52671..0f056e8 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java
@@ -43,7 +43,7 @@ public class SphericalPolygonsSetTest {
                                                              0x852fd2a0ed8d2f6dl));
         for (int i = 0; i < 1000; ++i) {
             Vector3D v = Vector3D.of(random.nextVector());
-            Assert.assertEquals(Location.INSIDE, full.checkPoint(new S2Point(v)));
+            Assert.assertEquals(Location.INSIDE, full.checkPoint(S2Point.of(v)));
         }
         Assert.assertEquals(4 * Math.PI, new SphericalPolygonsSet(0.01, new S2Point[0]).getSize(), 1.0e-10);
         Assert.assertEquals(0, new SphericalPolygonsSet(0.01, new S2Point[0]).getBoundarySize(), 1.0e-10);
@@ -61,7 +61,7 @@ public class SphericalPolygonsSetTest {
                                                              0x76d9205d6167b6ddl));
         for (int i = 0; i < 1000; ++i) {
             Vector3D v = Vector3D.of(random.nextVector());
-            Assert.assertEquals(Location.OUTSIDE, empty.checkPoint(new S2Point(v)));
+            Assert.assertEquals(Location.OUTSIDE, empty.checkPoint(S2Point.of(v)));
         }
         Assert.assertEquals(0, empty.getSize(), 1.0e-10);
         Assert.assertEquals(0, empty.getBoundarySize(), 1.0e-10);
@@ -81,11 +81,11 @@ public class SphericalPolygonsSetTest {
         for (int i = 0; i < 1000; ++i) {
             Vector3D v = Vector3D.of(random.nextVector());
             if (v.getZ() < -sinTol) {
-                Assert.assertEquals(Location.INSIDE, south.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.INSIDE, south.checkPoint(S2Point.of(v)));
             } else if (v.getZ() > sinTol) {
-                Assert.assertEquals(Location.OUTSIDE, south.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.OUTSIDE, south.checkPoint(S2Point.of(v)));
             } else {
-                Assert.assertEquals(Location.BOUNDARY, south.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.BOUNDARY, south.checkPoint(S2Point.of(v)));
             }
         }
         Assert.assertEquals(1, south.getBoundaryLoops().size());
@@ -117,11 +117,11 @@ public class SphericalPolygonsSetTest {
         for (int i = 0; i < 1000; ++i) {
             Vector3D v = Vector3D.of(random.nextVector());
             if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) {
-                Assert.assertEquals(Location.INSIDE, octant.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.INSIDE, octant.checkPoint(S2Point.of(v)));
             } else if ((v.getX() < -sinTol) || (v.getY() < -sinTol) || (v.getZ() < -sinTol)) {
-                Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(S2Point.of(v)));
             } else {
-                Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(S2Point.of(v)));
             }
         }
 
@@ -156,7 +156,7 @@ public class SphericalPolygonsSetTest {
         Assert.assertEquals(3, count);
 
         Assert.assertEquals(0.0,
-                            octant.getBarycenter().distance(new S2Point(Vector3D.of(1, 1, 1))),
+                            octant.getBarycenter().distance(S2Point.of(Vector3D.of(1, 1, 1))),
                             1.0e-10);
         Assert.assertEquals(0.5 * Math.PI, octant.getSize(), 1.0e-10);
 
@@ -166,7 +166,7 @@ public class SphericalPolygonsSetTest {
 
         EnclosingBall<S2Point> reversedCap =
                 ((SphericalPolygonsSet) factory.getComplement(octant)).getEnclosingCap();
-        Assert.assertEquals(0, reversedCap.getCenter().distance(new S2Point(Vector3D.of(-1, -1, -1))), 1.0e-10);
+        Assert.assertEquals(0, reversedCap.getCenter().distance(S2Point.of(Vector3D.of(-1, -1, -1))), 1.0e-10);
         Assert.assertEquals(Math.PI - Math.asin(1.0 / Math.sqrt(3)), reversedCap.getRadius(), 1.0e-10);
 
     }
@@ -182,11 +182,11 @@ public class SphericalPolygonsSetTest {
         for (int i = 0; i < 1000; ++i) {
             Vector3D v = Vector3D.of(random.nextVector());
             if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) {
-                Assert.assertEquals(Location.INSIDE, octant.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.INSIDE, octant.checkPoint(S2Point.of(v)));
             } else if ((v.getX() < -sinTol) || (v.getY() < -sinTol) || (v.getZ() < -sinTol)) {
-                Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(S2Point.of(v)));
             } else {
-                Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(S2Point.of(v)));
             }
         }
     }
@@ -208,11 +208,11 @@ public class SphericalPolygonsSetTest {
         for (int i = 0; i < 1000; ++i) {
             Vector3D v = Vector3D.of(random.nextVector());
             if (((v.getX() < -sinTol) || (v.getY() < -sinTol)) && (v.getZ() > sinTol)) {
-                Assert.assertEquals(Location.INSIDE, threeOctants.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.INSIDE, threeOctants.checkPoint(S2Point.of(v)));
             } else if (((v.getX() > sinTol) && (v.getY() > sinTol)) || (v.getZ() < -sinTol)) {
-                Assert.assertEquals(Location.OUTSIDE, threeOctants.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.OUTSIDE, threeOctants.checkPoint(S2Point.of(v)));
             } else {
-                Assert.assertEquals(Location.BOUNDARY, threeOctants.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.BOUNDARY, threeOctants.checkPoint(S2Point.of(v)));
             }
         }
 
@@ -274,14 +274,14 @@ public class SphericalPolygonsSetTest {
         boundary.add(create(Vector3D.PLUS_Z,  Vector3D.MINUS_Y, Vector3D.PLUS_X,  tol, 0.0, 0.5 * Math.PI));
         SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, tol);
 
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of( 1,  1,  1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(Vector3D.of(-1,  1,  1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(Vector3D.of(-1, -1,  1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(Vector3D.of( 1, -1,  1).normalize())));
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of( 1,  1, -1).normalize())));
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of(-1,  1, -1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(Vector3D.of(-1, -1, -1).normalize())));
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of( 1, -1, -1).normalize())));
+        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.of(Vector3D.of( 1,  1,  1).normalize())));
+        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(S2Point.of(Vector3D.of(-1,  1,  1).normalize())));
+        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(S2Point.of(Vector3D.of(-1, -1,  1).normalize())));
+        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(S2Point.of(Vector3D.of( 1, -1,  1).normalize())));
+        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.of(Vector3D.of( 1,  1, -1).normalize())));
+        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.of(Vector3D.of(-1,  1, -1).normalize())));
+        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(S2Point.of(Vector3D.of(-1, -1, -1).normalize())));
+        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.of(Vector3D.of( 1, -1, -1).normalize())));
 
         Assert.assertEquals(Geometry.TWO_PI, polygon.getSize(), 1.0e-10);
         Assert.assertEquals(3 * Math.PI, polygon.getBoundarySize(), 1.0e-10);
@@ -342,15 +342,15 @@ public class SphericalPolygonsSetTest {
         for (int i = 0; i < 1000; ++i) {
             Vector3D v = Vector3D.of(random.nextVector());
             if ((v.getX() < -sinTol) && (v.getY() < -sinTol) && (v.getZ() < -sinTol)) {
-                Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.INSIDE, polygon.checkPoint(S2Point.of(v)));
             } else if ((v.getX() < sinTol) && (v.getY() < sinTol) && (v.getZ() < sinTol)) {
-                Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(S2Point.of(v)));
             } else if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) {
-                Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.INSIDE, polygon.checkPoint(S2Point.of(v)));
             } else if ((v.getX() > -sinTol) && (v.getY() > -sinTol) && (v.getZ() > -sinTol)) {
-                Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(S2Point.of(v)));
             } else {
-                Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.of(v)));
             }
         }
 
@@ -366,17 +366,17 @@ public class SphericalPolygonsSetTest {
     public void testPartWithHole() {
         double tol = 0.01;
         double alpha = 0.7;
-        S2Point center = new S2Point(Vector3D.of(1, 1, 1));
+        S2Point center = S2Point.of(Vector3D.of(1, 1, 1));
         SphericalPolygonsSet hexa = new SphericalPolygonsSet(center.getVector(), Vector3D.PLUS_Z, alpha, 6, tol);
         SphericalPolygonsSet hole  = new SphericalPolygonsSet(tol,
-                                                              new S2Point(Math.PI / 6, Math.PI / 3),
-                                                              new S2Point(Math.PI / 3, Math.PI / 3),
-                                                              new S2Point(Math.PI / 4, Math.PI / 6));
+                                                              S2Point.of(Math.PI / 6, Math.PI / 3),
+                                                              S2Point.of(Math.PI / 3, Math.PI / 3),
+                                                              S2Point.of(Math.PI / 4, Math.PI / 6));
         SphericalPolygonsSet hexaWithHole =
                 (SphericalPolygonsSet) new RegionFactory<S2Point>().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(Math.PI / 4, phi));
+            Location l = hexaWithHole.checkPoint(S2Point.of(Math.PI / 4, phi));
             if (phi < Math.PI / 6 || phi > Math.PI / 3) {
                 Assert.assertEquals(Location.INSIDE,  l);
             } else {
@@ -428,24 +428,24 @@ public class SphericalPolygonsSetTest {
                             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);
+        double phi = S2Point.of(center).getPhi();
+        Assert.assertEquals(+0.207, concentric.projectToBoundary(S2Point.of(-0.60,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(-0.048, concentric.projectToBoundary(S2Point.of(-0.21,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(+0.027, concentric.projectToBoundary(S2Point.of(-0.10,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(-0.041, concentric.projectToBoundary(S2Point.of( 0.01,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(+0.049, concentric.projectToBoundary(S2Point.of( 0.16,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(-0.038, concentric.projectToBoundary(S2Point.of( 0.29,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(+0.097, concentric.projectToBoundary(S2Point.of( 0.48,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(-0.022, concentric.projectToBoundary(S2Point.of( 0.64,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(+0.072, concentric.projectToBoundary(S2Point.of( 0.79,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(-0.022, concentric.projectToBoundary(S2Point.of( 0.93,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(+0.091, concentric.projectToBoundary(S2Point.of( 1.08,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(-0.037, concentric.projectToBoundary(S2Point.of( 1.28,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(+0.051, concentric.projectToBoundary(S2Point.of( 1.40,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(-0.041, concentric.projectToBoundary(S2Point.of( 1.55,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(+0.027, concentric.projectToBoundary(S2Point.of( 1.67,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(-0.044, concentric.projectToBoundary(S2Point.of( 1.79,  phi)).getOffset(), 0.01);
+        Assert.assertEquals(+0.201, concentric.projectToBoundary(S2Point.of( 2.16,  phi)).getOffset(), 0.01);
 
     }
 
@@ -544,7 +544,7 @@ public class SphericalPolygonsSetTest {
     }
 
     private S2Point s2Point(double latitude, double longitude) {
-        return new S2Point(Math.toRadians(longitude), Math.toRadians(90.0 - latitude));
+        return S2Point.of(Math.toRadians(longitude), Math.toRadians(90.0 - latitude));
     }
 
 }


[commons-geometry] 05/08: Merge branch 'master' into geometry-3

Posted by er...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 6ecc77dfab8f6bd1bd168ad7148c6154bf520251
Merge: 519a17a 0f636b5
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Sat Jun 2 23:53:49 2018 -0400

    Merge branch 'master' into geometry-3



[commons-geometry] 07/08: GEOMETRY-3: adding @FunctionalInterface to Coordinates.Factory?D interfaces

Posted by er...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 7e501487ecdcd9cfbb565da3e3eb972fb2e932bf
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Sat Jun 16 15:00:23 2018 -0400

    GEOMETRY-3: adding @FunctionalInterface to Coordinates.Factory?D interfaces
---
 .../main/java/org/apache/commons/geometry/core/util/Coordinates.java   | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java
index 8ea6c77..c9c5fbc 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java
@@ -23,6 +23,7 @@ public class Coordinates {
     /** Interface for classes that create objects from a single coordinate value.
      * @param <T> The type created by this factory.
      */
+    @FunctionalInterface
     public interface Factory1D<T> {
 
         /** Creates a new instance of type T from the given coordinate value.
@@ -35,6 +36,7 @@ public class Coordinates {
     /** Interface for classes that create objects from two coordinate values.
      * @param <T> The type created by this factory.
      */
+    @FunctionalInterface
     public interface Factory2D<T> {
 
         /** Creates a new instance of type T from the given coordinate values.
@@ -48,6 +50,7 @@ public class Coordinates {
     /** Interface for classes that create objects from three coordinate values.
      * @param <T> The type created by this factory.
      */
+    @FunctionalInterface
     public interface Factory3D<T> {
 
         /** Creates a new instance of type T from the given coordinate values.


[commons-geometry] 08/08: GEOMETRY-3: simplifying parse and format functionality; renaming Coordinates.Factory?D interfaces to be more generic RealFunction interfaces

Posted by er...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 2331c8a18296ae25e1b4b85b98bc7b7dbb718d05
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Sat Jun 30 00:53:10 2018 -0400

    GEOMETRY-3: simplifying parse and format functionality; renaming Coordinates.Factory?D interfaces to be more generic RealFunction interfaces
---
 .../core/util/AbstractCoordinateParser.java        | 257 ------------
 .../commons/geometry/core/util/Coordinates.java    |  68 ----
 .../commons/geometry/core/util/RealFunction.java   |  31 ++
 .../commons/geometry/core/util/RealFunction2N.java |  32 ++
 .../commons/geometry/core/util/RealFunction3N.java |  33 ++
 .../geometry/core/util/SimpleCoordinateFormat.java | 202 ----------
 .../core/util/internal/SimpleTupleFormat.java      | 430 +++++++++++++++++++++
 .../geometry/core/util/internal/package-info.java  |  24 ++
 .../SimpleTupleFormatTest.java}                    |  88 ++---
 .../geometry/euclidean/oned/Cartesian1D.java       |   7 +
 .../commons/geometry/euclidean/oned/Point1D.java   |  20 +-
 .../commons/geometry/euclidean/oned/Vector1D.java  |  20 +-
 .../geometry/euclidean/threed/Cartesian3D.java     |   7 +
 .../commons/geometry/euclidean/threed/Point3D.java |  20 +-
 .../geometry/euclidean/threed/Vector3D.java        |  20 +-
 .../geometry/euclidean/twod/Cartesian2D.java       |   7 +
 .../commons/geometry/euclidean/twod/Point2D.java   |  20 +-
 .../commons/geometry/euclidean/twod/Vector2D.java  |  20 +-
 .../geometry/euclidean/oned/Cartesian1DTest.java   |  16 +
 .../geometry/euclidean/oned/Point1DTest.java       |   8 +-
 .../geometry/euclidean/oned/Vector1DTest.java      |  20 +-
 .../geometry/euclidean/threed/Cartesian3DTest.java |  16 +
 .../geometry/euclidean/threed/Point3DTest.java     |   8 +-
 .../geometry/euclidean/threed/Vector3DTest.java    |  18 +-
 .../geometry/euclidean/twod/Cartesian2DTest.java   |  16 +
 .../geometry/euclidean/twod/Point2DTest.java       |   8 +-
 .../geometry/euclidean/twod/Vector2DTest.java      |  18 +-
 .../commons/geometry/spherical/oned/S1Point.java   |  16 +-
 .../commons/geometry/spherical/twod/S2Point.java   |  16 +-
 .../geometry/spherical/oned/S1PointTest.java       |  10 +-
 .../geometry/spherical/twod/S2PointTest.java       |   8 +-
 31 files changed, 765 insertions(+), 719 deletions(-)

diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java
deleted file mode 100644
index ceb8527..0000000
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java
+++ /dev/null
@@ -1,257 +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.geometry.core.util;
-
-import java.text.ParsePosition;
-
-/** Abstract class providing basic parsing functionality for reading coordinate tuples
- * from strings.
- */
-public abstract class AbstractCoordinateParser {
-
-    /** String separating coordinate values */
-    private final String separator;
-
-    /** String used to signal the start of a coordinate tuple; may be null */
-    private final String prefix;
-
-    /** String used to signal the end of a coordinate tuple; may be null */
-    private final String suffix;
-
-    /** Simple constructor
-     * @param separator String used to separate coordinate values; must not be null.
-     * @param prefix String used to signal the start of a coordinate tuple; if null, no
-     *      string is expected at the start of the tuple
-     * @param suffix String used to signal the end of a coordinate tuple; if null, no
-     *      string is expected at the end of the tuple
-     */
-    protected AbstractCoordinateParser(String separator, String prefix, String suffix) {
-        this.separator = separator;
-        this.prefix = prefix;
-        this.suffix = suffix;
-    }
-
-    /** Returns the string used to separate coordinate values.
-     * @return the coordinate value separator string
-     */
-    public String getSeparator() {
-        return separator;
-    }
-
-    /** Returns the string used to signal the start of a coordinate tuple. This value may be null.
-     * @return the string used to begin each coordinate tuple or null
-     */
-    public String getPrefix() {
-        return prefix;
-    }
-
-    /** Returns the string used to signal the end of a coordinate tuple. This value may be null.
-     * @return the string used to end each coordinate tuple or null
-     */
-    public String getSuffix() {
-        return suffix;
-    }
-
-    /** Reads the configured prefix from the current position in the given string, ignoring any preceding
-     * whitespace, and advances the parsing position past the prefix sequence. An exception is thrown if the
-     * prefix is not found. Does nothing if the prefix is null.
-     * @param str the string being parsed
-     * @param pos the current parsing position
-     * @throws IllegalArgumentException if the configured prefix is not null and is not found at the current
-     *      parsing position, ignoring preceding whitespace
-     */
-    protected void readPrefix(String str, ParsePosition pos) throws IllegalArgumentException {
-        if (prefix != null) {
-            consumeWhitespace(str, pos);
-            readSequence(str, prefix, pos);
-        }
-    }
-
-    /** Reads and returns a coordinate value from the current position in the given string. An exception is thrown if a
-     * valid number is not found. The parsing position is advanced past the parsed number and any trailing separator.
-     * @param str the string being parsed
-     * @param pos the current parsing position
-     * @return the coordinate value
-     * @throws IllegalArgumentException if the configured prefix is not null and is not found at the current
-     *      parsing position, ignoring preceding whitespace
-     */
-    protected double readCoordinateValue(String str, ParsePosition pos) throws IllegalArgumentException {
-        final int startIdx = pos.getIndex();
-
-        int endIdx = str.indexOf(separator, startIdx);
-        if (endIdx < 0) {
-            if (suffix != null) {
-                endIdx = str.indexOf(suffix, startIdx);
-            }
-
-            if (endIdx < 0) {
-                endIdx = str.length();
-            }
-        }
-
-        String substr = str.substring(startIdx, endIdx);
-        try {
-            double value = Double.parseDouble(substr);
-
-            // advance the position and move past any terminating separator
-            pos.setIndex(endIdx);
-            matchSequence(str, separator, pos);
-
-            return value;
-        }
-        catch (NumberFormatException exc) {
-            fail(String.format("unable to parse number from string \"%s\"", substr), str, pos, exc);
-            return 0.0; // for the compiler
-        }
-    }
-
-    /** Reads the configured suffix from the current position in the given string, ignoring any preceding
-     * whitespace, and advances the parsing position past the suffix sequence. An exception is thrown if the
-     * suffix is not found. Does nothing if the suffix is null.
-     * @param str the string being parsed
-     * @param pos the current parsing position
-     * @throws IllegalArgumentException if the configured suffix is not null and is not found at the current
-     *      parsing position, ignoring preceding whitespace
-     */
-    protected void readSuffix(String str, ParsePosition pos) throws IllegalArgumentException {
-        if (suffix != null) {
-            consumeWhitespace(str, pos);
-            readSequence(str, suffix, pos);
-        }
-    }
-
-    /** Ends a parse operation by ensuring that all non-whitespace characters in the string have been parsed. An
-     * exception is thrown if extra content is found.
-     * @param str the string being parsed
-     * @param pos the current parsing position
-     * @throws IllegalArgumentException if extra non-whitespace content is found past the current parsing position
-     */
-    protected void endParse(String str, ParsePosition pos) throws IllegalArgumentException {
-        consumeWhitespace(str, pos);
-        if (pos.getIndex() != str.length()) {
-            fail("unexpected content", str, pos);
-        }
-    }
-
-    /** Advances {@code pos} past any whitespace characters in {@code str},
-     * starting at the current parse position index.
-     * @param str the input string
-     * @param pos the current parse position
-     */
-    protected void consumeWhitespace(String str, ParsePosition pos) {
-        int idx = pos.getIndex();
-        final int len = str.length();
-
-        for (; idx<len; ++idx) {
-            if (!Character.isWhitespace(str.codePointAt(idx))) {
-                break;
-            }
-        }
-
-        pos.setIndex(idx);
-    }
-
-    /** Returns a boolean indicating whether or not the input string {@code str}
-     * contains the string {@code seq} at the given parse index. If the match succeeds,
-     * the index of {@code pos} is moved to the first character after the match. If
-     * the match does not succeed, the parse position is left unchanged.
-     * @param str the string to match against
-     * @param seq the sequence to look for in {@code str}
-     * @param pos the parse position indicating the index in {@code str}
-     *      to attempt the match
-     * @return true if {@code str} contains exactly the same characters as {@code seq}
-     *      at {@code pos}; otherwise, false
-     */
-    protected boolean matchSequence(String str, String seq, ParsePosition pos) {
-        final int idx = pos.getIndex();
-        final int inputLength = str.length();
-        final int seqLength = seq.length();
-
-        int i = idx;
-        int s = 0;
-        for (; i<inputLength && s<seqLength; ++i, ++s) {
-            if (str.codePointAt(i) != seq.codePointAt(s)) {
-                break;
-            }
-        }
-
-        if (i <= inputLength && s == seqLength) {
-            pos.setIndex(idx + seqLength);
-            return true;
-        }
-        return false;
-    }
-
-    /** Reads the string given by {@code seq} from the given position in {@code str}.
-     * Throws an IllegalArgumentException if the sequence is not found at that position.
-     * @param str the string to match against
-     * @param seq the sequence to look for in {@code str}
-     * @param pos the parse position indicating the index in {@code str}
-     *      to attempt the match
-     * @throws IllegalArgumentException if {@code str} does not contain the characters from
-     *      {@code seq} at position {@code pos}
-     */
-    protected void readSequence(String str, String seq, ParsePosition pos) throws IllegalArgumentException {
-        if (!matchSequence(str, seq, pos)) {
-            final int idx = pos.getIndex();
-            final String actualSeq = str.substring(idx, Math.min(str.length(), idx + seq.length()));
-
-            fail(String.format("expected \"%s\" but found \"%s\"", seq, actualSeq), str, pos);
-        }
-    }
-
-    /** Aborts the current parsing operation by throwing an {@link IllegalArgumentException} with an informative
-     * error message.
-     * @param msg the error message
-     * @param str the string being parsed
-     * @param pos the current parse position
-     * @throws IllegalArgumentException the exception signaling a parse failure
-     */
-    protected void fail(String msg, String str, ParsePosition pos) throws IllegalArgumentException {
-        fail(msg, str, pos, null);
-    }
-
-    /** Aborts the current parsing operation by throwing an {@link IllegalArgumentException} with an informative
-     * error message.
-     * @param msg the error message
-     * @param str the string being parsed
-     * @param pos the current parse position
-     * @param cause the original cause of the error
-     * @throws IllegalArgumentException the exception signaling a parse failure
-     */
-    protected void fail(String msg, String str, ParsePosition pos, Throwable cause) throws IllegalArgumentException {
-        String fullMsg = String.format("Failed to parse string \"%s\" at index %d: %s", str, pos.getIndex(), msg);
-
-        throw new CoordinateParseException(fullMsg, cause);
-    }
-
-    /** Exception class for errors occurring during coordinate parsing.
-     */
-    private static class CoordinateParseException extends IllegalArgumentException {
-
-        /** Serializable version identifier */
-        private static final long serialVersionUID = 1494716029613981959L;
-
-        /** Simple constructor.
-         * @param msg the exception message
-         * @param cause the exception root cause
-         */
-        CoordinateParseException(String msg, Throwable cause) {
-            super(msg, cause);
-        }
-    }
-}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java
deleted file mode 100644
index c9c5fbc..0000000
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.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.geometry.core.util;
-
-/** Utility class for working with coordinate tuples.
- */
-public class Coordinates {
-
-    /** Interface for classes that create objects from a single coordinate value.
-     * @param <T> The type created by this factory.
-     */
-    @FunctionalInterface
-    public interface Factory1D<T> {
-
-        /** Creates a new instance of type T from the given coordinate value.
-         * @param a the coordinate value
-         * @return a new instance of type T
-         */
-        T create(double a);
-    }
-
-    /** Interface for classes that create objects from two coordinate values.
-     * @param <T> The type created by this factory.
-     */
-    @FunctionalInterface
-    public interface Factory2D<T> {
-
-        /** Creates a new instance of type T from the given coordinate values.
-         * @param a1 the first coordinate value
-         * @param a2 the second coordinate value
-         * @return a new instance of type T
-         */
-        T create(double a1, double a2);
-    }
-
-    /** Interface for classes that create objects from three coordinate values.
-     * @param <T> The type created by this factory.
-     */
-    @FunctionalInterface
-    public interface Factory3D<T> {
-
-        /** Creates a new instance of type T from the given coordinate values.
-         * @param a1 the first coordinate value
-         * @param a2 the second coordinate value
-         * @param a3 the third coordinate value
-         * @return a new instance of type T
-         */
-        T create(double a1, double a2, double a3);
-    }
-
-    /** Private constructor. */
-    private Coordinates() {
-    }
-}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/RealFunction.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/RealFunction.java
new file mode 100644
index 0000000..1b9acb6
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/RealFunction.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.util;
+
+/** Represents a function that accepts a single real number and returns
+ * a result.
+ * @param <T> The function return type.
+ */
+@FunctionalInterface
+public interface RealFunction<T> {
+
+    /** Apply the function and return the result.
+     * @param n the function argument
+     * @return the function result
+     */
+    T apply(double n);
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/RealFunction2N.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/RealFunction2N.java
new file mode 100644
index 0000000..20df7c7
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/RealFunction2N.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.util;
+
+/** Represents a function that accepts two real numbers and returns
+ * a result.
+ * @param <T> The function return type.
+ */
+@FunctionalInterface
+public interface RealFunction2N<T> {
+
+    /** Apply the function and return the result.
+     * @param n1 first function argument
+     * @param n2 second function argument
+     * @return the function result
+     */
+    T apply(double n1, double n2);
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/RealFunction3N.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/RealFunction3N.java
new file mode 100644
index 0000000..08e22e2
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/RealFunction3N.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.util;
+
+/** Represents a function that accepts three real numbers and returns
+ * a result.
+ * @param <T> The function return type.
+ */
+@FunctionalInterface
+public interface RealFunction3N<T> {
+
+    /** Apply the function and return the result.
+     * @param n1 first function argument
+     * @param n2 second function argument
+     * @param n3 third function argument
+     * @return the function result
+     */
+    T apply(double n1, double n2, double n3);
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java
deleted file mode 100644
index 6a4eb09..0000000
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java
+++ /dev/null
@@ -1,202 +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.geometry.core.util;
-
-import java.text.ParsePosition;
-
-/** Class for performing simple formatting and parsing of coordinate tuples in common dimensions.
- */
-public class SimpleCoordinateFormat extends AbstractCoordinateParser {
-
-    /** Default coordinate separator value */
-    private static final String DEFAULT_SEPARATOR = ",";
-
-    /** Space character */
-    private static final String SPACE = " ";
-
-    /** Static instance configured with default values for working with points. */
-    private static final SimpleCoordinateFormat DEFAULT_POINT_FORMAT =
-            new SimpleCoordinateFormat(DEFAULT_SEPARATOR, "(", ")");
-
-    /** Static instance configured with default values for working with vectors. */
-    private static final SimpleCoordinateFormat DEFAULT_VECTOR_FORMAT =
-            new SimpleCoordinateFormat(DEFAULT_SEPARATOR, "{", "}");
-
-    /** Creates a new format instance with the default separator value and the given
-     * tuple prefix and suffix.
-     * @param prefix coordinate tuple prefix; may be null
-     * @param suffix coordinate tuple suffix; may be null
-     */
-    public SimpleCoordinateFormat(String prefix, String suffix) {
-        this(DEFAULT_SEPARATOR, prefix, suffix);
-    }
-
-    /** Creates a new format instance with the given separator, prefix, and suffix.
-     * @param separator string separating coordinate values
-     * @param prefix coordinate tuple prefix; may be null
-     * @param suffix coordinate tuple suffix; may be null
-     */
-    public SimpleCoordinateFormat(String separator, String prefix, String suffix) {
-        super(separator, prefix, suffix);
-    }
-
-    /** Returns a 1D coordinate tuple string with the given value.
-     * @param a coordinate value
-     * @return 1D coordinate tuple string
-     */
-    public String format(double a) {
-        StringBuilder sb = new StringBuilder();
-
-        if (getPrefix() != null) {
-            sb.append(getPrefix());
-        }
-
-        sb.append(a);
-
-        if (getSuffix() != null) {
-            sb.append(getSuffix());
-        }
-
-        return sb.toString();
-    }
-
-    /** Returns a 2D coordinate tuple string with the given values.
-     * @param a1 first coordinate value
-     * @param a2 second coordinate value
-     * @return 2D coordinate tuple string
-     */
-    public String format(double a1, double a2) {
-        StringBuilder sb = new StringBuilder();
-
-        if (getPrefix() != null) {
-            sb.append(getPrefix());
-        }
-
-        sb.append(a1);
-        sb.append(getSeparator());
-        sb.append(SPACE);
-        sb.append(a2);
-
-        if (getSuffix() != null) {
-            sb.append(getSuffix());
-        }
-
-        return sb.toString();
-    }
-
-    /** Returns a 3D coordinate tuple string with the given values.
-     * @param a1 first coordinate value
-     * @param a2 second coordinate value
-     * @param a3 third coordinate value
-     * @return 3D coordinate tuple string
-     */
-    public String format(double a1, double a2, double a3) {
-        StringBuilder sb = new StringBuilder();
-
-        if (getPrefix() != null) {
-            sb.append(getPrefix());
-        }
-
-        sb.append(a1);
-        sb.append(getSeparator());
-        sb.append(SPACE);
-        sb.append(a2);
-        sb.append(getSeparator());
-        sb.append(SPACE);
-        sb.append(a3);
-
-        if (getSuffix() != null) {
-            sb.append(getSuffix());
-        }
-
-        return sb.toString();
-    }
-
-    /** Parses the given string as a 1D coordinate tuple and passes the coordinate value to the
-     * given factory. The object created by the factory is returned.
-     * @param <T> The type created by {@code factory}
-     * @param str the string to be parsed
-     * @param factory object that will be passed the parsed coordinate value
-     * @return object created by {@code factory}
-     * @throws IllegalArgumentException if the input string format is invalid
-     */
-    public <T> T parse(String str, Coordinates.Factory1D<T> factory) throws IllegalArgumentException {
-        final ParsePosition pos = new ParsePosition(0);
-
-        readPrefix(str, pos);
-        final double v = readCoordinateValue(str, pos);
-        readSuffix(str, pos);
-        endParse(str, pos);
-
-        return factory.create(v);
-    }
-
-    /** Parses the given string as a 2D coordinate tuple and passes the coordinate values to the
-     * given factory. The object created by the factory is returned.
-     * @param <T> The type created by {@code factory}
-     * @param str the string to be parsed
-     * @param factory object that will be passed the parsed coordinate values
-     * @return object created by {@code factory}
-     * @throws IllegalArgumentException if the input string format is invalid
-     */
-    public <T> T parse(String str, Coordinates.Factory2D<T> factory) throws IllegalArgumentException {
-        final ParsePosition pos = new ParsePosition(0);
-
-        readPrefix(str, pos);
-        final double v1 = readCoordinateValue(str, pos);
-        final double v2 = readCoordinateValue(str, pos);
-        readSuffix(str, pos);
-        endParse(str, pos);
-
-        return factory.create(v1, v2);
-    }
-
-    /** Parses the given string as a 3D coordinate tuple and passes the coordinate values to the
-     * given factory. The object created by the factory is returned.
-     * @param <T> The type created by {@code factory}
-     * @param str the string to be parsed
-     * @param factory object that will be passed the parsed coordinate values
-     * @return object created by {@code factory}
-     * @throws IllegalArgumentException if the input string format is invalid
-     */
-    public <T> T parse(String str, Coordinates.Factory3D<T> factory) throws IllegalArgumentException {
-        ParsePosition pos = new ParsePosition(0);
-
-        readPrefix(str, pos);
-        final double v1 = readCoordinateValue(str, pos);
-        final double v2 = readCoordinateValue(str, pos);
-        final double v3 = readCoordinateValue(str, pos);
-        readSuffix(str, pos);
-        endParse(str, pos);
-
-        return factory.create(v1, v2, v3);
-    }
-
-    /** Returns a default instance for working with points.
-     * @return instance configured with default values for points
-     */
-    public static SimpleCoordinateFormat getPointFormat() {
-        return DEFAULT_POINT_FORMAT;
-    }
-
-    /** Returns a default instance for working with vectors.
-     * @return instance configured with default values for vectors.
-     */
-    public static SimpleCoordinateFormat getVectorFormat() {
-        return DEFAULT_VECTOR_FORMAT;
-    }
-}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/internal/SimpleTupleFormat.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/internal/SimpleTupleFormat.java
new file mode 100644
index 0000000..84641cb
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/internal/SimpleTupleFormat.java
@@ -0,0 +1,430 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.util.internal;
+
+import java.text.ParsePosition;
+
+import org.apache.commons.geometry.core.util.RealFunction;
+import org.apache.commons.geometry.core.util.RealFunction2N;
+import org.apache.commons.geometry.core.util.RealFunction3N;
+
+/** Class for performing simple formatting and parsing of real number tuples.
+ */
+public class SimpleTupleFormat {
+
+    /** Default value separator string. */
+    private static final String DEFAULT_SEPARATOR = ",";
+
+    /** Space character */
+    private static final String SPACE = " ";
+
+    /** Static instance configured with default values. Tuples in this format
+     * are enclosed by parentheses and separated by commas.
+     */
+    private static final SimpleTupleFormat DEFAULT_INSTANCE =
+            new SimpleTupleFormat(",", "(", ")");
+
+    /** String separating tuple values */
+    private final String separator;
+
+    /** String used to signal the start of a tuple; may be null */
+    private final String prefix;
+
+    /** String used to signal the end of a tuple; may be null */
+    private final String suffix;
+
+    /** Constructs a new instance with the default string separator (a comma)
+     * and the given prefix and suffix.
+     * @param prefix String used to signal the start of a tuple; if null, no
+     *      string is expected at the start of the tuple
+     * @param suffix String used to signal the end of a tuple; if null, no
+     *      string is expected at the end of the tuple
+     */
+    public SimpleTupleFormat(String prefix, String suffix) {
+        this(DEFAULT_SEPARATOR, prefix, suffix);
+    }
+
+    /** Simple constructor.
+     * @param separator String used to separate tuple values; must not be null.
+     * @param prefix String used to signal the start of a tuple; if null, no
+     *      string is expected at the start of the tuple
+     * @param suffix String used to signal the end of a tuple; if null, no
+     *      string is expected at the end of the tuple
+     */
+    protected SimpleTupleFormat(String separator, String prefix, String suffix) {
+        this.separator = separator;
+        this.prefix = prefix;
+        this.suffix = suffix;
+    }
+
+    /** Return the string used to separate tuple values.
+     * @return the value separator string
+     */
+    public String getSeparator() {
+        return separator;
+    }
+
+    /** Return the string used to signal the start of a tuple. This value may be null.
+     * @return the string used to begin each tuple or null
+     */
+    public String getPrefix() {
+        return prefix;
+    }
+
+    /** Returns the string used to signal the end of a tuple. This value may be null.
+     * @return the string used to end each tuple or null
+     */
+    public String getSuffix() {
+        return suffix;
+    }
+
+    /** Return a tuple string with the given value.
+     * @param a value
+     * @return 1-tuple string
+     */
+    public String format(double a) {
+        StringBuilder sb = new StringBuilder();
+
+        if (prefix != null) {
+            sb.append(prefix);
+        }
+
+        sb.append(a);
+
+        if (suffix != null) {
+            sb.append(suffix);
+        }
+
+        return sb.toString();
+    }
+
+    /** Return a tuple string with the given values.
+     * @param a1 first value
+     * @param a2 second value
+     * @return 2-tuple string
+     */
+    public String format(double a1, double a2) {
+        StringBuilder sb = new StringBuilder();
+
+        if (prefix != null) {
+            sb.append(prefix);
+        }
+
+        sb.append(a1);
+        sb.append(separator);
+        sb.append(SPACE);
+        sb.append(a2);
+
+        if (suffix != null) {
+            sb.append(suffix);
+        }
+
+        return sb.toString();
+    }
+
+    /** Return a tuple string with the given values.
+     * @param a1 first value
+     * @param a2 second value
+     * @param a3 third value
+     * @return 3-tuple string
+     */
+    public String format(double a1, double a2, double a3) {
+        StringBuilder sb = new StringBuilder();
+
+        if (prefix != null) {
+            sb.append(prefix);
+        }
+
+        sb.append(a1);
+        sb.append(separator);
+        sb.append(SPACE);
+        sb.append(a2);
+        sb.append(separator);
+        sb.append(SPACE);
+        sb.append(a3);
+
+        if (suffix != null) {
+            sb.append(suffix);
+        }
+
+        return sb.toString();
+    }
+
+    /** Parse the given string as a 1-tuple and passes the tuple values to the
+     * given function. The function output is returned.
+     * @param <T> function return type
+     * @param str the string to be parsed
+     * @param fn function that will be passed the parsed tuple values
+     * @return object returned by {@code fn}
+     * @throws IllegalArgumentException if the input string format is invalid
+     */
+    public <T> T parse(String str, RealFunction<T> factory) throws IllegalArgumentException {
+        final ParsePosition pos = new ParsePosition(0);
+
+        readPrefix(str, pos);
+        final double v = readTupleValue(str, pos);
+        readSuffix(str, pos);
+        endParse(str, pos);
+
+        return factory.apply(v);
+    }
+
+    /** Parse the given string as a 2-tuple and passes the tuple values to the
+     * given function. The function output is returned.
+     * @param <T> function return type
+     * @param str the string to be parsed
+     * @param fn function that will be passed the parsed tuple values
+     * @return object returned by {@code fn}
+     * @throws IllegalArgumentException if the input string format is invalid
+     */
+    public <T> T parse(String str, RealFunction2N<T> factory) throws IllegalArgumentException {
+        final ParsePosition pos = new ParsePosition(0);
+
+        readPrefix(str, pos);
+        final double v1 = readTupleValue(str, pos);
+        final double v2 = readTupleValue(str, pos);
+        readSuffix(str, pos);
+        endParse(str, pos);
+
+        return factory.apply(v1, v2);
+    }
+
+    /** Parse the given string as a 3-tuple and passes the parsed values to the
+     * given function. The function output is returned.
+     * @param <T> function return type
+     * @param str the string to be parsed
+     * @param fn function that will be passed the parsed tuple values
+     * @return object returned by {@code fn}
+     * @throws IllegalArgumentException if the input string format is invalid
+     */
+    public <T> T parse(String str, RealFunction3N<T> fn) throws IllegalArgumentException {
+        ParsePosition pos = new ParsePosition(0);
+
+        readPrefix(str, pos);
+        final double v1 = readTupleValue(str, pos);
+        final double v2 = readTupleValue(str, pos);
+        final double v3 = readTupleValue(str, pos);
+        readSuffix(str, pos);
+        endParse(str, pos);
+
+        return fn.apply(v1, v2, v3);
+    }
+
+    /** Read the configured prefix from the current position in the given string, ignoring any preceding
+     * whitespace, and advance the parsing position past the prefix sequence. An exception is thrown if the
+     * prefix is not found. Does nothing if the prefix is null.
+     * @param str the string being parsed
+     * @param pos the current parsing position
+     * @throws IllegalArgumentException if the configured prefix is not null and is not found at the current
+     *      parsing position, ignoring preceding whitespace
+     */
+    private void readPrefix(String str, ParsePosition pos) throws IllegalArgumentException {
+        if (prefix != null) {
+            consumeWhitespace(str, pos);
+            readSequence(str, prefix, pos);
+        }
+    }
+
+    /** Read and return a tuple value from the current position in the given string. An exception is thrown if a
+     * valid number is not found. The parsing position is advanced past the parsed number and any trailing separator.
+     * @param str the string being parsed
+     * @param pos the current parsing position
+     * @return the tuple value
+     * @throws IllegalArgumentException if the configured prefix is not null and is not found at the current
+     *      parsing position, ignoring preceding whitespace
+     */
+    private double readTupleValue(String str, ParsePosition pos) throws IllegalArgumentException {
+        final int startIdx = pos.getIndex();
+
+        int endIdx = str.indexOf(separator, startIdx);
+        if (endIdx < 0) {
+            if (suffix != null) {
+                endIdx = str.indexOf(suffix, startIdx);
+            }
+
+            if (endIdx < 0) {
+                endIdx = str.length();
+            }
+        }
+
+        String substr = str.substring(startIdx, endIdx);
+        try {
+            double value = Double.parseDouble(substr);
+
+            // advance the position and move past any terminating separator
+            pos.setIndex(endIdx);
+            matchSequence(str, separator, pos);
+
+            return value;
+        }
+        catch (NumberFormatException exc) {
+            fail(String.format("unable to parse number from string \"%s\"", substr), str, pos, exc);
+            return 0.0; // for the compiler
+        }
+    }
+
+    /** Read the configured suffix from the current position in the given string, ignoring any preceding
+     * whitespace, and advance the parsing position past the suffix sequence. An exception is thrown if the
+     * suffix is not found. Does nothing if the suffix is null.
+     * @param str the string being parsed
+     * @param pos the current parsing position
+     * @throws IllegalArgumentException if the configured suffix is not null and is not found at the current
+     *      parsing position, ignoring preceding whitespace
+     */
+    private void readSuffix(String str, ParsePosition pos) throws IllegalArgumentException {
+        if (suffix != null) {
+            consumeWhitespace(str, pos);
+            readSequence(str, suffix, pos);
+        }
+    }
+
+    /** End a parse operation by ensuring that all non-whitespace characters in the string have been parsed. An
+     * exception is thrown if extra content is found.
+     * @param str the string being parsed
+     * @param pos the current parsing position
+     * @throws IllegalArgumentException if extra non-whitespace content is found past the current parsing position
+     */
+    private void endParse(String str, ParsePosition pos) throws IllegalArgumentException {
+        consumeWhitespace(str, pos);
+        if (pos.getIndex() != str.length()) {
+            fail("unexpected content", str, pos);
+        }
+    }
+
+    /** Advance {@code pos} past any whitespace characters in {@code str},
+     * starting at the current parse position index.
+     * @param str the input string
+     * @param pos the current parse position
+     */
+    private void consumeWhitespace(final String str, final ParsePosition pos) {
+        int idx = pos.getIndex();
+        final int len = str.length();
+
+        for (; idx<len; ++idx) {
+            if (!Character.isWhitespace(str.codePointAt(idx))) {
+                break;
+            }
+        }
+
+        pos.setIndex(idx);
+    }
+
+    /** Return a boolean indicating whether or not the input string {@code str}
+     * contains the string {@code seq} at the given parse index. If the match succeeds,
+     * the index of {@code pos} is moved to the first character after the match. If
+     * the match does not succeed, the parse position is left unchanged.
+     * @param str the string to match against
+     * @param seq the sequence to look for in {@code str}
+     * @param pos the parse position indicating the index in {@code str}
+     *      to attempt the match
+     * @return true if {@code str} contains exactly the same characters as {@code seq}
+     *      at {@code pos}; otherwise, false
+     */
+    private boolean matchSequence(final String str, final String seq, final ParsePosition pos) {
+        final int idx = pos.getIndex();
+        final int inputLength = str.length();
+        final int seqLength = seq.length();
+
+        int i = idx;
+        int s = 0;
+        for (; i<inputLength && s<seqLength; ++i, ++s) {
+            if (str.codePointAt(i) != seq.codePointAt(s)) {
+                break;
+            }
+        }
+
+        if (i <= inputLength && s == seqLength) {
+            pos.setIndex(idx + seqLength);
+            return true;
+        }
+        return false;
+    }
+
+    /** Read the string given by {@code seq} from the given position in {@code str}.
+     * Throws an IllegalArgumentException if the sequence is not found at that position.
+     * @param str the string to match against
+     * @param seq the sequence to look for in {@code str}
+     * @param pos the parse position indicating the index in {@code str}
+     *      to attempt the match
+     * @throws IllegalArgumentException if {@code str} does not contain the characters from
+     *      {@code seq} at position {@code pos}
+     */
+    private void readSequence(String str, String seq, ParsePosition pos) throws IllegalArgumentException {
+        if (!matchSequence(str, seq, pos)) {
+            final int idx = pos.getIndex();
+            final String actualSeq = str.substring(idx, Math.min(str.length(), idx + seq.length()));
+
+            fail(String.format("expected \"%s\" but found \"%s\"", seq, actualSeq), str, pos);
+        }
+    }
+
+    /** Abort the current parsing operation by throwing an {@link IllegalArgumentException} with an informative
+     * error message.
+     * @param msg the error message
+     * @param str the string being parsed
+     * @param pos the current parse position
+     * @throws IllegalArgumentException the exception signaling a parse failure
+     */
+    private void fail(String msg, String str, ParsePosition pos) throws IllegalArgumentException {
+        fail(msg, str, pos, null);
+    }
+
+    /** Abort the current parsing operation by throwing an {@link IllegalArgumentException} with an informative
+     * error message.
+     * @param msg the error message
+     * @param str the string being parsed
+     * @param pos the current parse position
+     * @param cause the original cause of the error
+     * @throws IllegalArgumentException the exception signaling a parse failure
+     */
+    private void fail(String msg, String str, ParsePosition pos, Throwable cause) throws IllegalArgumentException {
+        String fullMsg = String.format("Failed to parse string \"%s\" at index %d: %s", str, pos.getIndex(), msg);
+
+        throw new TupleParseException(fullMsg, cause);
+    }
+
+    /** Return an instance configured with default values. Tuples in this format
+     * are enclosed by parentheses and separated by commas.
+     *
+     * Ex:
+     * <pre>
+     * "(1.0)"
+     * "(1.0, 2.0)"
+     * "(1.0, 2.0, 3.0)"
+     * </pre>
+     * @return instance configured with default values
+     */
+    public static SimpleTupleFormat getDefault() {
+        return DEFAULT_INSTANCE;
+    }
+
+    /** Exception class for errors occurring during tuple parsing.
+     */
+    private static class TupleParseException extends IllegalArgumentException {
+
+        /** Serializable version identifier */
+        private static final long serialVersionUID = 20180629;
+
+        /** Simple constructor.
+         * @param msg the exception message
+         * @param cause the exception root cause
+         */
+        TupleParseException(String msg, Throwable cause) {
+            super(msg, cause);
+        }
+    }
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/internal/package-info.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/internal/package-info.java
new file mode 100644
index 0000000..547fc6b
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/internal/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ *
+ * <p>
+ * This package contains geometry utilities intended for internal use only.
+ * No guarantees are made for the stability of the contained APIs.
+ * </p>
+ */
+package org.apache.commons.geometry.core.util.internal;
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/internal/SimpleTupleFormatTest.java
similarity index 80%
rename from commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java
rename to commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/internal/SimpleTupleFormatTest.java
index 23202d7..a3e554b 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/internal/SimpleTupleFormatTest.java
@@ -14,22 +14,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.commons.geometry.core.util;
+package org.apache.commons.geometry.core.util.internal;
 
+import org.apache.commons.geometry.core.util.RealFunction;
+import org.apache.commons.geometry.core.util.RealFunction2N;
+import org.apache.commons.geometry.core.util.RealFunction3N;
 import org.junit.Assert;
 import org.junit.Test;
 
-public class SimpleCoordinateFormatTest {
+public class SimpleTupleFormatTest {
 
     private static final double EPS = 1e-10;
 
     private static final String OPEN_PAREN = "(";
     private static final String CLOSE_PAREN = ")";
 
-    private static Coordinates.Factory1D<Stub1D> FACTORY_1D = new Coordinates.Factory1D<Stub1D>() {
+    private static RealFunction<Stub1D> FACTORY_1D = new RealFunction<Stub1D>() {
 
         @Override
-        public Stub1D create(double v) {
+        public Stub1D apply(double v) {
             Stub1D result = new Stub1D();
             result.v = v;
 
@@ -37,10 +40,10 @@ public class SimpleCoordinateFormatTest {
         }
     };
 
-    private static Coordinates.Factory2D<Stub2D> FACTORY_2D = new Coordinates.Factory2D<Stub2D>() {
+    private static RealFunction2N<Stub2D> FACTORY_2D = new RealFunction2N<Stub2D>() {
 
         @Override
-        public Stub2D create(double v1, double v2) {
+        public Stub2D apply(double v1, double v2) {
             Stub2D result = new Stub2D();
             result.v1 = v1;
             result.v2 = v2;
@@ -49,10 +52,10 @@ public class SimpleCoordinateFormatTest {
         }
     };
 
-    private static Coordinates.Factory3D<Stub3D> FACTORY_3D = new Coordinates.Factory3D<Stub3D>() {
+    private static RealFunction3N<Stub3D> FACTORY_3D = new RealFunction3N<Stub3D>() {
 
         @Override
-        public Stub3D create(double v1, double v2, double v3) {
+        public Stub3D apply(double v1, double v2, double v3) {
             Stub3D result = new Stub3D();
             result.v1 = v1;
             result.v2 = v2;
@@ -65,7 +68,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testConstructor() {
         // act
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("|", "{", "}");
+        SimpleTupleFormat formatter = new SimpleTupleFormat("|", "{", "}");
 
         // assert
         Assert.assertEquals("|", formatter.getSeparator());
@@ -76,7 +79,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testConstructor_defaultSeparator() {
         // act
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("{", "}");
+        SimpleTupleFormat formatter = new SimpleTupleFormat("{", "}");
 
         // assert
         Assert.assertEquals(",", formatter.getSeparator());
@@ -87,7 +90,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testFormat1D() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
         Assert.assertEquals("(1.0)", formatter.format(1.0));
@@ -100,7 +103,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testFormat1D_noPrefixSuffix() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
 
         // act/assert
         Assert.assertEquals("1.0", formatter.format(1.0));
@@ -113,7 +116,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testFormat2D() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
         Assert.assertEquals("(1.0, -1.0)", formatter.format(1.0, -1.0));
@@ -125,7 +128,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testFormat2D_noPrefixSuffix() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
 
         // act/assert
         Assert.assertEquals("1.0, -1.0", formatter.format(1.0, -1.0));
@@ -137,7 +140,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testFormat3D() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
         Assert.assertEquals("(1.0, 0.0, -1.0)", formatter.format(1.0, 0.0, -1.0));
@@ -148,7 +151,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testFormat3D_noPrefixSuffix() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
 
         // act/assert
         Assert.assertEquals("1.0, 0.0, -1.0", formatter.format(1.0, 0.0, -1.0));
@@ -159,7 +162,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testFormat_longTokens() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("||", "<<", ">>");
+        SimpleTupleFormat formatter = new SimpleTupleFormat("||", "<<", ">>");
 
         // act/assert
         Assert.assertEquals("<<1.0>>", formatter.format(1.0));
@@ -170,7 +173,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testParse1D() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
         checkParse1D(formatter, "(1)", 1.0);
@@ -196,7 +199,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testParse1D_noPrefixSuffix() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
 
         // act/assert
         checkParse1D(formatter, "1", 1.0);
@@ -222,7 +225,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testParse1D_failure() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
         checkParse1DFailure(formatter, "", "index 0: expected \"(\" but found \"\"");
@@ -236,7 +239,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testParse2D() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
         checkParse2D(formatter, "(1,-2)", 1.0, -2.0);
@@ -260,7 +263,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testParse2D_noPrefixSuffix() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
 
         // act/assert
         checkParse2D(formatter, "1,-2", 1.0, -2.0);
@@ -284,7 +287,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testParse2D_failure() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
         checkParse2DFailure(formatter, "", "index 0: expected \"(\" but found \"\"");
@@ -298,7 +301,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testParse3D() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
         checkParse3D(formatter, "(1,-2,3)", 1.0, -2.0, 3.0);
@@ -321,7 +324,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testParse3D_noPrefixSuffix() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
 
         // act/assert
         checkParse3D(formatter, "1,-2,3", 1.0, -2.0, 3.0);
@@ -344,7 +347,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testParse3D_failure() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+        SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
 
         // act/assert
         checkParse3DFailure(formatter, "", "index 0: expected \"(\" but found \"\"");
@@ -358,7 +361,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testParse_longTokens() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("||", "<<", ">>");
+        SimpleTupleFormat formatter = new SimpleTupleFormat("||", "<<", ">>");
 
         // act/assert
         checkParse1D(formatter, "<<1.0>>", 1.0);
@@ -369,7 +372,7 @@ public class SimpleCoordinateFormatTest {
     @Test
     public void testParse_longTokens_failure() {
         // arrange
-        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("||", "<<", ">>");
+        SimpleTupleFormat formatter = new SimpleTupleFormat("||", "<<", ">>");
 
         // act/assert
         checkParse1DFailure(formatter, "<", "index 0: expected \"<<\" but found \"<\"");
@@ -379,9 +382,9 @@ public class SimpleCoordinateFormatTest {
     }
 
     @Test
-    public void testDefaultPointFormat() {
+    public void testDefaultInstance() {
         // act
-        SimpleCoordinateFormat formatter = SimpleCoordinateFormat.getPointFormat();
+        SimpleTupleFormat formatter = SimpleTupleFormat.getDefault();
 
         // assert
         Assert.assertEquals(",", formatter.getSeparator());
@@ -391,26 +394,13 @@ public class SimpleCoordinateFormatTest {
         Assert.assertEquals("(1.0, 2.0)", formatter.format(1, 2));
     }
 
-    @Test
-    public void testDefaultVectorFormat() {
-        // act
-        SimpleCoordinateFormat formatter = SimpleCoordinateFormat.getVectorFormat();
-
-        // assert
-        Assert.assertEquals(",", formatter.getSeparator());
-        Assert.assertEquals("{", formatter.getPrefix());
-        Assert.assertEquals("}", formatter.getSuffix());
-
-        Assert.assertEquals("{1.0, 2.0}", formatter.format(1, 2));
-    }
-
-    private void checkParse1D(SimpleCoordinateFormat formatter, String str, double v) {
+    private void checkParse1D(SimpleTupleFormat formatter, String str, double v) {
         Stub1D result = formatter.parse(str, FACTORY_1D);
 
         Assert.assertEquals(v, result.v, EPS);
     }
 
-    private void checkParse1DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) {
+    private void checkParse1DFailure(SimpleTupleFormat formatter, String str, String msgSubstr) {
         try {
             formatter.parse(str, FACTORY_1D);
             Assert.fail("Operation should have failed");
@@ -422,14 +412,14 @@ public class SimpleCoordinateFormatTest {
         }
     }
 
-    private void checkParse2D(SimpleCoordinateFormat formatter, String str, double v1, double v2) {
+    private void checkParse2D(SimpleTupleFormat formatter, String str, double v1, double v2) {
         Stub2D result = formatter.parse(str, FACTORY_2D);
 
         Assert.assertEquals(v1, result.v1, EPS);
         Assert.assertEquals(v2, result.v2, EPS);
     }
 
-    private void checkParse2DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) {
+    private void checkParse2DFailure(SimpleTupleFormat formatter, String str, String msgSubstr) {
         try {
             formatter.parse(str, FACTORY_2D);
             Assert.fail("Operation should have failed");
@@ -441,7 +431,7 @@ public class SimpleCoordinateFormatTest {
         }
     }
 
-    private void checkParse3D(SimpleCoordinateFormat formatter, String str, double v1, double v2, double v3) {
+    private void checkParse3D(SimpleTupleFormat formatter, String str, double v1, double v2, double v3) {
         Stub3D result = formatter.parse(str, FACTORY_3D);
 
         Assert.assertEquals(v1, result.v1, EPS);
@@ -449,7 +439,7 @@ public class SimpleCoordinateFormatTest {
         Assert.assertEquals(v3, result.v3, EPS);
     }
 
-    private void checkParse3DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) {
+    private void checkParse3DFailure(SimpleTupleFormat formatter, String str, String msgSubstr) {
         try {
             formatter.parse(str, FACTORY_3D);
             Assert.fail("Operation should have failed");
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Cartesian1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Cartesian1D.java
index 8d9b800..19ea67f 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Cartesian1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Cartesian1D.java
@@ -19,6 +19,7 @@ package org.apache.commons.geometry.euclidean.oned;
 import java.io.Serializable;
 
 import org.apache.commons.geometry.core.Spatial;
+import org.apache.commons.geometry.core.util.internal.SimpleTupleFormat;
 
 /** This class represents a Cartesian coordinate value in
  * one-dimensional Euclidean space.
@@ -64,4 +65,10 @@ public abstract class Cartesian1D implements Spatial, Serializable {
     public boolean isInfinite() {
         return !isNaN() && Double.isInfinite(x);
     }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return SimpleTupleFormat.getDefault().format(getX());
+    }
 }
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
index 3715c69..870ac6e 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
@@ -16,8 +16,8 @@
  */
 package org.apache.commons.geometry.euclidean.oned;
 
-import org.apache.commons.geometry.core.util.Coordinates;
-import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
+import org.apache.commons.geometry.core.util.RealFunction;
+import org.apache.commons.geometry.core.util.internal.SimpleTupleFormat;
 import org.apache.commons.geometry.euclidean.EuclideanPoint;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
@@ -49,12 +49,12 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D
     private static final long serialVersionUID = 7556674948671647925L;
 
     /** Factory for delegating instance creation. */
-    private static Coordinates.Factory1D<Point1D> FACTORY = new Coordinates.Factory1D<Point1D>() {
+    private static RealFunction<Point1D> FACTORY = new RealFunction<Point1D>() {
 
         /** {@inheritDoc} */
         @Override
-        public Point1D create(double a) {
-            return new Point1D(a);
+        public Point1D apply(double n) {
+            return new Point1D(n);
         }
     };
 
@@ -145,12 +145,6 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D
         return false;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public String toString() {
-        return SimpleCoordinateFormat.getPointFormat().format(getX());
-    }
-
     /** Returns a point with the given coordinate value.
      * @param x point coordinate
      * @return point instance
@@ -174,13 +168,13 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D
      * @throws IllegalArgumentException if the given string has an invalid format
      */
     public static Point1D parse(String str) throws IllegalArgumentException {
-        return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY);
+        return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
     /** Returns a factory object that can be used to created new point instances.
      * @return point factory instance
      */
-    public static Coordinates.Factory1D<Point1D> getFactory() {
+    public static RealFunction<Point1D> getFactory() {
         return FACTORY;
     }
 
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
index 0aab089..d9fd0c2 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
@@ -16,8 +16,8 @@
  */
 package org.apache.commons.geometry.euclidean.oned;
 
-import org.apache.commons.geometry.core.util.Coordinates;
-import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
+import org.apache.commons.geometry.core.util.RealFunction;
+import org.apache.commons.geometry.core.util.internal.SimpleTupleFormat;
 import org.apache.commons.geometry.euclidean.EuclideanVector;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
@@ -49,12 +49,12 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
     private static final long serialVersionUID = 1582116020164328846L;
 
     /** Factory for delegating instance creation. */
-    private static Coordinates.Factory1D<Vector1D> FACTORY = new Coordinates.Factory1D<Vector1D>() {
+    private static RealFunction<Vector1D> FACTORY = new RealFunction<Vector1D>() {
 
         /** {@inheritDoc} */
         @Override
-        public Vector1D create(double a) {
-            return new Vector1D(a);
+        public Vector1D apply(double n) {
+            return new Vector1D(n);
         }
     };
 
@@ -229,12 +229,6 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
         return false;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public String toString() {
-        return SimpleCoordinateFormat.getVectorFormat().format(getX());
-    }
-
     /** Returns a vector with the given coordinate value.
      * @param x vector coordinate
      * @return vector instance
@@ -258,13 +252,13 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
      * @throws IllegalArgumentException if the given string has an invalid format
      */
     public static Vector1D parse(String str) throws IllegalArgumentException {
-        return SimpleCoordinateFormat.getVectorFormat().parse(str, FACTORY);
+        return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
     /** Returns a factory object that can be used to created new vector instances.
      * @return vector factory instance
      */
-    public static Coordinates.Factory1D<Vector1D> getFactory() {
+    public static RealFunction<Vector1D> getFactory() {
         return FACTORY;
     }
 
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Cartesian3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Cartesian3D.java
index 6b619ac..8d680e9 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Cartesian3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Cartesian3D.java
@@ -20,6 +20,7 @@ package org.apache.commons.geometry.euclidean.threed;
 import java.io.Serializable;
 
 import org.apache.commons.geometry.core.Spatial;
+import org.apache.commons.geometry.core.util.internal.SimpleTupleFormat;
 
 /** This class represents a Cartesian coordinate value in
  * three-dimensional Euclidean space.
@@ -95,6 +96,12 @@ public abstract class Cartesian3D implements Spatial, Serializable {
         return !isNaN() && (Double.isInfinite(x) || Double.isInfinite(y) || Double.isInfinite(z));
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return SimpleTupleFormat.getDefault().format(getX(), getY(), getZ());
+    }
+
     /** Returns the Euclidean distance from this set of coordinates to the given coordinates.
      * @param other coordinates to compute the distance to.
      * @return Euclidean distance value
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
index f257425..c9841ac 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
@@ -17,8 +17,8 @@
 
 package org.apache.commons.geometry.euclidean.threed;
 
-import org.apache.commons.geometry.core.util.Coordinates;
-import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
+import org.apache.commons.geometry.core.util.RealFunction3N;
+import org.apache.commons.geometry.core.util.internal.SimpleTupleFormat;
 import org.apache.commons.geometry.euclidean.EuclideanPoint;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
@@ -47,12 +47,12 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
     private static final long serialVersionUID = 1313493323784566947L;
 
     /** Factory for delegating instance creation. */
-    private static Coordinates.Factory3D<Point3D> FACTORY = new Coordinates.Factory3D<Point3D>() {
+    private static RealFunction3N<Point3D> FACTORY = new RealFunction3N<Point3D>() {
 
         /** {@inheritDoc} */
         @Override
-        public Point3D create(double a1, double a2, double a3) {
-            return new Point3D(a1, a2, a3);
+        public Point3D apply(double n1, double n2, double n3) {
+            return new Point3D(n1, n2, n3);
         }
     };
 
@@ -154,12 +154,6 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
         return false;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public String toString() {
-        return SimpleCoordinateFormat.getPointFormat().format(getX(), getY(), getZ());
-    }
-
     /** Returns a point with the given coordinate values
      * @param x abscissa (first coordinate value)
      * @param y ordinate (second coordinate value)
@@ -197,13 +191,13 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
      * @throws IllegalArgumentException if the given string has an invalid format
      */
     public static Point3D parse(String str) throws IllegalArgumentException {
-        return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY);
+        return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
     /** Returns a factory object that can be used to created new point instances.
      * @return point factory instance
      */
-    public static Coordinates.Factory3D<Point3D> getFactory() {
+    public static RealFunction3N<Point3D> getFactory() {
         return FACTORY;
     }
 
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
index 9d1f258..5e9d952 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
@@ -16,8 +16,8 @@
  */
 package org.apache.commons.geometry.euclidean.threed;
 
-import org.apache.commons.geometry.core.util.Coordinates;
-import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
+import org.apache.commons.geometry.core.util.RealFunction3N;
+import org.apache.commons.geometry.core.util.internal.SimpleTupleFormat;
 import org.apache.commons.geometry.euclidean.EuclideanVector;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
@@ -67,12 +67,12 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
     private static final String ZERO_NORM_MSG = "Norm is zero";
 
     /** Factory for delegating instance creation. */
-    private static Coordinates.Factory3D<Vector3D> FACTORY = new Coordinates.Factory3D<Vector3D>() {
+    private static RealFunction3N<Vector3D> FACTORY = new RealFunction3N<Vector3D>() {
 
         /** {@inheritDoc} */
         @Override
-        public Vector3D create(double a1, double a2, double a3) {
-            return new Vector3D(a1, a2, a3);
+        public Vector3D apply(double n1, double n2, double n3) {
+            return new Vector3D(n1, n2, n3);
         }
     };
 
@@ -382,12 +382,6 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
         return false;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public String toString() {
-        return SimpleCoordinateFormat.getVectorFormat().format(getX(), getY(), getZ());
-    }
-
     /** Computes the dot product between to vectors. This method simply
      * calls {@code v1.dotProduct(v2)}.
      * @param v1 first vector
@@ -477,13 +471,13 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
      * @throws IllegalArgumentException if the given string has an invalid format
      */
     public static Vector3D parse(String str) throws IllegalArgumentException {
-        return SimpleCoordinateFormat.getVectorFormat().parse(str, FACTORY);
+        return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
     /** Returns a factory object that can be used to created new vector instances.
      * @return vector factory instance
      */
-    public static Coordinates.Factory3D<Vector3D> getFactory() {
+    public static RealFunction3N<Vector3D> getFactory() {
         return FACTORY;
     }
 
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Cartesian2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Cartesian2D.java
index d4c69b6..8ddb6a0 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Cartesian2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Cartesian2D.java
@@ -20,6 +20,7 @@ package org.apache.commons.geometry.euclidean.twod;
 import java.io.Serializable;
 
 import org.apache.commons.geometry.core.Spatial;
+import org.apache.commons.geometry.core.util.internal.SimpleTupleFormat;
 
 /** This class represents a set of Cartesian coordinates in
  * two-dimensional Euclidean space.
@@ -84,6 +85,12 @@ public abstract class Cartesian2D implements Spatial, Serializable {
         return !isNaN() && (Double.isInfinite(x) || Double.isInfinite(y));
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return SimpleTupleFormat.getDefault().format(getX(), getY());
+    }
+
     /** Returns the Euclidean distance from this value to the given value.
      * @param other the set of coordinates to compute the distance to
      * @return Euclidean distance
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
index c32777a..0d2af49 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
@@ -16,8 +16,8 @@
  */
 package org.apache.commons.geometry.euclidean.twod;
 
-import org.apache.commons.geometry.core.util.Coordinates;
-import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
+import org.apache.commons.geometry.core.util.RealFunction2N;
+import org.apache.commons.geometry.core.util.internal.SimpleTupleFormat;
 import org.apache.commons.geometry.euclidean.EuclideanPoint;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
@@ -46,12 +46,12 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D
     private static final long serialVersionUID = 266938651998679754L;
 
     /** Factory for delegating instance creation. */
-    private static Coordinates.Factory2D<Point2D> FACTORY = new Coordinates.Factory2D<Point2D>() {
+    private static RealFunction2N<Point2D> FACTORY = new RealFunction2N<Point2D>() {
 
         /** {@inheritDoc} */
         @Override
-        public Point2D create(double a1, double a2) {
-            return new Point2D(a1, a2);
+        public Point2D apply(double n1, double n2) {
+            return new Point2D(n1, n2);
         }
     };
 
@@ -143,12 +143,6 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D
         return false;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public String toString() {
-        return SimpleCoordinateFormat.getPointFormat().format(getX(), getY());
-    }
-
     /** Returns a point with the given coordinate values
      * @param x abscissa (first coordinate value)
      * @param y ordinate (second coordinate value)
@@ -185,13 +179,13 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D
      * @throws IllegalArgumentException if the given string has an invalid format
      */
     public static Point2D parse(String str) throws IllegalArgumentException {
-        return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY);
+        return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
     /** Returns a factory object that can be used to created new point instances.
      * @return point factory instance
      */
-    public static Coordinates.Factory2D<Point2D> getFactory() {
+    public static RealFunction2N<Point2D> getFactory() {
         return FACTORY;
     }
 
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
index ac8e380..42dc10d 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
@@ -16,8 +16,8 @@
  */
 package org.apache.commons.geometry.euclidean.twod;
 
-import org.apache.commons.geometry.core.util.Coordinates;
-import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
+import org.apache.commons.geometry.core.util.RealFunction2N;
+import org.apache.commons.geometry.core.util.internal.SimpleTupleFormat;
 import org.apache.commons.geometry.euclidean.EuclideanVector;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
@@ -61,12 +61,12 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
     private static final String ZERO_NORM_MSG = "Norm is zero";
 
     /** Factory for delegating instance creation. */
-    private static Coordinates.Factory2D<Vector2D> FACTORY = new Coordinates.Factory2D<Vector2D>() {
+    private static RealFunction2N<Vector2D> FACTORY = new RealFunction2N<Vector2D>() {
 
         /** {@inheritDoc} */
         @Override
-        public Vector2D create(double a1, double a2) {
-            return new Vector2D(a1, a2);
+        public Vector2D apply(double n1, double n2) {
+            return new Vector2D(n1, n2);
         }
     };
 
@@ -320,12 +320,6 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
         return false;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public String toString() {
-        return SimpleCoordinateFormat.getVectorFormat().format(getX(), getY());
-    }
-
     /** Computes the dot product between to vectors. This method simply
      * calls {@code v1.dotProduct(v2)}.
      * @param v1 first vector
@@ -384,13 +378,13 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
      * @throws IllegalArgumentException if the given string has an invalid format
      */
     public static Vector2D parse(String str) throws IllegalArgumentException {
-        return SimpleCoordinateFormat.getVectorFormat().parse(str, FACTORY);
+        return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
     /** Returns a factory object that can be used to created new vector instances.
      * @return vector factory instance
      */
-    public static Coordinates.Factory2D<Vector2D> getFactory() {
+    public static RealFunction2N<Vector2D> getFactory() {
         return FACTORY;
     }
 
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Cartesian1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Cartesian1DTest.java
index 835a368..afd6ca8 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Cartesian1DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Cartesian1DTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.geometry.euclidean.oned;
 
+import java.util.regex.Pattern;
+
 import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
 import org.junit.Assert;
 import org.junit.Test;
@@ -64,6 +66,20 @@ public class Cartesian1DTest {
         Assert.assertFalse(new StubCartesian1D(Double.NaN).isInfinite());
     }
 
+    @Test
+    public void testToString() {
+        // arrange
+        StubCartesian1D c = new StubCartesian1D(1);
+        Pattern pattern = Pattern.compile("\\(1.{0,2}\\)");
+
+        // act
+        String str = c.toString();
+
+        // assert
+        Assert.assertTrue("Expected string " + str + " to match regex " + pattern,
+                    pattern.matcher(str).matches());
+    }
+
     private static class StubCartesian1D extends Cartesian1D {
         private static final long serialVersionUID = 1L;
 
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
index bcde081..2ac7379 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
@@ -19,7 +19,7 @@ package org.apache.commons.geometry.euclidean.oned;
 
 import java.util.regex.Pattern;
 
-import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.RealFunction;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
@@ -231,11 +231,11 @@ public class Point1DTest {
     @Test
     public void testGetFactory() {
         // act
-        Coordinates.Factory1D<Point1D> factory = Point1D.getFactory();
+        RealFunction<Point1D> factory = Point1D.getFactory();
 
         // assert
-        checkPoint(factory.create(1), 1);
-        checkPoint(factory.create(-1), -1);
+        checkPoint(factory.apply(1), 1);
+        checkPoint(factory.apply(-1), -1);
     }
 
     @Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
index 7184476..9e81737 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
@@ -2,7 +2,7 @@ package org.apache.commons.geometry.euclidean.oned;
 
 import java.util.regex.Pattern;
 
-import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.RealFunction;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
@@ -281,7 +281,7 @@ public class Vector1DTest {
     public void testToString() {
         // arrange
         Vector1D v = Vector1D.of(3);
-        Pattern pattern = Pattern.compile("\\{3.{0,2}\\}");
+        Pattern pattern = Pattern.compile("\\(3.{0,2}\\)");
 
         // act
         String str = v.toString();
@@ -294,13 +294,13 @@ public class Vector1DTest {
     @Test
     public void testParse() {
         // act/assert
-        checkVector(Vector1D.parse("{1}"), 1);
-        checkVector(Vector1D.parse("{-1}"), -1);
+        checkVector(Vector1D.parse("(1)"), 1);
+        checkVector(Vector1D.parse("(-1)"), -1);
 
-        checkVector(Vector1D.parse("{0.01}"), 1e-2);
-        checkVector(Vector1D.parse("{-1e-3}"), -1e-3);
+        checkVector(Vector1D.parse("(0.01)"), 1e-2);
+        checkVector(Vector1D.parse("(-1e-3)"), -1e-3);
 
-        checkVector(Vector1D.parse("{NaN}"), Double.NaN);
+        checkVector(Vector1D.parse("(NaN)"), Double.NaN);
 
         checkVector(Vector1D.parse(Vector1D.ZERO.toString()), 0);
         checkVector(Vector1D.parse(Vector1D.ONE.toString()), 1);
@@ -339,11 +339,11 @@ public class Vector1DTest {
     @Test
     public void testGetFactory() {
         // act
-        Coordinates.Factory1D<Vector1D> factory = Vector1D.getFactory();
+        RealFunction<Vector1D> factory = Vector1D.getFactory();
 
         // assert
-        checkVector(factory.create(1), 1);
-        checkVector(factory.create(-1), -1);
+        checkVector(factory.apply(1), 1);
+        checkVector(factory.apply(-1), -1);
     }
 
     @Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Cartesian3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Cartesian3DTest.java
index 4e6205d..aadfe73 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Cartesian3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Cartesian3DTest.java
@@ -1,5 +1,7 @@
 package org.apache.commons.geometry.euclidean.threed;
 
+import java.util.regex.Pattern;
+
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -73,6 +75,20 @@ public class Cartesian3DTest {
         Assert.assertFalse(new StubCartesian3D(0, Double.NaN, Double.POSITIVE_INFINITY).isInfinite());
     }
 
+    @Test
+    public void testToString() {
+        // arrange
+        StubCartesian3D c = new StubCartesian3D(1, 2, 3);
+        Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}, 3.{0,2}\\)");
+
+        // act
+        String str = c.toString();
+
+        // assert
+        Assert.assertTrue("Expected string " + str + " to match regex " + pattern,
+                    pattern.matcher(str).matches());
+    }
+
     private static class StubCartesian3D extends Cartesian3D {
         private static final long serialVersionUID = 1L;
 
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java
index d20d918..d2959dc 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java
@@ -18,7 +18,7 @@ package org.apache.commons.geometry.euclidean.threed;
 
 import java.util.regex.Pattern;
 
-import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.RealFunction3N;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
@@ -245,11 +245,11 @@ public class Point3DTest {
     @Test
     public void testGetFactory() {
         // act
-        Coordinates.Factory3D<Point3D> factory = Point3D.getFactory();
+        RealFunction3N<Point3D> factory = Point3D.getFactory();
 
         // assert
-        checkPoint(factory.create(1, 2, 3), 1, 2, 3);
-        checkPoint(factory.create(-1, -2, -3), -1, -2, -3);
+        checkPoint(factory.apply(1, 2, 3), 1, 2, 3);
+        checkPoint(factory.apply(-1, -2, -3), -1, -2, -3);
     }
 
     @Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
index c9b3cf9..17e6a36 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
@@ -20,7 +20,7 @@ package org.apache.commons.geometry.euclidean.threed;
 import java.util.regex.Pattern;
 
 import org.apache.commons.geometry.core.Geometry;
-import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.RealFunction3N;
 import org.apache.commons.numbers.core.Precision;
 import org.apache.commons.rng.UniformRandomProvider;
 import org.apache.commons.rng.simple.RandomSource;
@@ -619,7 +619,7 @@ public class Vector3DTest {
     public void testToString() {
         // arrange
         Vector3D v = Vector3D.of(1, 2, 3);
-        Pattern pattern = Pattern.compile("\\{1.{0,2}, 2.{0,2}, 3.{0,2}\\}");
+        Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}, 3.{0,2}\\)");
 
         // act
         String str = v.toString();
@@ -632,12 +632,12 @@ public class Vector3DTest {
     @Test
     public void testParse() {
         // act/assert
-        checkVector(Vector3D.parse("{1, 2, 3}"), 1, 2, 3);
-        checkVector(Vector3D.parse("{-1, -2, -3}"), -1, -2, -3);
+        checkVector(Vector3D.parse("(1, 2, 3)"), 1, 2, 3);
+        checkVector(Vector3D.parse("(-1, -2, -3)"), -1, -2, -3);
 
-        checkVector(Vector3D.parse("{0.01, -1e-3, 0}"), 1e-2, -1e-3, 0);
+        checkVector(Vector3D.parse("(0.01, -1e-3, 0)"), 1e-2, -1e-3, 0);
 
-        checkVector(Vector3D.parse("{NaN, -Infinity, Infinity}"), Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+        checkVector(Vector3D.parse("(NaN, -Infinity, Infinity)"), Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
 
         checkVector(Vector3D.parse(Vector3D.ZERO.toString()), 0, 0, 0);
         checkVector(Vector3D.parse(Vector3D.MINUS_X.toString()), -1, 0, 0);
@@ -691,11 +691,11 @@ public class Vector3DTest {
     @Test
     public void testGetFactory() {
         // act
-        Coordinates.Factory3D<Vector3D> factory = Vector3D.getFactory();
+        RealFunction3N<Vector3D> factory = Vector3D.getFactory();
 
         // assert
-        checkVector(factory.create(1, 2, 3), 1, 2, 3);
-        checkVector(factory.create(-1, -2, -3), -1, -2, -3);
+        checkVector(factory.apply(1, 2, 3), 1, 2, 3);
+        checkVector(factory.apply(-1, -2, -3), -1, -2, -3);
     }
 
     @Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Cartesian2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Cartesian2DTest.java
index b8c7238..e3d5127 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Cartesian2DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Cartesian2DTest.java
@@ -1,5 +1,7 @@
 package org.apache.commons.geometry.euclidean.twod;
 
+import java.util.regex.Pattern;
+
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -68,6 +70,20 @@ public class Cartesian2DTest {
         Assert.assertFalse(new StubCartesian2D(Double.NaN, Double.POSITIVE_INFINITY).isInfinite());
     }
 
+    @Test
+    public void testToString() {
+        // arrange
+        StubCartesian2D c = new StubCartesian2D(1, 2);
+        Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}\\)");
+
+        // act
+        String str = c.toString();
+
+        // assert
+        Assert.assertTrue("Expected string " + str + " to match regex " + pattern,
+                    pattern.matcher(str).matches());
+    }
+
     private static class StubCartesian2D extends Cartesian2D {
         private static final long serialVersionUID = 1L;
 
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java
index 20d95ad..d26f002 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java
@@ -18,7 +18,7 @@ package org.apache.commons.geometry.euclidean.twod;
 
 import java.util.regex.Pattern;
 
-import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.RealFunction2N;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
@@ -222,11 +222,11 @@ public class Point2DTest {
     @Test
     public void testGetFactory() {
         // act
-        Coordinates.Factory2D<Point2D> factory = Point2D.getFactory();
+        RealFunction2N<Point2D> factory = Point2D.getFactory();
 
         // assert
-        checkPoint(factory.create(1, 2), 1, 2);
-        checkPoint(factory.create(-1, -2), -1, -2);
+        checkPoint(factory.apply(1, 2), 1, 2);
+        checkPoint(factory.apply(-1, -2), -1, -2);
     }
 
     @Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
index 13208c0..fa130e8 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
@@ -3,7 +3,7 @@ package org.apache.commons.geometry.euclidean.twod;
 import java.util.regex.Pattern;
 
 import org.apache.commons.geometry.core.Geometry;
-import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.RealFunction2N;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
@@ -421,7 +421,7 @@ public class Vector2DTest {
     public void testToString() {
         // arrange
         Vector2D v = Vector2D.of(1, 2);
-        Pattern pattern = Pattern.compile("\\{1.{0,2}, 2.{0,2}\\}");
+        Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}\\)");
 
         // act
         String str = v.toString();
@@ -434,12 +434,12 @@ public class Vector2DTest {
     @Test
     public void testParse() {
         // act/assert
-        checkVector(Vector2D.parse("{1, 2}"), 1, 2);
-        checkVector(Vector2D.parse("{-1, -2}"), -1, -2);
+        checkVector(Vector2D.parse("(1, 2)"), 1, 2);
+        checkVector(Vector2D.parse("(-1, -2)"), -1, -2);
 
-        checkVector(Vector2D.parse("{0.01, -1e-3}"), 1e-2, -1e-3);
+        checkVector(Vector2D.parse("(0.01, -1e-3)"), 1e-2, -1e-3);
 
-        checkVector(Vector2D.parse("{NaN, -Infinity}"), Double.NaN, Double.NEGATIVE_INFINITY);
+        checkVector(Vector2D.parse("(NaN, -Infinity)"), Double.NaN, Double.NEGATIVE_INFINITY);
 
         checkVector(Vector2D.parse(Vector2D.ZERO.toString()), 0, 0);
         checkVector(Vector2D.parse(Vector2D.MINUS_X.toString()), -1, 0);
@@ -487,11 +487,11 @@ public class Vector2DTest {
     @Test
     public void testGetFactory() {
         // act
-        Coordinates.Factory2D<Vector2D> factory = Vector2D.getFactory();
+        RealFunction2N<Vector2D> factory = Vector2D.getFactory();
 
         // assert
-        checkVector(factory.create(1, 2), 1, 2);
-        checkVector(factory.create(-1, -2), -1, -2);
+        checkVector(factory.apply(1, 2), 1, 2);
+        checkVector(factory.apply(-1, -2), -1, -2);
     }
 
     @Test
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
index 7cced20..9dd2d32 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
@@ -19,8 +19,8 @@ package org.apache.commons.geometry.spherical.oned;
 import java.io.Serializable;
 
 import org.apache.commons.geometry.core.Point;
-import org.apache.commons.geometry.core.util.Coordinates;
-import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
+import org.apache.commons.geometry.core.util.RealFunction;
+import org.apache.commons.geometry.core.util.internal.SimpleTupleFormat;
 import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.numbers.angle.PlaneAngleRadians;
 
@@ -38,12 +38,12 @@ public final class S1Point implements Point<S1Point>, Serializable {
     private static final long serialVersionUID = 20131218L;
 
     /** Factory for delegating instance creation. */
-    private static Coordinates.Factory1D<S1Point> FACTORY = new Coordinates.Factory1D<S1Point>() {
+    private static RealFunction<S1Point> FACTORY = new RealFunction<S1Point>() {
 
         /** {@inheritDoc} */
         @Override
-        public S1Point create(double a) {
-            return S1Point.of(a);
+        public S1Point apply(double n) {
+            return S1Point.of(n);
         }
     };
 
@@ -167,7 +167,7 @@ public final class S1Point implements Point<S1Point>, Serializable {
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return SimpleCoordinateFormat.getPointFormat().format(getAlpha());
+        return SimpleTupleFormat.getDefault().format(getAlpha());
     }
 
     /** Creates a new point instance from the given azimuthal coordinate value.
@@ -189,13 +189,13 @@ public final class S1Point implements Point<S1Point>, Serializable {
      * @throws IllegalArgumentException if the given string has an invalid format
      */
     public static S1Point parse(String str) throws IllegalArgumentException {
-        return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY);
+        return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
     /** Returns a factory object that can be used to created new point instances.
      * @return point factory instance
      */
-    public static Coordinates.Factory1D<S1Point> getFactory() {
+    public static RealFunction<S1Point> getFactory() {
         return FACTORY;
     }
 }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
index f8d3f4e..e5b2fbb 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
@@ -19,8 +19,8 @@ package org.apache.commons.geometry.spherical.twod;
 import java.io.Serializable;
 
 import org.apache.commons.geometry.core.Point;
-import org.apache.commons.geometry.core.util.Coordinates;
-import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
+import org.apache.commons.geometry.core.util.RealFunction2N;
+import org.apache.commons.geometry.core.util.internal.SimpleTupleFormat;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
 
 /** This class represents a point on the 2-sphere.
@@ -62,12 +62,12 @@ public final class S2Point implements Point<S2Point>, Serializable {
     private static final long serialVersionUID = 20131218L;
 
     /** Factory for delegating instance creation. */
-    private static Coordinates.Factory2D<S2Point> FACTORY = new Coordinates.Factory2D<S2Point>() {
+    private static RealFunction2N<S2Point> FACTORY = new RealFunction2N<S2Point>() {
 
         /** {@inheritDoc} */
         @Override
-        public S2Point create(double a1, double a2) {
-            return S2Point.of(a1, a2);
+        public S2Point apply(double n1, double n2) {
+            return S2Point.of(n1, n2);
         }
     };
 
@@ -209,7 +209,7 @@ public final class S2Point implements Point<S2Point>, Serializable {
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return SimpleCoordinateFormat.getPointFormat().format(getTheta(), getPhi());
+        return SimpleTupleFormat.getDefault().format(getTheta(), getPhi());
     }
 
     /** Build a vector from its spherical coordinates
@@ -263,13 +263,13 @@ public final class S2Point implements Point<S2Point>, Serializable {
      * @throws IllegalArgumentException if the given string has an invalid format
      */
     public static S2Point parse(String str) throws IllegalArgumentException {
-        return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY);
+        return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
     /** Returns a factory object that can be used to created new point instances.
      * @return point factory instance
      */
-    public static Coordinates.Factory2D<S2Point> getFactory() {
+    public static RealFunction2N<S2Point> getFactory() {
         return FACTORY;
     }
 }
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java
index eac954d..e4f8b08 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java
@@ -17,7 +17,7 @@
 package org.apache.commons.geometry.spherical.oned;
 
 import org.apache.commons.geometry.core.Geometry;
-import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.RealFunction;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -83,12 +83,12 @@ public class S1PointTest {
     @Test
     public void testGetFactory() {
         // act
-        Coordinates.Factory1D<S1Point> factory = S1Point.getFactory();
+        RealFunction<S1Point> factory = S1Point.getFactory();
 
         // assert
-        checkPoint(factory.create(0), 0);
-        checkPoint(factory.create(1), 1);
-        checkPoint(factory.create(Geometry.TWO_PI), 0);
+        checkPoint(factory.apply(0), 0);
+        checkPoint(factory.apply(1), 1);
+        checkPoint(factory.apply(Geometry.TWO_PI), 0);
     }
 
     private void checkPoint(S1Point p, double alpha) {
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java
index 1661921..1a04010 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java
@@ -18,7 +18,7 @@ package org.apache.commons.geometry.spherical.twod;
 
 
 import org.apache.commons.geometry.core.Geometry;
-import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.RealFunction2N;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -100,11 +100,11 @@ public class S2PointTest {
     @Test
     public void testGetFactory() {
         // act
-        Coordinates.Factory2D<S2Point> factory = S2Point.getFactory();
+        RealFunction2N<S2Point> factory = S2Point.getFactory();
 
         // assert
-        checkPoint(factory.create(0, 0), 0, 0);
-        checkPoint(factory.create(1, 2), 1, 2);
+        checkPoint(factory.apply(0, 0), 0, 0);
+        checkPoint(factory.apply(1, 2), 1, 2);
     }
 
     private void checkPoint(S2Point p, double theta, double phi) {


[commons-geometry] 01/08: GEOMETRY-3: making euclidean point and vector constructors private

Posted by er...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit e97c5355668643a0dd26611c95900e2e5e67e4fc
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Tue May 22 15:37:48 2018 -0400

    GEOMETRY-3: making euclidean point and vector constructors private
---
 .../threed/enclosing/SphereGenerator.java          |    2 +-
 .../euclidean/twod/enclosing/DiskGenerator.java    |    2 +-
 .../geometry/enclosing/WelzlEncloser2DTest.java    |    4 +-
 .../geometry/enclosing/WelzlEncloser3DTest.java    |   58 +-
 .../threed/enclosing/SphereGeneratorTest.java      |   78 +-
 .../twod/enclosing/DiskGeneratorTest.java          |   32 +-
 .../geometry/euclidean/oned/IntervalsSet.java      |   10 +-
 .../commons/geometry/euclidean/oned/Point1D.java   |   15 +-
 .../commons/geometry/euclidean/oned/Vector1D.java  |   24 +-
 .../commons/geometry/euclidean/threed/Line.java    |    2 +-
 .../euclidean/threed/OutlineExtractor.java         |    4 +-
 .../commons/geometry/euclidean/threed/Plane.java   |    4 +-
 .../commons/geometry/euclidean/threed/Point3D.java |   14 +-
 .../geometry/euclidean/threed/PolyhedronsSet.java  |   16 +-
 .../geometry/euclidean/threed/Rotation.java        |    8 +-
 .../commons/geometry/euclidean/threed/SubLine.java |    4 +-
 .../geometry/euclidean/threed/Vector3D.java        |   42 +-
 .../commons/geometry/euclidean/twod/Line.java      |   10 +-
 .../commons/geometry/euclidean/twod/Point2D.java   |   14 +-
 .../geometry/euclidean/twod/PolygonsSet.java       |   22 +-
 .../commons/geometry/euclidean/twod/Segment.java   |    2 +-
 .../commons/geometry/euclidean/twod/SubLine.java   |    4 +-
 .../commons/geometry/euclidean/twod/Vector2D.java  |   32 +-
 .../core/partitioning/CharacterizationTest.java    |  104 +-
 .../geometry/euclidean/EuclideanTestUtils.java     |    8 +-
 .../geometry/euclidean/oned/IntervalsSetTest.java  |   68 +-
 .../geometry/euclidean/oned/OrientedPointTest.java |   64 +-
 .../geometry/euclidean/oned/Point1DTest.java       |   14 +-
 .../euclidean/oned/SubOrientedPointTest.java       |   30 +-
 .../geometry/euclidean/threed/LineTest.java        |   64 +-
 .../geometry/euclidean/threed/PLYParser.java       |    2 +-
 .../geometry/euclidean/threed/PlaneTest.java       |   68 +-
 .../euclidean/threed/PolyhedronsSetTest.java       |  762 ++++++------
 .../geometry/euclidean/threed/RotationTest.java    |  118 +-
 .../geometry/euclidean/threed/SubLineTest.java     |   58 +-
 .../commons/geometry/euclidean/twod/LineTest.java  |   56 +-
 .../geometry/euclidean/twod/NestedLoopsTest.java   |   10 +-
 .../geometry/euclidean/twod/PolygonsSetTest.java   | 1312 ++++++++++----------
 .../geometry/euclidean/twod/SegmentTest.java       |   12 +-
 .../geometry/euclidean/twod/SubLineTest.java       |   58 +-
 .../hull/ConvexHullGenerator2DAbstractTest.java    |  160 +--
 .../euclidean/twod/hull/MonotoneChainTest.java     |   16 +-
 .../geometry/spherical/SphericalCoordinates.java   |    4 +-
 .../commons/geometry/spherical/oned/S1Point.java   |    2 +-
 .../commons/geometry/spherical/twod/S2Point.java   |    2 +-
 .../spherical/SphericalCoordinatesTest.java        |   24 +-
 .../geometry/spherical/SphericalTestUtils.java     |    2 +-
 .../geometry/spherical/twod/CircleTest.java        |    6 +-
 .../spherical/twod/SphericalPolygonsSetTest.java   |   24 +-
 .../geometry/spherical/twod/SubCircleTest.java     |    4 +-
 50 files changed, 1727 insertions(+), 1728 deletions(-)

diff --git a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGenerator.java b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGenerator.java
index a124cf3..b0ada02 100644
--- a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGenerator.java
+++ b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGenerator.java
@@ -117,7 +117,7 @@ public class SphereGenerator implements SupportBallGenerator<Point3D> {
                         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 Point3D(centerX.doubleValue(),
+                        return new EnclosingBall<>(Point3D.of(centerX.doubleValue(),
                                                                                      centerY.doubleValue(),
                                                                                      centerZ.doubleValue()),
                                                                         Math.sqrt(r2.doubleValue()),
diff --git a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/twod/enclosing/DiskGenerator.java b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/twod/enclosing/DiskGenerator.java
index c2b9acc..bab99ac 100644
--- a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/twod/enclosing/DiskGenerator.java
+++ b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/twod/enclosing/DiskGenerator.java
@@ -85,7 +85,7 @@ public class DiskGenerator implements SupportBallGenerator<Point2D> {
                     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 Point2D(centerX.doubleValue(),
+                    return new EnclosingBall<>(Point2D.of(centerX.doubleValue(),
                                                                                  centerY.doubleValue()),
                                                                     Math.sqrt(r2.doubleValue()),
                                                                     vA, vB, vC);
diff --git a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser2DTest.java b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser2DTest.java
index 8a975e1..5f6fb80 100644
--- a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser2DTest.java
+++ b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser2DTest.java
@@ -88,7 +88,7 @@ public class WelzlEncloser2DTest {
             for (int i = 0; i < nbPoints; ++i) {
                 double x = random.nextDouble();
                 double y = random.nextDouble();
-                points.add(new Point2D(x, y));
+                points.add(Point2D.of(x, y));
             }
             checkDisk(points);
         }
@@ -97,7 +97,7 @@ public class WelzlEncloser2DTest {
     private List<Point2D> buildList(final double ... coordinates) {
         List<Point2D> list = new ArrayList<>(coordinates.length / 2);
         for (int i = 0; i < coordinates.length; i += 2) {
-            list.add(new Point2D(coordinates[i], coordinates[i + 1]));
+            list.add(Point2D.of(coordinates[i], coordinates[i + 1]));
         }
         return list;
     }
diff --git a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser3DTest.java b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser3DTest.java
index e874ca7..b7fc5e0 100644
--- a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser3DTest.java
+++ b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser3DTest.java
@@ -53,17 +53,17 @@ public class WelzlEncloser3DTest {
     @Test
     public void testReducingBall() {
         List<Point3D> list =
-                Arrays.asList(new Point3D(-7.140397329568118, -16.571661242582177,  11.714458961735405),
-                              new Point3D(-7.137986707455888, -16.570767323375720,  11.708602108715928),
-                              new Point3D(-7.139185068549035, -16.570891204702250,  11.715554057357394),
-                              new Point3D(-7.142682716997507, -16.571609818234290,  11.710787934580328),
-                              new Point3D(-7.139018392423351, -16.574405614157020,  11.710518716711425),
-                              new Point3D(-7.140870659936730, -16.567993074240455,  11.710914678204503),
-                              new Point3D(-7.136350173659562, -16.570498228820930,  11.713965225900928),
-                              new Point3D(-7.141675762759172, -16.572852471407028,  11.714033471449508),
-                              new Point3D(-7.140453077221105, -16.570212820780647,  11.708624578004980),
-                              new Point3D(-7.140322188726825, -16.574152894557717,  11.710305611121410),
-                              new Point3D(-7.141116131477088, -16.574061164624560,  11.712938509321699));
+                Arrays.asList(Point3D.of(-7.140397329568118, -16.571661242582177,  11.714458961735405),
+                              Point3D.of(-7.137986707455888, -16.570767323375720,  11.708602108715928),
+                              Point3D.of(-7.139185068549035, -16.570891204702250,  11.715554057357394),
+                              Point3D.of(-7.142682716997507, -16.571609818234290,  11.710787934580328),
+                              Point3D.of(-7.139018392423351, -16.574405614157020,  11.710518716711425),
+                              Point3D.of(-7.140870659936730, -16.567993074240455,  11.710914678204503),
+                              Point3D.of(-7.136350173659562, -16.570498228820930,  11.713965225900928),
+                              Point3D.of(-7.141675762759172, -16.572852471407028,  11.714033471449508),
+                              Point3D.of(-7.140453077221105, -16.570212820780647,  11.708624578004980),
+                              Point3D.of(-7.140322188726825, -16.574152894557717,  11.710305611121410),
+                              Point3D.of(-7.141116131477088, -16.574061164624560,  11.712938509321699));
         WelzlEncloser<Point3D> encloser =
                 new WelzlEncloser<>(1.0e-10, new SphereGenerator());
         EnclosingBall<Point3D> ball = encloser.enclose(list);
@@ -74,24 +74,24 @@ public class WelzlEncloser3DTest {
     public void testInfiniteLoop() {
         // this test used to generate an infinite loop
         List<Point3D> list =
-                Arrays.asList(new Point3D( -0.89227075512164380,  -2.89317694645713900,  14.84572323743355500),
-                              new Point3D( -0.92099498940693580,  -2.31086108263908940,  12.92071026467688300),
-                              new Point3D( -0.85227999411005200,  -3.06314731441320730,  15.40163831651287000),
-                              new Point3D( -1.77399413020785970,  -3.65630391378114260,  14.13190097751873400),
-                              new Point3D(  0.33157833272465354,  -2.22813591757792160,  14.21225234159008200),
-                              new Point3D( -1.53065579165484400,  -1.65692084770139570,  14.61483055714788500),
-                              new Point3D( -1.08457093941217140,  -1.96100325935602980,  13.09265170575555000),
-                              new Point3D(  0.30029469589708850,  -3.05470831395667370,  14.56352400426342600),
-                              new Point3D( -0.95007443938638460,  -1.86810946486118360,  15.14491234340057000),
-                              new Point3D( -1.89661503804130830,  -2.17004080885185860,  14.81235128513927000),
-                              new Point3D( -0.72193328761607530,  -1.44513142833618270,  14.52355724218561800),
-                              new Point3D( -0.26895980939606550,  -3.69512371522084140,  14.72272846327652000),
-                              new Point3D( -1.53501693431786170,  -3.25055166611021900,  15.15509062584274800),
-                              new Point3D( -0.71727553535519410,  -3.62284279460799100,  13.26256700929380700),
-                              new Point3D( -0.30220950676137365,  -3.25410412500779070,  13.13682612771606000),
-                              new Point3D( -0.04543996608267075,  -1.93081853923797750,  14.79497997883171400),
-                              new Point3D( -1.53348892951571640,  -3.66688919703524900,  14.73095600812074200),
-                              new Point3D( -0.98034899533935820,  -3.34004481162763960,  13.03245014017556800));
+                Arrays.asList(Point3D.of( -0.89227075512164380,  -2.89317694645713900,  14.84572323743355500),
+                              Point3D.of( -0.92099498940693580,  -2.31086108263908940,  12.92071026467688300),
+                              Point3D.of( -0.85227999411005200,  -3.06314731441320730,  15.40163831651287000),
+                              Point3D.of( -1.77399413020785970,  -3.65630391378114260,  14.13190097751873400),
+                              Point3D.of(  0.33157833272465354,  -2.22813591757792160,  14.21225234159008200),
+                              Point3D.of( -1.53065579165484400,  -1.65692084770139570,  14.61483055714788500),
+                              Point3D.of( -1.08457093941217140,  -1.96100325935602980,  13.09265170575555000),
+                              Point3D.of(  0.30029469589708850,  -3.05470831395667370,  14.56352400426342600),
+                              Point3D.of( -0.95007443938638460,  -1.86810946486118360,  15.14491234340057000),
+                              Point3D.of( -1.89661503804130830,  -2.17004080885185860,  14.81235128513927000),
+                              Point3D.of( -0.72193328761607530,  -1.44513142833618270,  14.52355724218561800),
+                              Point3D.of( -0.26895980939606550,  -3.69512371522084140,  14.72272846327652000),
+                              Point3D.of( -1.53501693431786170,  -3.25055166611021900,  15.15509062584274800),
+                              Point3D.of( -0.71727553535519410,  -3.62284279460799100,  13.26256700929380700),
+                              Point3D.of( -0.30220950676137365,  -3.25410412500779070,  13.13682612771606000),
+                              Point3D.of( -0.04543996608267075,  -1.93081853923797750,  14.79497997883171400),
+                              Point3D.of( -1.53348892951571640,  -3.66688919703524900,  14.73095600812074200),
+                              Point3D.of( -0.98034899533935820,  -3.34004481162763960,  13.03245014017556800));
 
         WelzlEncloser<Point3D> encloser =
                 new WelzlEncloser<>(1.0e-10, new SphereGenerator());
diff --git a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGeneratorTest.java b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGeneratorTest.java
index a1bf60b..b65d726 100644
--- a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGeneratorTest.java
+++ b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGeneratorTest.java
@@ -41,16 +41,16 @@ public class SphereGeneratorTest {
 
     @Test
     public void testSupport1Point() {
-        List<Point3D> support = Arrays.asList(new Point3D(1, 2, 3));
+        List<Point3D> support = Arrays.asList(Point3D.of(1, 2, 3));
         EnclosingBall<Point3D> 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 Point3D(support.get(0).getX() + 0.1,
+        Assert.assertFalse(sphere.contains(Point3D.of(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 Point3D(support.get(0).getX() + 0.1,
+        Assert.assertTrue(sphere.contains(Point3D.of(support.get(0).getX() + 0.1,
                                                        support.get(0).getY() + 0.1,
                                                        support.get(0).getZ() + 0.1),
                                           0.5));
@@ -61,8 +61,8 @@ public class SphereGeneratorTest {
 
     @Test
     public void testSupport2Points() {
-        List<Point3D> support = Arrays.asList(new Point3D(1, 0, 0),
-                                               new Point3D(3, 0, 0));
+        List<Point3D> support = Arrays.asList(Point3D.of(1, 0, 0),
+                                               Point3D.of(3, 0, 0));
         EnclosingBall<Point3D> sphere = new SphereGenerator().ballOnSupport(support);
         Assert.assertEquals(1.0, sphere.getRadius(), 1.0e-10);
         int i = 0;
@@ -71,17 +71,17 @@ public class SphereGeneratorTest {
             Assert.assertEquals(1.0, v.distance(sphere.getCenter()), 1.0e-10);
             Assert.assertTrue(v == sphere.getSupport()[i++]);
         }
-        Assert.assertTrue(sphere.contains(new Point3D(2, 0.9, 0)));
+        Assert.assertTrue(sphere.contains(Point3D.of(2, 0.9, 0)));
         Assert.assertFalse(sphere.contains(Point3D.ZERO));
-        Assert.assertEquals(0.0, new Point3D(2, 0, 0).distance(sphere.getCenter()), 1.0e-10);
+        Assert.assertEquals(0.0, Point3D.of(2, 0, 0).distance(sphere.getCenter()), 1.0e-10);
         Assert.assertEquals(2, sphere.getSupportSize());
     }
 
     @Test
     public void testSupport3Points() {
-        List<Point3D> support = Arrays.asList(new Point3D(1, 0, 0),
-                                               new Point3D(3, 0, 0),
-                                               new Point3D(2, 2, 0));
+        List<Point3D> support = Arrays.asList(Point3D.of(1, 0, 0),
+                                               Point3D.of(3, 0, 0),
+                                               Point3D.of(2, 2, 0));
         EnclosingBall<Point3D> sphere = new SphereGenerator().ballOnSupport(support);
         Assert.assertEquals(5.0 / 4.0, sphere.getRadius(), 1.0e-10);
         int i = 0;
@@ -90,23 +90,23 @@ public class SphereGeneratorTest {
             Assert.assertEquals(5.0 / 4.0, v.distance(sphere.getCenter()), 1.0e-10);
             Assert.assertTrue(v == sphere.getSupport()[i++]);
         }
-        Assert.assertTrue(sphere.contains(new Point3D(2, 0.9, 0)));
-        Assert.assertFalse(sphere.contains(new Point3D(0.9,  0, 0)));
-        Assert.assertFalse(sphere.contains(new Point3D(3.1,  0, 0)));
-        Assert.assertTrue(sphere.contains(new Point3D(2.0, -0.499, 0)));
-        Assert.assertFalse(sphere.contains(new Point3D(2.0, -0.501, 0)));
-        Assert.assertTrue(sphere.contains(new Point3D(2.0, 3.0 / 4.0, -1.249)));
-        Assert.assertFalse(sphere.contains(new Point3D(2.0, 3.0 / 4.0, -1.251)));
-        Assert.assertEquals(0.0, new Point3D(2.0, 3.0 / 4.0, 0).distance(sphere.getCenter()), 1.0e-10);
+        Assert.assertTrue(sphere.contains(Point3D.of(2, 0.9, 0)));
+        Assert.assertFalse(sphere.contains(Point3D.of(0.9,  0, 0)));
+        Assert.assertFalse(sphere.contains(Point3D.of(3.1,  0, 0)));
+        Assert.assertTrue(sphere.contains(Point3D.of(2.0, -0.499, 0)));
+        Assert.assertFalse(sphere.contains(Point3D.of(2.0, -0.501, 0)));
+        Assert.assertTrue(sphere.contains(Point3D.of(2.0, 3.0 / 4.0, -1.249)));
+        Assert.assertFalse(sphere.contains(Point3D.of(2.0, 3.0 / 4.0, -1.251)));
+        Assert.assertEquals(0.0, Point3D.of(2.0, 3.0 / 4.0, 0).distance(sphere.getCenter()), 1.0e-10);
         Assert.assertEquals(3, sphere.getSupportSize());
     }
 
     @Test
     public void testSupport4Points() {
-        List<Point3D> support = Arrays.asList(new Point3D(17, 14,  18),
-                                               new Point3D(11, 14,  22),
-                                               new Point3D( 2, 22,  17),
-                                               new Point3D(22, 11, -10));
+        List<Point3D> support = Arrays.asList(Point3D.of(17, 14,  18),
+                                               Point3D.of(11, 14,  22),
+                                               Point3D.of( 2, 22,  17),
+                                               Point3D.of(22, 11, -10));
         EnclosingBall<Point3D> sphere = new SphereGenerator().ballOnSupport(support);
         Assert.assertEquals(25.0, sphere.getRadius(), 1.0e-10);
         int i = 0;
@@ -115,19 +115,19 @@ public class SphereGeneratorTest {
             Assert.assertEquals(25.0, v.distance(sphere.getCenter()), 1.0e-10);
             Assert.assertTrue(v == sphere.getSupport()[i++]);
         }
-        Assert.assertTrue(sphere.contains (new Point3D(-22.999, 2, 2)));
-        Assert.assertFalse(sphere.contains(new Point3D(-23.001, 2, 2)));
-        Assert.assertTrue(sphere.contains (new Point3D( 26.999, 2, 2)));
-        Assert.assertFalse(sphere.contains(new Point3D( 27.001, 2, 2)));
-        Assert.assertTrue(sphere.contains (new Point3D(2, -22.999, 2)));
-        Assert.assertFalse(sphere.contains(new Point3D(2, -23.001, 2)));
-        Assert.assertTrue(sphere.contains (new Point3D(2,  26.999, 2)));
-        Assert.assertFalse(sphere.contains(new Point3D(2,  27.001, 2)));
-        Assert.assertTrue(sphere.contains (new Point3D(2, 2, -22.999)));
-        Assert.assertFalse(sphere.contains(new Point3D(2, 2, -23.001)));
-        Assert.assertTrue(sphere.contains (new Point3D(2, 2,  26.999)));
-        Assert.assertFalse(sphere.contains(new Point3D(2, 2,  27.001)));
-        Assert.assertEquals(0.0, new Point3D(2.0, 2.0, 2.0).distance(sphere.getCenter()), 1.0e-10);
+        Assert.assertTrue(sphere.contains (Point3D.of(-22.999, 2, 2)));
+        Assert.assertFalse(sphere.contains(Point3D.of(-23.001, 2, 2)));
+        Assert.assertTrue(sphere.contains (Point3D.of( 26.999, 2, 2)));
+        Assert.assertFalse(sphere.contains(Point3D.of( 27.001, 2, 2)));
+        Assert.assertTrue(sphere.contains (Point3D.of(2, -22.999, 2)));
+        Assert.assertFalse(sphere.contains(Point3D.of(2, -23.001, 2)));
+        Assert.assertTrue(sphere.contains (Point3D.of(2,  26.999, 2)));
+        Assert.assertFalse(sphere.contains(Point3D.of(2,  27.001, 2)));
+        Assert.assertTrue(sphere.contains (Point3D.of(2, 2, -22.999)));
+        Assert.assertFalse(sphere.contains(Point3D.of(2, 2, -23.001)));
+        Assert.assertTrue(sphere.contains (Point3D.of(2, 2,  26.999)));
+        Assert.assertFalse(sphere.contains(Point3D.of(2, 2,  27.001)));
+        Assert.assertEquals(0.0, Point3D.of(2.0, 2.0, 2.0).distance(sphere.getCenter()), 1.0e-10);
         Assert.assertEquals(4, sphere.getSupportSize());
     }
 
@@ -153,16 +153,16 @@ public class SphereGeneratorTest {
     @Test
     public void testDegeneratedCase() {
        final List<Point3D> support =
-               Arrays.asList(new Point3D(Math.scalb(-8039905610797991.0, -50),   //   -7.140870659936730
+               Arrays.asList(Point3D.of(Math.scalb(-8039905610797991.0, -50),   //   -7.140870659936730
                                           Math.scalb(-4663475464714142.0, -48),   //  -16.567993074240455
                                           Math.scalb( 6592658872616184.0, -49)),  //   11.710914678204503
-                             new Point3D(Math.scalb(-8036658568968473.0, -50),   //   -7.137986707455888
+                             Point3D.of(Math.scalb(-8036658568968473.0, -50),   //   -7.137986707455888
                                           Math.scalb(-4664256346424880.0, -48),   //  -16.570767323375720
                                           Math.scalb( 6591357011730307.0, -49)),  //  11.708602108715928)
-                             new Point3D(Math.scalb(-8037820142977230.0, -50),   //   -7.139018392423351
+                             Point3D.of(Math.scalb(-8037820142977230.0, -50),   //   -7.139018392423351
                                           Math.scalb(-4665280434237813.0, -48),   //  -16.574405614157020
                                           Math.scalb( 6592435966112099.0, -49)),  //   11.710518716711425
-                             new Point3D(Math.scalb(-8038007803611611.0, -50),   //   -7.139185068549035
+                             Point3D.of(Math.scalb(-8038007803611611.0, -50),   //   -7.139185068549035
                                           Math.scalb(-4664291215918380.0, -48),   //  -16.570891204702250
                                           Math.scalb( 6595270610894208.0, -49))); //   11.715554057357394
         EnclosingBall<Point3D> sphere = new SphereGenerator().ballOnSupport(support);
diff --git a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/euclidean/twod/enclosing/DiskGeneratorTest.java b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/euclidean/twod/enclosing/DiskGeneratorTest.java
index fcafaa4..8770b6b 100644
--- a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/euclidean/twod/enclosing/DiskGeneratorTest.java
+++ b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/euclidean/twod/enclosing/DiskGeneratorTest.java
@@ -42,15 +42,15 @@ public class DiskGeneratorTest {
 
     @Test
     public void testSupport1Point() {
-        List<Point2D> support = Arrays.asList(new Point2D(1, 2));
+        List<Point2D> support = Arrays.asList(Point2D.of(1, 2));
         EnclosingBall<Point2D> 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 Point2D(support.get(0).getX() + 0.1,
+        Assert.assertFalse(disk.contains(Point2D.of(support.get(0).getX() + 0.1,
                                                       support.get(0).getY() - 0.1),
                                          0.001));
-        Assert.assertTrue(disk.contains(new Point2D(support.get(0).getX() + 0.1,
+        Assert.assertTrue(disk.contains(Point2D.of(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);
@@ -60,8 +60,8 @@ public class DiskGeneratorTest {
 
     @Test
     public void testSupport2Points() {
-        List<Point2D> support = Arrays.asList(new Point2D(1, 0),
-                                               new Point2D(3, 0));
+        List<Point2D> support = Arrays.asList(Point2D.of(1, 0),
+                                               Point2D.of(3, 0));
         EnclosingBall<Point2D> disk = new DiskGenerator().ballOnSupport(support);
         Assert.assertEquals(1.0, disk.getRadius(), 1.0e-10);
         int i = 0;
@@ -70,17 +70,17 @@ public class DiskGeneratorTest {
             Assert.assertEquals(1.0, v.distance(disk.getCenter()), 1.0e-10);
             Assert.assertTrue(v == disk.getSupport()[i++]);
         }
-        Assert.assertTrue(disk.contains(new Point2D(2, 0.9)));
+        Assert.assertTrue(disk.contains(Point2D.of(2, 0.9)));
         Assert.assertFalse(disk.contains(Point2D.ZERO));
-        Assert.assertEquals(0.0, new Point2D(2, 0).distance(disk.getCenter()), 1.0e-10);
+        Assert.assertEquals(0.0, Point2D.of(2, 0).distance(disk.getCenter()), 1.0e-10);
         Assert.assertEquals(2, disk.getSupportSize());
     }
 
     @Test
     public void testSupport3Points() {
-        List<Point2D> support = Arrays.asList(new Point2D(1, 0),
-                                               new Point2D(3, 0),
-                                               new Point2D(2, 2));
+        List<Point2D> support = Arrays.asList(Point2D.of(1, 0),
+                                               Point2D.of(3, 0),
+                                               Point2D.of(2, 2));
         EnclosingBall<Point2D> disk = new DiskGenerator().ballOnSupport(support);
         Assert.assertEquals(5.0 / 4.0, disk.getRadius(), 1.0e-10);
         int i = 0;
@@ -89,12 +89,12 @@ public class DiskGeneratorTest {
             Assert.assertEquals(5.0 / 4.0, v.distance(disk.getCenter()), 1.0e-10);
             Assert.assertTrue(v == disk.getSupport()[i++]);
         }
-        Assert.assertTrue(disk.contains(new Point2D(2, 0.9)));
-        Assert.assertFalse(disk.contains(new Point2D(0.9,  0)));
-        Assert.assertFalse(disk.contains(new Point2D(3.1,  0)));
-        Assert.assertTrue(disk.contains(new Point2D(2.0, -0.499)));
-        Assert.assertFalse(disk.contains(new Point2D(2.0, -0.501)));
-        Assert.assertEquals(0.0, new Point2D(2.0, 3.0 / 4.0).distance(disk.getCenter()), 1.0e-10);
+        Assert.assertTrue(disk.contains(Point2D.of(2, 0.9)));
+        Assert.assertFalse(disk.contains(Point2D.of(0.9,  0)));
+        Assert.assertFalse(disk.contains(Point2D.of(3.1,  0)));
+        Assert.assertTrue(disk.contains(Point2D.of(2.0, -0.499)));
+        Assert.assertFalse(disk.contains(Point2D.of(2.0, -0.501)));
+        Assert.assertEquals(0.0, Point2D.of(2.0, 3.0 / 4.0).distance(disk.getCenter()), 1.0e-10);
         Assert.assertEquals(3, disk.getSupportSize());
     }
 
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/IntervalsSet.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/IntervalsSet.java
index 05e7798..376b8fc 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/IntervalsSet.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/IntervalsSet.java
@@ -105,14 +105,14 @@ public class IntervalsSet extends AbstractRegion<Point1D, Point1D> implements It
             }
             // the tree must be open on the negative infinity side
             final SubHyperplane<Point1D> upperCut =
-                new OrientedPoint(new Point1D(upper), true, tolerance).wholeHyperplane();
+                new OrientedPoint(Point1D.of(upper), true, tolerance).wholeHyperplane();
             return new BSPTree<>(upperCut,
                                new BSPTree<Point1D>(Boolean.FALSE),
                                new BSPTree<Point1D>(Boolean.TRUE),
                                null);
         }
         final SubHyperplane<Point1D> lowerCut =
-            new OrientedPoint(new Point1D(lower), false, tolerance).wholeHyperplane();
+            new OrientedPoint(Point1D.of(lower), false, tolerance).wholeHyperplane();
         if (Double.isInfinite(upper) && (upper > 0)) {
             // the tree must be open on the positive infinity side
             return new BSPTree<>(lowerCut,
@@ -123,7 +123,7 @@ public class IntervalsSet extends AbstractRegion<Point1D, Point1D> implements It
 
         // the tree must be bounded on the two sides
         final SubHyperplane<Point1D> upperCut =
-            new OrientedPoint(new Point1D(upper), true, tolerance).wholeHyperplane();
+            new OrientedPoint(Point1D.of(upper), true, tolerance).wholeHyperplane();
         return new BSPTree<>(lowerCut,
                                         new BSPTree<Point1D>(Boolean.FALSE),
                                         new BSPTree<>(upperCut,
@@ -157,7 +157,7 @@ public class IntervalsSet extends AbstractRegion<Point1D, Point1D> implements It
             if (Double.isInfinite(size)) {
                 setBarycenter(Point1D.NaN);
             } else if (size > 0) {
-                setBarycenter(new Point1D(sum / size));
+                setBarycenter(Point1D.of(sum / size));
             } else {
                 setBarycenter(((OrientedPoint) getTree(false).getCut().getHyperplane()).getLocation());
             }
@@ -242,7 +242,7 @@ public class IntervalsSet extends AbstractRegion<Point1D, Point1D> implements It
      * @return a new point for finite abscissa, null otherwise
      */
     private Point1D finiteOrNullPoint(final double x) {
-        return Double.isInfinite(x) ? null : new Point1D(x);
+        return Double.isInfinite(x) ? null : Point1D.of(x);
     }
 
     /** Build an ordered list of intervals representing the instance.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
index eeeed9f..75f4cb8 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
@@ -25,32 +25,31 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D, Vector1D> {
 
     /** Origin (coordinates: 0). */
-    public static final Point1D ZERO = new Point1D(0.0);
+    public static final Point1D ZERO = Point1D.of(0.0);
 
     /** Unit (coordinates: 1). */
-    public static final Point1D ONE  = new Point1D(1.0);
+    public static final Point1D ONE  = Point1D.of(1.0);
 
     // CHECKSTYLE: stop ConstantName
     /** A vector with all coordinates set to NaN. */
-    public static final Point1D NaN = new Point1D(Double.NaN);
+    public static final Point1D NaN = Point1D.of(Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A point with all coordinates set to positive infinity. */
     public static final Point1D POSITIVE_INFINITY =
-        new Point1D(Double.POSITIVE_INFINITY);
+        Point1D.of(Double.POSITIVE_INFINITY);
 
     /** A point with all coordinates set to negative infinity. */
     public static final Point1D NEGATIVE_INFINITY =
-        new Point1D(Double.NEGATIVE_INFINITY);
+        Point1D.of(Double.NEGATIVE_INFINITY);
 
     /** Serializable UID. */
     private static final long serialVersionUID = 7556674948671647925L;
 
     /** Simple constructor.
      * @param x abscissa (coordinate value)
-     * @see #getX()
      */
-    public Point1D(double x) {
+    private Point1D(double x) {
         super(x);
     }
 
@@ -81,7 +80,7 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D
     /** {@inheritDoc} */
     @Override
     public Point1D add(Vector1D v) {
-        return new Point1D(getX() + v.getX());
+        return Point1D.of(getX() + v.getX());
     }
 
     /**
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
index 1e6ab7d..8455441 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
@@ -25,23 +25,23 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public final class Vector1D extends Cartesian1D implements EuclideanVector<Point1D, Vector1D> {
 
     /** Zero vector (coordinates: 0). */
-    public static final Vector1D ZERO = new Vector1D(0.0);
+    public static final Vector1D ZERO = Vector1D.of(0.0);
 
     /** Unit vector (coordinates: 1). */
-    public static final Vector1D ONE  = new Vector1D(1.0);
+    public static final Vector1D ONE  = Vector1D.of(1.0);
 
     // CHECKSTYLE: stop ConstantName
     /** A vector with all coordinates set to NaN. */
-    public static final Vector1D NaN = new Vector1D(Double.NaN);
+    public static final Vector1D NaN = Vector1D.of(Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A vector with all coordinates set to positive infinity. */
     public static final Vector1D POSITIVE_INFINITY =
-        new Vector1D(Double.POSITIVE_INFINITY);
+        Vector1D.of(Double.POSITIVE_INFINITY);
 
     /** A vector with all coordinates set to negative infinity. */
     public static final Vector1D NEGATIVE_INFINITY =
-        new Vector1D(Double.NEGATIVE_INFINITY);
+        Vector1D.of(Double.NEGATIVE_INFINITY);
 
     /** Serializable UID. */
     private static final long serialVersionUID = 1582116020164328846L;
@@ -49,7 +49,7 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
     /** Simple constructor.
      * @param x abscissa (coordinate value)
      */
-    public Vector1D(double x) {
+    private Vector1D(double x) {
         super(x);
     }
 
@@ -92,31 +92,31 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector1D add(Vector1D v) {
-        return new Vector1D(getX() + v.getX());
+        return Vector1D.of(getX() + v.getX());
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector1D add(double factor, Vector1D v) {
-        return new Vector1D(getX() + (factor * v.getX()));
+        return Vector1D.of(getX() + (factor * v.getX()));
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector1D subtract(Vector1D v) {
-        return new Vector1D(getX() - v.getX());
+        return Vector1D.of(getX() - v.getX());
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector1D subtract(double factor, Vector1D v) {
-        return new Vector1D(getX() - (factor * v.getX()));
+        return Vector1D.of(getX() - (factor * v.getX()));
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector1D negate() {
-        return new Vector1D(-getX());
+        return Vector1D.of(-getX());
     }
 
     /** {@inheritDoc} */
@@ -132,7 +132,7 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector1D scalarMultiply(double a) {
-        return new Vector1D(a * getX());
+        return Vector1D.of(a * getX());
     }
 
     /** {@inheritDoc} */
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Line.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Line.java
index 68512a8..e7b4f38 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Line.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Line.java
@@ -135,7 +135,7 @@ public class Line implements Embedding<Point3D, Point1D> {
      */
     @Override
     public Point1D toSubSpace(final Point3D point) {
-        return new Point1D(getAbscissa(point));
+        return Point1D.of(getAbscissa(point));
     }
 
     /** Transform a sub-space point into a space point.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/OutlineExtractor.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/OutlineExtractor.java
index 830d8bf..be504db 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/OutlineExtractor.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/OutlineExtractor.java
@@ -205,12 +205,12 @@ public class OutlineExtractor {
                     int previous         = closed ? (loop.length - 1) : 1;
                     Vector3D previous3D  = plane.toSpace(loop[previous]).asVector();
                     int current          = (previous + 1) % loop.length;
-                    Point2D pPoint       = new Point2D(previous3D.dotProduct(u),
+                    Point2D pPoint       = Point2D.of(previous3D.dotProduct(u),
                                                          previous3D.dotProduct(v));
                     while (current < loop.length) {
 
                         final Vector3D current3D = plane.toSpace(loop[current]).asVector();
-                        final Point2D  cPoint    = new Point2D(current3D.dotProduct(u),
+                        final Point2D  cPoint    = Point2D.of(current3D.dotProduct(u),
                                                                  current3D.dotProduct(v));
                         final org.apache.commons.geometry.euclidean.twod.Line line =
                             new org.apache.commons.geometry.euclidean.twod.Line(pPoint, cPoint, tolerance);
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
index 5ac48dc..23fc6cd 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
@@ -241,7 +241,7 @@ public class Plane implements Hyperplane<Point3D>, Embedding<Point3D, Point2D> {
     @Override
     public Point2D toSubSpace(final Point3D point) {
         Vector3D vec = point.asVector();
-        return new Point2D(vec.dotProduct(u), vec.dotProduct(v));
+        return Point2D.of(vec.dotProduct(u), vec.dotProduct(v));
     }
 
     /** Transform an in-plane point into a 3D space point.
@@ -380,7 +380,7 @@ public class Plane implements Hyperplane<Point3D>, Embedding<Point3D, Point2D> {
         }
 
         final double r = 1.0 / determinant;
-        return new Point3D(
+        return Point3D.of(
                             (-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);
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
index 46de33d..05af242 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
@@ -26,20 +26,20 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D, Vector3D> {
 
     /** Zero point (coordinates: 0, 0, 0). */
-    public static final Point3D ZERO   = new Point3D(0, 0, 0);
+    public static final Point3D ZERO   = Point3D.of(0, 0, 0);
 
     // CHECKSTYLE: stop ConstantName
     /** A point with all coordinates set to NaN. */
-    public static final Point3D NaN = new Point3D(Double.NaN, Double.NaN, Double.NaN);
+    public static final Point3D NaN = Point3D.of(Double.NaN, Double.NaN, Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A point with all coordinates set to positive infinity. */
     public static final Point3D POSITIVE_INFINITY =
-        new Point3D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+        Point3D.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
 
     /** A point with all coordinates set to negative infinity. */
     public static final Point3D NEGATIVE_INFINITY =
-        new Point3D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+        Point3D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
 
     /** Serializable version identifier. */
     private static final long serialVersionUID = 1313493323784566947L;
@@ -50,7 +50,7 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
      * @param y ordinate
      * @param z height
      */
-    public Point3D(double x, double y, double z) {
+    private Point3D(double x, double y, double z) {
         super(x, y, z);
     }
 
@@ -69,7 +69,7 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
     /** {@inheritDoc} */
     @Override
     public Vector3D subtract(Point3D p) {
-        return new Vector3D(
+        return Vector3D.of(
                     getX() - p.getX(),
                     getY() - p.getY(),
                     getZ() - p.getZ()
@@ -85,7 +85,7 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
     /** {@inheritDoc} */
     @Override
     public Point3D add(Vector3D v) {
-        return new Point3D(
+        return Point3D.of(
                     getX() + v.getX(),
                     getY() + v.getY(),
                     getZ() + v.getZ()
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSet.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSet.java
index d70efba..114eb51 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSet.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSet.java
@@ -152,12 +152,12 @@ public class PolyhedronsSet extends AbstractRegion<Point3D, Point2D> {
             // too thin box, build an empty polygons set
             return new BSPTree<>(Boolean.FALSE);
         }
-        final Plane pxMin = new Plane(new Point3D(xMin, 0,    0),   Vector3D.MINUS_X, tolerance);
-        final Plane pxMax = new Plane(new Point3D(xMax, 0,    0),   Vector3D.PLUS_X,  tolerance);
-        final Plane pyMin = new Plane(new Point3D(0,    yMin, 0),   Vector3D.MINUS_Y, tolerance);
-        final Plane pyMax = new Plane(new Point3D(0,    yMax, 0),   Vector3D.PLUS_Y,  tolerance);
-        final Plane pzMin = new Plane(new Point3D(0,    0,   zMin), Vector3D.MINUS_Z, tolerance);
-        final Plane pzMax = new Plane(new Point3D(0,    0,   zMax), Vector3D.PLUS_Z,  tolerance);
+        final Plane pxMin = new Plane(Point3D.of(xMin, 0,    0),   Vector3D.MINUS_X, tolerance);
+        final Plane pxMax = new Plane(Point3D.of(xMax, 0,    0),   Vector3D.PLUS_X,  tolerance);
+        final Plane pyMin = new Plane(Point3D.of(0,    yMin, 0),   Vector3D.MINUS_Y, tolerance);
+        final Plane pyMax = new Plane(Point3D.of(0,    yMax, 0),   Vector3D.PLUS_Y,  tolerance);
+        final Plane pzMin = new Plane(Point3D.of(0,    0,   zMin), Vector3D.MINUS_Z, tolerance);
+        final Plane pzMax = new Plane(Point3D.of(0,    0,   zMax), Vector3D.PLUS_Z,  tolerance);
         final Region<Point3D> boundary =
         new RegionFactory<Point3D>().buildConvex(pxMin, pxMax, pyMin, pyMax, pzMin, pzMax);
         return boundary.getTree(false);
@@ -614,8 +614,8 @@ public class PolyhedronsSet extends AbstractRegion<Point3D, Point2D> {
                 final Plane    oPlane = (Plane) original;
                 final Plane    tPlane = (Plane) transformed;
                 final Point3D p00    = oPlane.getOrigin();
-                final Point3D p10    = oPlane.toSpace(new Point2D(1.0, 0.0));
-                final Point3D p01    = oPlane.toSpace(new Point2D(0.0, 1.0));
+                final Point3D p10    = oPlane.toSpace(Point2D.of(1.0, 0.0));
+                final Point3D p01    = oPlane.toSpace(Point2D.of(0.0, 1.0));
                 final Point2D tP00   = tPlane.toSubSpace(apply(p00));
                 final Point2D tP10   = tPlane.toSubSpace(apply(p10));
                 final Point2D tP01   = tPlane.toSubSpace(apply(p01));
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Rotation.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Rotation.java
index 7261fd1..931be75 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Rotation.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Rotation.java
@@ -543,10 +543,10 @@ public class Rotation implements Serializable {
         final double sgn = convention == RotationConvention.VECTOR_OPERATOR ? +1 : -1;
         if (q0 < 0) {
             final double inverse = sgn / Math.sqrt(squaredSine);
-            return new Vector3D(q1 * inverse, q2 * inverse, q3 * inverse);
+            return Vector3D.of(q1 * inverse, q2 * inverse, q3 * inverse);
         }
         final double inverse = -sgn / Math.sqrt(squaredSine);
-        return new Vector3D(q1 * inverse, q2 * inverse, q3 * inverse);
+        return Vector3D.of(q1 * inverse, q2 * inverse, q3 * inverse);
     }
   }
 
@@ -1113,7 +1113,7 @@ public class Rotation implements Serializable {
 
     double s = q1 * x + q2 * y + q3 * z;
 
-    return new Vector3D(2 * (q0 * (x * q0 - (q2 * z - q3 * y)) + s * q1) - x,
+    return Vector3D.of(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);
 
@@ -1151,7 +1151,7 @@ public class Rotation implements Serializable {
     double s = q1 * x + q2 * y + q3 * z;
     double m0 = -q0;
 
-    return new Vector3D(2 * (m0 * (x * m0 - (q2 * z - q3 * y)) + s * q1) - x,
+    return Vector3D.of(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);
 
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubLine.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubLine.java
index fdf511b..d390536 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubLine.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubLine.java
@@ -83,8 +83,8 @@ public class SubLine {
         final List<Segment> segments = new ArrayList<>(list.size());
 
         for (final Interval interval : list) {
-            final Point3D start = line.toSpace(new Point1D(interval.getInf()));
-            final Point3D end   = line.toSpace(new Point1D(interval.getSup()));
+            final Point3D start = line.toSpace(Point1D.of(interval.getInf()));
+            final Point3D end   = line.toSpace(Point1D.of(interval.getSup()));
             segments.add(new Segment(start, end, line));
         }
 
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
index 5a9e0ac..f50816a 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
@@ -25,38 +25,38 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Vector3D> {
 
     /** Zero (null) vector (coordinates: 0, 0, 0). */
-    public static final Vector3D ZERO   = new Vector3D(0, 0, 0);
+    public static final Vector3D ZERO   = Vector3D.of(0, 0, 0);
 
     /** First canonical vector (coordinates: 1, 0, 0). */
-    public static final Vector3D PLUS_X = new Vector3D(1, 0, 0);
+    public static final Vector3D PLUS_X = Vector3D.of(1, 0, 0);
 
     /** Opposite of the first canonical vector (coordinates: -1, 0, 0). */
-    public static final Vector3D MINUS_X = new Vector3D(-1, 0, 0);
+    public static final Vector3D MINUS_X = Vector3D.of(-1, 0, 0);
 
     /** Second canonical vector (coordinates: 0, 1, 0). */
-    public static final Vector3D PLUS_Y = new Vector3D(0, 1, 0);
+    public static final Vector3D PLUS_Y = Vector3D.of(0, 1, 0);
 
     /** Opposite of the second canonical vector (coordinates: 0, -1, 0). */
-    public static final Vector3D MINUS_Y = new Vector3D(0, -1, 0);
+    public static final Vector3D MINUS_Y = Vector3D.of(0, -1, 0);
 
     /** Third canonical vector (coordinates: 0, 0, 1). */
-    public static final Vector3D PLUS_Z = new Vector3D(0, 0, 1);
+    public static final Vector3D PLUS_Z = Vector3D.of(0, 0, 1);
 
     /** Opposite of the third canonical vector (coordinates: 0, 0, -1).  */
-    public static final Vector3D MINUS_Z = new Vector3D(0, 0, -1);
+    public static final Vector3D MINUS_Z = Vector3D.of(0, 0, -1);
 
  // CHECKSTYLE: stop ConstantName
     /** A vector with all coordinates set to NaN. */
-    public static final Vector3D NaN = new Vector3D(Double.NaN, Double.NaN, Double.NaN);
+    public static final Vector3D NaN = Vector3D.of(Double.NaN, Double.NaN, Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A vector with all coordinates set to positive infinity. */
     public static final Vector3D POSITIVE_INFINITY =
-        new Vector3D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+        Vector3D.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
 
     /** A vector with all coordinates set to negative infinity. */
     public static final Vector3D NEGATIVE_INFINITY =
-        new Vector3D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+        Vector3D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
 
     /** Serializable UID */
     private static final long serialVersionUID = 3695385854431542858L;
@@ -70,7 +70,7 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
      * @param y ordinate
      * @param z height
      */
-    public Vector3D(double x, double y, double z) {
+    private Vector3D(double x, double y, double z) {
         super(x, y, z);
     }
 
@@ -135,7 +135,7 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
     /** {@inheritDoc} */
     @Override
     public Vector3D add(Vector3D v) {
-        return new Vector3D(
+        return Vector3D.of(
                     getX() + v.getX(),
                     getY() + v.getY(),
                     getZ() + v.getZ()
@@ -145,7 +145,7 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
     /** {@inheritDoc} */
     @Override
     public Vector3D add(double factor, Vector3D v) {
-        return new Vector3D(
+        return Vector3D.of(
                     getX() + (factor * v.getX()),
                     getY() + (factor * v.getY()),
                     getZ() + (factor * v.getZ())
@@ -155,7 +155,7 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
     /** {@inheritDoc} */
     @Override
     public Vector3D subtract(Vector3D v) {
-        return new Vector3D(
+        return Vector3D.of(
                     getX() - v.getX(),
                     getY() - v.getY(),
                     getZ() - v.getZ()
@@ -165,7 +165,7 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
     /** {@inheritDoc} */
     @Override
     public Vector3D subtract(double factor, Vector3D v) {
-        return new Vector3D(
+        return Vector3D.of(
                     getX() - (factor * v.getX()),
                     getY() - (factor * v.getY()),
                     getZ() - (factor * v.getZ())
@@ -175,7 +175,7 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
     /** {@inheritDoc} */
     @Override
     public Vector3D negate() {
-        return new Vector3D(-getX(), -getY(), -getZ());
+        return Vector3D.of(-getX(), -getY(), -getZ());
     }
 
     /** {@inheritDoc} */
@@ -215,13 +215,13 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
 
         if (Math.abs(x) <= threshold) {
             double inverse  = 1 / Math.sqrt(y * y + z * z);
-            return new Vector3D(0, inverse * z, -inverse * y);
+            return Vector3D.of(0, inverse * z, -inverse * y);
         } else if (Math.abs(y) <= threshold) {
             double inverse  = 1 / Math.sqrt(x * x + z * z);
-            return new Vector3D(-inverse * z, 0, inverse * x);
+            return Vector3D.of(-inverse * z, 0, inverse * x);
         }
         double inverse  = 1 / Math.sqrt(x * x + y * y);
-        return new Vector3D(inverse * y, -inverse * x, 0);
+        return Vector3D.of(inverse * y, -inverse * x, 0);
     }
 
     /** Compute the angular separation between two vectors.
@@ -260,7 +260,7 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
      * @return the cross product this ^ v as a new Cartesian3D
      */
     public Vector3D crossProduct(final Vector3D v) {
-        return new Vector3D(LinearCombination.value(getY(), v.getZ(), -getZ(), v.getY()),
+        return Vector3D.of(LinearCombination.value(getY(), v.getZ(), -getZ(), v.getY()),
                             LinearCombination.value(getZ(), v.getX(), -getX(), v.getZ()),
                             LinearCombination.value(getX(), v.getY(), -getY(), v.getX()));
     }
@@ -268,7 +268,7 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve
     /** {@inheritDoc} */
     @Override
     public Vector3D scalarMultiply(double a) {
-        return new Vector3D(a * getX(), a * getY(), a * getZ());
+        return Vector3D.of(a * getX(), a * getY(), a * getZ());
     }
 
     /** {@inheritDoc} */
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
index cb3c2ea..c5a5394 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
@@ -212,14 +212,14 @@ public class Line implements Hyperplane<Point2D>, Embedding<Point2D, Point1D> {
     /** {@inheritDoc} */
     @Override
     public Point1D toSubSpace(final Point2D point) {
-        return new Point1D(LinearCombination.value(cos, point.getX(), sin, point.getY()));
+        return Point1D.of(LinearCombination.value(cos, point.getX(), sin, point.getY()));
     }
 
     /** {@inheritDoc} */
     @Override
     public Point2D toSpace(final Point1D point) {
         final double abscissa = point.getX();
-        return new Point2D(LinearCombination.value(abscissa, cos, -originOffset, sin),
+        return Point2D.of(LinearCombination.value(abscissa, cos, -originOffset, sin),
                             LinearCombination.value(abscissa, sin,  originOffset, cos));
     }
 
@@ -233,7 +233,7 @@ public class Line implements Hyperplane<Point2D>, Embedding<Point2D, Point1D> {
         if (Math.abs(d) < tolerance) {
             return null;
         }
-        return new Point2D(LinearCombination.value(cos, other.originOffset, -other.cos, originOffset) / d,
+        return Point2D.of(LinearCombination.value(cos, other.originOffset, -other.cos, originOffset) / d,
                             LinearCombination.value(sin, other.originOffset, -other.sin, originOffset) / d);
     }
 
@@ -301,7 +301,7 @@ public class Line implements Hyperplane<Point2D>, Embedding<Point2D, Point1D> {
     public Point2D getPointAt(final Point1D abscissa, final double offset) {
         final double x       = abscissa.getX();
         final double dOffset = offset - originOffset;
-        return new Point2D(LinearCombination.value(x, cos,  dOffset, sin),
+        return Point2D.of(LinearCombination.value(x, cos,  dOffset, sin),
                             LinearCombination.value(x, sin, -dOffset, cos));
     }
 
@@ -468,7 +468,7 @@ public class Line implements Hyperplane<Point2D>, Embedding<Point2D, Point1D> {
         public Point2D apply(final Point2D point) {
             final double  x   = point.getX();
             final double  y   = point.getY();
-            return new Point2D(LinearCombination.value(cXX, x, cXY, y, cX1, 1),
+            return Point2D.of(LinearCombination.value(cXX, x, cXY, y, cX1, 1),
                                 LinearCombination.value(cYX, x, cYY, y, cY1, 1));
         }
 
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
index e062b89..376d970 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
@@ -25,20 +25,20 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D, Vector2D> {
 
     /** Origin (coordinates: 0, 0). */
-    public static final Point2D ZERO   = new Point2D(0, 0);
+    public static final Point2D ZERO   = Point2D.of(0, 0);
 
  // CHECKSTYLE: stop ConstantName
     /** A point with all coordinates set to NaN. */
-    public static final Point2D NaN = new Point2D(Double.NaN, Double.NaN);
+    public static final Point2D NaN = Point2D.of(Double.NaN, Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A point with all coordinates set to positive infinity. */
     public static final Point2D POSITIVE_INFINITY =
-        new Point2D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+        Point2D.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
 
     /** A point with all coordinates set to negative infinity. */
     public static final Point2D NEGATIVE_INFINITY =
-        new Point2D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+        Point2D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
 
     /** Serializable UID. */
     private static final long serialVersionUID = 266938651998679754L;
@@ -48,14 +48,14 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D
      * @param x abscissa
      * @param y ordinate
      */
-    public Point2D(double x, double y) {
+    private Point2D(double x, double y) {
         super(x, y);
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector2D asVector() {
-        return new Vector2D(getX(), getY());
+        return Vector2D.of(getX(), getY());
     }
 
     /** {@inheritDoc} */
@@ -79,7 +79,7 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D
     /** {@inheritDoc} */
     @Override
     public Point2D add(Vector2D v) {
-        return new Point2D(getX() + v.getX(), getY() + v.getY());
+        return Point2D.of(getX() + v.getX(), getY() + v.getY());
     }
 
     /**
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolygonsSet.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolygonsSet.java
index de79c32..e7ffbeb 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolygonsSet.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolygonsSet.java
@@ -158,10 +158,10 @@ public class PolygonsSet extends AbstractRegion<Point2D, Point1D> {
             // too thin box, build an empty polygons set
             return null;
         }
-        final Point2D minMin = new Point2D(xMin, yMin);
-        final Point2D minMax = new Point2D(xMin, yMax);
-        final Point2D maxMin = new Point2D(xMax, yMin);
-        final Point2D maxMax = new Point2D(xMax, yMax);
+        final Point2D minMin = Point2D.of(xMin, yMin);
+        final Point2D minMax = Point2D.of(xMin, yMax);
+        final Point2D maxMin = Point2D.of(xMax, yMin);
+        final Point2D maxMax = Point2D.of(xMax, yMax);
         return new Line[] {
             new Line(minMin, maxMin, tolerance),
             new Line(maxMin, maxMax, tolerance),
@@ -579,7 +579,7 @@ public class PolygonsSet extends AbstractRegion<Point2D, Point1D> {
                 setBarycenter(Point2D.NaN);
             } else {
                 setSize(sum / 2);
-                setBarycenter(new Point2D(sumX / (3 * sum), sumY / (3 * sum)));
+                setBarycenter(Point2D.of(sumX / (3 * sum), sumY / (3 * sum)));
             }
 
         }
@@ -661,8 +661,8 @@ public class PolygonsSet extends AbstractRegion<Point2D, Point1D> {
                         final Line line = loop.get(0).getLine();
                         vertices[i++] = new Point2D[] {
                             null,
-                            line.toSpace(new Point1D(-Float.MAX_VALUE)),
-                            line.toSpace(new Point1D(+Float.MAX_VALUE))
+                            line.toSpace(Point1D.of(-Float.MAX_VALUE)),
+                            line.toSpace(Point1D.of(+Float.MAX_VALUE))
                         };
                     } else if (loop.get(0).getStart() == null) {
                         // open loop with at least one real point
@@ -675,7 +675,7 @@ public class PolygonsSet extends AbstractRegion<Point2D, Point1D> {
                                 double x = segment.getLine().toSubSpace(segment.getEnd()).getX();
                                 x -= Math.max(1.0, Math.abs(x / 2));
                                 array[j++] = null;
-                                array[j++] = segment.getLine().toSpace(new Point1D(x));
+                                array[j++] = segment.getLine().toSpace(Point1D.of(x));
                             }
 
                             if (j < (array.length - 1)) {
@@ -685,7 +685,7 @@ public class PolygonsSet extends AbstractRegion<Point2D, Point1D> {
                                 // last dummy point
                                 double x = segment.getLine().toSubSpace(segment.getStart()).getX();
                                 x += Math.max(1.0, Math.abs(x / 2));
-                                array[j++] = segment.getLine().toSpace(new Point1D(x));
+                                array[j++] = segment.getLine().toSpace(Point1D.of(x));
                             }
 
                         }
@@ -1047,9 +1047,9 @@ public class PolygonsSet extends AbstractRegion<Point2D, Point1D> {
 
                 // find the 2D points
                 final Point2D startV = Double.isInfinite(i.getInf()) ?
-                                        null : line.toSpace(new Point1D(i.getInf()));
+                                        null : line.toSpace(Point1D.of(i.getInf()));
                 final Point2D endV   = Double.isInfinite(i.getSup()) ?
-                                        null : line.toSpace(new Point1D(i.getSup()));
+                                        null : line.toSpace(Point1D.of(i.getSup()));
 
                 // recover the connectivity information
                 final BSPTree<Point2D> startN = selectClosest(startV, splitters);
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java
index bc8b214..a728d61 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java
@@ -100,7 +100,7 @@ public class Segment {
             final double px = start.getX() + r * deltaX;
             final double py = start.getY() + r * deltaY;
 
-            final Point2D interPt = new Point2D(px, py);
+            final Point2D interPt = Point2D.of(px, py);
             return interPt.distance(p);
         }
     }
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/SubLine.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/SubLine.java
index b9e63d6..94d2398 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/SubLine.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/SubLine.java
@@ -81,8 +81,8 @@ public class SubLine extends AbstractSubHyperplane<Point2D, Point1D> {
         final List<Segment> segments = new ArrayList<>(list.size());
 
         for (final Interval interval : list) {
-            final Point2D start = line.toSpace(new Point1D(interval.getInf()));
-            final Point2D end   = line.toSpace(new Point1D(interval.getSup()));
+            final Point2D start = line.toSpace(Point1D.of(interval.getInf()));
+            final Point2D end   = line.toSpace(Point1D.of(interval.getSup()));
             segments.add(new Segment(start, end, line));
         }
 
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
index 0bc84d2..98ac4bc 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
@@ -25,32 +25,32 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public final class Vector2D extends Cartesian2D implements EuclideanVector<Point2D, Vector2D> {
 
     /** Zero vector (coordinates: 0, 0). */
-    public static final Vector2D ZERO   = new Vector2D(0, 0);
+    public static final Vector2D ZERO   = Vector2D.of(0, 0);
 
     /** Unit vector pointing in the direction of the positive x-axis. */
-    public static final Vector2D PLUS_X = new Vector2D(1, 0);
+    public static final Vector2D PLUS_X = Vector2D.of(1, 0);
 
     /** Unit vector pointing in the direction of the negative x-axis. */
-    public static final Vector2D MINUS_X = new Vector2D(-1, 0);
+    public static final Vector2D MINUS_X = Vector2D.of(-1, 0);
 
     /** Unit vector pointing in the direction of the positive y-axis. */
-    public static final Vector2D PLUS_Y = new Vector2D(0, 1);
+    public static final Vector2D PLUS_Y = Vector2D.of(0, 1);
 
     /** Unit vector pointing in the direction of the negative y-axis. */
-    public static final Vector2D MINUS_Y = new Vector2D(0, -1);
+    public static final Vector2D MINUS_Y = Vector2D.of(0, -1);
 
     // CHECKSTYLE: stop ConstantName
     /** A vector with all coordinates set to NaN. */
-    public static final Vector2D NaN = new Vector2D(Double.NaN, Double.NaN);
+    public static final Vector2D NaN = Vector2D.of(Double.NaN, Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A vector with all coordinates set to positive infinity. */
     public static final Vector2D POSITIVE_INFINITY =
-        new Vector2D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+        Vector2D.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
 
     /** A vector with all coordinates set to negative infinity. */
     public static final Vector2D NEGATIVE_INFINITY =
-        new Vector2D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+        Vector2D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
 
     /** Serializable UID */
     private static final long serialVersionUID = 1746839897232305304L;
@@ -62,7 +62,7 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
      * @param x abscissa (first coordinate)
      * @param y ordinate (second coordinate)
      */
-    public Vector2D(double x, double y) {
+    private Vector2D(double x, double y) {
         super(x, y);
     }
 
@@ -77,7 +77,7 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Point2D asPoint() {
-        return new Point2D(getX(), getY());
+        return Point2D.of(getX(), getY());
     }
 
     /** {@inheritDoc} */
@@ -117,31 +117,31 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector2D add(Vector2D v) {
-        return new Vector2D(getX() + v.getX(), getY() + v.getY());
+        return Vector2D.of(getX() + v.getX(), getY() + v.getY());
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector2D add(double factor, Vector2D v) {
-        return new Vector2D(getX() + (factor * v.getX()), getY() + (factor * v.getY()));
+        return Vector2D.of(getX() + (factor * v.getX()), getY() + (factor * v.getY()));
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector2D subtract(Vector2D v) {
-        return new Vector2D(getX() - v.getX(), getY() - v.getY());
+        return Vector2D.of(getX() - v.getX(), getY() - v.getY());
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector2D subtract(double factor, Vector2D v) {
-        return new Vector2D(getX() - (factor * v.getX()), getY() - (factor * v.getY()));
+        return Vector2D.of(getX() - (factor * v.getX()), getY() - (factor * v.getY()));
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector2D negate() {
-        return new Vector2D(-getX(), -getY());
+        return Vector2D.of(-getX(), -getY());
     }
 
     /** {@inheritDoc} */
@@ -157,7 +157,7 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector2D scalarMultiply(double a) {
-        return new Vector2D(a * getX(), a * getY());
+        return Vector2D.of(a * getX(), a * getY());
     }
 
     /** {@inheritDoc} */
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/core/partitioning/CharacterizationTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/core/partitioning/CharacterizationTest.java
index e2a94fb..dc28a43 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/core/partitioning/CharacterizationTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/core/partitioning/CharacterizationTest.java
@@ -38,7 +38,7 @@ public class CharacterizationTest {
     public void testCharacterize_insideLeaf() {
         // arrange
         BSPTree<Point2D> tree = new BSPTree<>(Boolean.TRUE);
-        SubLine sub = buildSubLine(new Point2D(0, -1), new Point2D(0, 1));
+        SubLine sub = buildSubLine(Point2D.of(0, -1), Point2D.of(0, 1));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -57,7 +57,7 @@ public class CharacterizationTest {
     public void testCharacterize_outsideLeaf() {
         // arrange
         BSPTree<Point2D> tree = new BSPTree<>(Boolean.FALSE);
-        SubLine sub = buildSubLine(new Point2D(0, -1), new Point2D(0, 1));
+        SubLine sub = buildSubLine(Point2D.of(0, -1), Point2D.of(0, 1));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -76,9 +76,9 @@ public class CharacterizationTest {
     public void testCharacterize_onPlusSide() {
         // arrange
         BSPTree<Point2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Point2D(0, 0), new Point2D(1, 0)));
+        cut(tree, buildLine(Point2D.of(0, 0), Point2D.of(1, 0)));
 
-        SubLine sub = buildSubLine(new Point2D(0, -1), new Point2D(0, -2));
+        SubLine sub = buildSubLine(Point2D.of(0, -1), Point2D.of(0, -2));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -97,9 +97,9 @@ public class CharacterizationTest {
     public void testCharacterize_onMinusSide() {
         // arrange
         BSPTree<Point2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Point2D(0, 0), new Point2D(1, 0)));
+        cut(tree, buildLine(Point2D.of(0, 0), Point2D.of(1, 0)));
 
-        SubLine sub = buildSubLine(new Point2D(0, 1), new Point2D(0, 2));
+        SubLine sub = buildSubLine(Point2D.of(0, 1), Point2D.of(0, 2));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -118,9 +118,9 @@ public class CharacterizationTest {
     public void testCharacterize_onBothSides() {
         // arrange
         BSPTree<Point2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Point2D(0, 0), new Point2D(1, 0)));
+        cut(tree, buildLine(Point2D.of(0, 0), Point2D.of(1, 0)));
 
-        SubLine sub = buildSubLine(new Point2D(0, -1), new Point2D(0, 1));
+        SubLine sub = buildSubLine(Point2D.of(0, -1), Point2D.of(0, 1));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -131,8 +131,8 @@ public class CharacterizationTest {
 
         SubLine inside = (SubLine) ch.insideTouching();
         Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Point2D(0, 0), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(0, 1), inside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(0, 0), inside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(0, 1), inside.getSegments().get(0).getEnd());
 
         Assert.assertEquals(1, size(ch.getInsideSplitters()));
         Iterator<BSPTree<Point2D>> insideSplitterIter = ch.getInsideSplitters().iterator();
@@ -143,8 +143,8 @@ public class CharacterizationTest {
 
         SubLine outside = (SubLine) ch.outsideTouching();
         Assert.assertEquals(1, outside.getSegments().size());
-        assertVectorEquals(new Point2D(0, -1), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(0, 0), outside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(0, -1), outside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(0, 0), outside.getSegments().get(0).getEnd());
 
         Assert.assertEquals(1, size(ch.getOutsideSplitters()));
         Iterator<BSPTree<Point2D>> outsideSplitterIter = ch.getOutsideSplitters().iterator();
@@ -155,10 +155,10 @@ public class CharacterizationTest {
     public void testCharacterize_multipleSplits_reunitedOnPlusSide() {
         // arrange
         BSPTree<Point2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Point2D(0, 0), new Point2D(1, 0)));
-        cut(tree.getMinus(), buildLine(new Point2D(-1, 0), new Point2D(0, 1)));
+        cut(tree, buildLine(Point2D.of(0, 0), Point2D.of(1, 0)));
+        cut(tree.getMinus(), buildLine(Point2D.of(-1, 0), Point2D.of(0, 1)));
 
-        SubLine sub = buildSubLine(new Point2D(0, -2), new Point2D(0, 2));
+        SubLine sub = buildSubLine(Point2D.of(0, -2), Point2D.of(0, 2));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -169,8 +169,8 @@ public class CharacterizationTest {
 
         SubLine inside = (SubLine) ch.insideTouching();
         Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Point2D(0, 1), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(0, 2), inside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(0, 1), inside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(0, 2), inside.getSegments().get(0).getEnd());
 
         Assert.assertEquals(2, size(ch.getInsideSplitters()));
         Iterator<BSPTree<Point2D>> insideSplitterIter = ch.getInsideSplitters().iterator();
@@ -182,8 +182,8 @@ public class CharacterizationTest {
 
         SubLine outside = (SubLine) ch.outsideTouching();
         Assert.assertEquals(1, outside.getSegments().size());
-        assertVectorEquals(new Point2D(0, -2), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(0, 1), outside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(0, -2), outside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(0, 1), outside.getSegments().get(0).getEnd());
 
         Assert.assertEquals(2, size(ch.getOutsideSplitters()));
         Iterator<BSPTree<Point2D>> outsideSplitterIter = ch.getOutsideSplitters().iterator();
@@ -195,11 +195,11 @@ public class CharacterizationTest {
     public void testCharacterize_multipleSplits_reunitedOnMinusSide() {
         // arrange
         BSPTree<Point2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Point2D(0, 0), new Point2D(1, 0)));
-        cut(tree.getMinus(), buildLine(new Point2D(-1, 0), new Point2D(0, 1)));
-        cut(tree.getMinus().getPlus(), buildLine(new Point2D(-0.5, 0.5), new Point2D(0, 0)));
+        cut(tree, buildLine(Point2D.of(0, 0), Point2D.of(1, 0)));
+        cut(tree.getMinus(), buildLine(Point2D.of(-1, 0), Point2D.of(0, 1)));
+        cut(tree.getMinus().getPlus(), buildLine(Point2D.of(-0.5, 0.5), Point2D.of(0, 0)));
 
-        SubLine sub = buildSubLine(new Point2D(0, -2), new Point2D(0, 2));
+        SubLine sub = buildSubLine(Point2D.of(0, -2), Point2D.of(0, 2));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -210,8 +210,8 @@ public class CharacterizationTest {
 
         SubLine inside = (SubLine) ch.insideTouching();
         Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Point2D(0, 0), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(0, 2), inside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(0, 0), inside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(0, 2), inside.getSegments().get(0).getEnd());
 
         Assert.assertEquals(2, size(ch.getInsideSplitters()));
         Iterator<BSPTree<Point2D>> insideSplitterIter = ch.getInsideSplitters().iterator();
@@ -223,8 +223,8 @@ public class CharacterizationTest {
 
         SubLine outside = (SubLine) ch.outsideTouching();
         Assert.assertEquals(1, outside.getSegments().size());
-        assertVectorEquals(new Point2D(0, -2), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(0, 0), outside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(0, -2), outside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(0, 0), outside.getSegments().get(0).getEnd());
 
         Assert.assertEquals(1, size(ch.getOutsideSplitters()));
         Iterator<BSPTree<Point2D>> outsideSplitterIter = ch.getOutsideSplitters().iterator();
@@ -235,9 +235,9 @@ public class CharacterizationTest {
     public void testCharacterize_onHyperplane_sameOrientation() {
         // arrange
         BSPTree<Point2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Point2D(0, 0), new Point2D(1, 0)));
+        cut(tree, buildLine(Point2D.of(0, 0), Point2D.of(1, 0)));
 
-        SubLine sub = buildSubLine(new Point2D(0, 0), new Point2D(1, 0));
+        SubLine sub = buildSubLine(Point2D.of(0, 0), Point2D.of(1, 0));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -256,9 +256,9 @@ public class CharacterizationTest {
     public void testCharacterize_onHyperplane_oppositeOrientation() {
         // arrange
         BSPTree<Point2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Point2D(0, 0), new Point2D(1, 0)));
+        cut(tree, buildLine(Point2D.of(0, 0), Point2D.of(1, 0)));
 
-        SubLine sub = buildSubLine(new Point2D(1, 0), new Point2D(0, 0));
+        SubLine sub = buildSubLine(Point2D.of(1, 0), Point2D.of(0, 0));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -277,10 +277,10 @@ public class CharacterizationTest {
     public void testCharacterize_onHyperplane_multipleSplits_sameOrientation() {
         // arrange
         BSPTree<Point2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Point2D(0, 0), new Point2D(1, 0)));
-        cut(tree.getMinus(), buildLine(new Point2D(-1, 0), new Point2D(0, 1)));
+        cut(tree, buildLine(Point2D.of(0, 0), Point2D.of(1, 0)));
+        cut(tree.getMinus(), buildLine(Point2D.of(-1, 0), Point2D.of(0, 1)));
 
-        SubLine sub = buildSubLine(new Point2D(-2, 0), new Point2D(2, 0));
+        SubLine sub = buildSubLine(Point2D.of(-2, 0), Point2D.of(2, 0));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -291,8 +291,8 @@ public class CharacterizationTest {
 
         SubLine inside = (SubLine) ch.insideTouching();
         Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Point2D(-2, 0), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(-1, 0), inside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(-2, 0), inside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(-1, 0), inside.getSegments().get(0).getEnd());
 
         Assert.assertEquals(1, size(ch.getInsideSplitters()));
         Iterator<BSPTree<Point2D>> insideSplitterIter = ch.getInsideSplitters().iterator();
@@ -303,8 +303,8 @@ public class CharacterizationTest {
 
         SubLine outside = (SubLine) ch.outsideTouching();
         Assert.assertEquals(1, outside.getSegments().size());
-        assertVectorEquals(new Point2D(-1, 0), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(2, 0), outside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(-1, 0), outside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(2, 0), outside.getSegments().get(0).getEnd());
 
         Assert.assertEquals(1, size(ch.getOutsideSplitters()));
         Iterator<BSPTree<Point2D>> outsideSplitterIter = ch.getOutsideSplitters().iterator();
@@ -315,10 +315,10 @@ public class CharacterizationTest {
     public void testCharacterize_onHyperplane_multipleSplits_oppositeOrientation() {
         // arrange
         BSPTree<Point2D> tree = new BSPTree<>(Boolean.TRUE);
-        cut(tree, buildLine(new Point2D(0, 0), new Point2D(1, 0)));
-        cut(tree.getMinus(), buildLine(new Point2D(-1, 0), new Point2D(0, 1)));
+        cut(tree, buildLine(Point2D.of(0, 0), Point2D.of(1, 0)));
+        cut(tree.getMinus(), buildLine(Point2D.of(-1, 0), Point2D.of(0, 1)));
 
-        SubLine sub = buildSubLine(new Point2D(2, 0), new Point2D(-2, 0));
+        SubLine sub = buildSubLine(Point2D.of(2, 0), Point2D.of(-2, 0));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -329,8 +329,8 @@ public class CharacterizationTest {
 
         SubLine inside = (SubLine) ch.insideTouching();
         Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Point2D(-1, 0), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(-2, 0), inside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(-1, 0), inside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(-2, 0), inside.getSegments().get(0).getEnd());
 
         Assert.assertEquals(1, size(ch.getInsideSplitters()));
         Iterator<BSPTree<Point2D>> insideSplitterIter = ch.getInsideSplitters().iterator();
@@ -341,8 +341,8 @@ public class CharacterizationTest {
 
         SubLine outside = (SubLine) ch.outsideTouching();
         Assert.assertEquals(1, outside.getSegments().size());
-        assertVectorEquals(new Point2D(2, 0), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(-1, 0), outside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(2, 0), outside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(-1, 0), outside.getSegments().get(0).getEnd());
 
         Assert.assertEquals(1, size(ch.getOutsideSplitters()));
         Iterator<BSPTree<Point2D>> outsideSplitterIter = ch.getOutsideSplitters().iterator();
@@ -355,7 +355,7 @@ public class CharacterizationTest {
         PolygonsSet poly = new PolygonsSet(0, 1, 0, 1, TEST_TOLERANCE);
         BSPTree<Point2D> tree = poly.getTree(false);
 
-        SubLine sub = buildSubLine(new Point2D(2, 0), new Point2D(-2, 0));
+        SubLine sub = buildSubLine(Point2D.of(2, 0), Point2D.of(-2, 0));
 
         // act
         Characterization<Point2D> ch = new Characterization<>(tree, sub);
@@ -366,8 +366,8 @@ public class CharacterizationTest {
 
         SubLine inside = (SubLine) ch.insideTouching();
         Assert.assertEquals(1, inside.getSegments().size());
-        assertVectorEquals(new Point2D(1, 0), inside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(0, 0), inside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(1, 0), inside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(0, 0), inside.getSegments().get(0).getEnd());
 
         Assert.assertEquals(2, size(ch.getInsideSplitters()));
 
@@ -376,10 +376,10 @@ public class CharacterizationTest {
 
         SubLine outside = (SubLine) ch.outsideTouching();
         Assert.assertEquals(2, outside.getSegments().size());
-        assertVectorEquals(new Point2D(2, 0), outside.getSegments().get(0).getStart());
-        assertVectorEquals(new Point2D(1, 0), outside.getSegments().get(0).getEnd());
-        assertVectorEquals(new Point2D(0, 0), outside.getSegments().get(1).getStart());
-        assertVectorEquals(new Point2D(-2, 0), outside.getSegments().get(1).getEnd());
+        assertVectorEquals(Point2D.of(2, 0), outside.getSegments().get(0).getStart());
+        assertVectorEquals(Point2D.of(1, 0), outside.getSegments().get(0).getEnd());
+        assertVectorEquals(Point2D.of(0, 0), outside.getSegments().get(1).getStart());
+        assertVectorEquals(Point2D.of(-2, 0), outside.getSegments().get(1).getEnd());
 
         Assert.assertEquals(2, size(ch.getOutsideSplitters()));
     }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/EuclideanTestUtils.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/EuclideanTestUtils.java
index 9fb0df1..e3ebdf9 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/EuclideanTestUtils.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/EuclideanTestUtils.java
@@ -181,7 +181,7 @@ public class EuclideanTestUtils {
             @Override
             public OrientedPoint parseHyperplane()
                 throws IOException, ParseException {
-                return new OrientedPoint(new Point1D(getNumber()), getBoolean(), getNumber());
+                return new OrientedPoint(Point1D.of(getNumber()), getBoolean(), getNumber());
             }
 
         };
@@ -202,7 +202,7 @@ public class EuclideanTestUtils {
             @Override
             public Line parseHyperplane()
                 throws IOException, ParseException {
-                return new Line(new Point2D(getNumber(), getNumber()), getNumber(), getNumber());
+                return new Line(Point2D.of(getNumber(), getNumber()), getNumber(), getNumber());
             }
 
         };
@@ -223,8 +223,8 @@ public class EuclideanTestUtils {
             @Override
             public Plane parseHyperplane()
                 throws IOException, ParseException {
-                return new Plane(new Point3D(getNumber(), getNumber(), getNumber()),
-                                 new Vector3D(getNumber(), getNumber(), getNumber()),
+                return new Plane(Point3D.of(getNumber(), getNumber(), getNumber()),
+                                 Vector3D.of(getNumber(), getNumber(), getNumber()),
                                  getNumber());
             }
 
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalsSetTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalsSetTest.java
index dd70adf..f032f7b 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalsSetTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalsSetTest.java
@@ -150,7 +150,7 @@ public class IntervalsSetTest {
         Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
         Assert.assertEquals(10.0, set.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point1D(4.0), set.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point1D.of(4.0), set.getBarycenter(), TEST_TOLERANCE);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
@@ -176,7 +176,7 @@ public class IntervalsSetTest {
         Assert.assertEquals(1.0, set.getSup(), TEST_TOLERANCE);
         Assert.assertEquals(0.0, set.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point1D(1.0), set.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point1D.of(1.0), set.getBarycenter(), TEST_TOLERANCE);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
@@ -294,7 +294,7 @@ public class IntervalsSetTest {
         Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
         Assert.assertEquals(10.0, set.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point1D(4.0), set.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point1D.of(4.0), set.getBarycenter(), TEST_TOLERANCE);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
@@ -327,7 +327,7 @@ public class IntervalsSetTest {
         Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
         Assert.assertEquals(7.0, set.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point1D(29.5 / 7.0), set.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point1D.of(29.5 / 7.0), set.getBarycenter(), TEST_TOLERANCE);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(2, intervals.size());
@@ -365,7 +365,7 @@ public class IntervalsSetTest {
         EuclideanTestUtils.assertPositiveInfinity(set.getSup());
         EuclideanTestUtils.assertPositiveInfinity(set.getSize());
         Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point1D(Double.NaN), set.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point1D.of(Double.NaN), set.getBarycenter(), TEST_TOLERANCE);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(4, intervals.size());
@@ -461,31 +461,31 @@ public class IntervalsSetTest {
         IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
 
         // act/assert
-        assertProjection(new Point1D(-2), -1, set, new Point1D(-3));
-        assertProjection(new Point1D(-2), 0, set, new Point1D(-2));
-        assertProjection(new Point1D(-2), 0.1, set, new Point1D(-1.9));
+        assertProjection(Point1D.of(-2), -1, set, Point1D.of(-3));
+        assertProjection(Point1D.of(-2), 0, set, Point1D.of(-2));
+        assertProjection(Point1D.of(-2), 0.1, set, Point1D.of(-1.9));
 
-        assertProjection(new Point1D(-1), 0.5, set, new Point1D(-1.5));
-        assertProjection(new Point1D(-1), 0.1, set, new Point1D(-1.1));
-        assertProjection(new Point1D(-1), 0, set, new Point1D(-1));
-        assertProjection(new Point1D(-1), -1, set, new Point1D(0));
+        assertProjection(Point1D.of(-1), 0.5, set, Point1D.of(-1.5));
+        assertProjection(Point1D.of(-1), 0.1, set, Point1D.of(-1.1));
+        assertProjection(Point1D.of(-1), 0, set, Point1D.of(-1));
+        assertProjection(Point1D.of(-1), -1, set, Point1D.of(0));
 
-        assertProjection(new Point1D(2), -1, set, new Point1D(1));
-        assertProjection(new Point1D(2), 0, set, new Point1D(2));
-        assertProjection(new Point1D(2), 1, set, new Point1D(3));
+        assertProjection(Point1D.of(2), -1, set, Point1D.of(1));
+        assertProjection(Point1D.of(2), 0, set, Point1D.of(2));
+        assertProjection(Point1D.of(2), 1, set, Point1D.of(3));
 
-        assertProjection(new Point1D(5), 1, set, new Point1D(4));
-        assertProjection(new Point1D(5), 0, set, new Point1D(5));
+        assertProjection(Point1D.of(5), 1, set, Point1D.of(4));
+        assertProjection(Point1D.of(5), 0, set, Point1D.of(5));
 
-        assertProjection(new Point1D(5), -1, set, new Point1D(6));
-        assertProjection(new Point1D(5), -2, set, new Point1D(7));
+        assertProjection(Point1D.of(5), -1, set, Point1D.of(6));
+        assertProjection(Point1D.of(5), -2, set, Point1D.of(7));
 
-        assertProjection(new Point1D(9), -1, set, new Point1D(8));
-        assertProjection(new Point1D(9), 0, set, new Point1D(9));
-        assertProjection(new Point1D(9), 0.1, set, new Point1D(9.1));
+        assertProjection(Point1D.of(9), -1, set, Point1D.of(8));
+        assertProjection(Point1D.of(9), 0, set, Point1D.of(9));
+        assertProjection(Point1D.of(9), 0.1, set, Point1D.of(9.1));
 
-        assertProjection(new Point1D(10), 0, set, new Point1D(10));
-        assertProjection(new Point1D(10), -1, set, new Point1D(11));
+        assertProjection(Point1D.of(10), 0, set, Point1D.of(10));
+        assertProjection(Point1D.of(10), -1, set, Point1D.of(11));
     }
 
     @Test
@@ -493,11 +493,11 @@ public class IntervalsSetTest {
         IntervalsSet set = new IntervalsSet(2.3, 5.7, 1.0e-10);
         Assert.assertEquals(3.4, set.getSize(), 1.0e-10);
         Assert.assertEquals(4.0, set.getBarycenter().getX(), 1.0e-10);
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(2.3)));
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(5.7)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new Point1D(1.2)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new Point1D(8.7)));
-        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new Point1D(3.0)));
+        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(Point1D.of(2.3)));
+        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(Point1D.of(5.7)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(Point1D.of(1.2)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(Point1D.of(8.7)));
+        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(Point1D.of(3.0)));
         Assert.assertEquals(2.3, set.getInf(), 1.0e-10);
         Assert.assertEquals(5.7, set.getSup(), 1.0e-10);
     }
@@ -505,11 +505,11 @@ public class IntervalsSetTest {
     @Test
     public void testInfinite() {
         IntervalsSet set = new IntervalsSet(9.0, Double.POSITIVE_INFINITY, 1.0e-10);
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(9.0)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new Point1D(8.4)));
+        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(Point1D.of(9.0)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(Point1D.of(8.4)));
         for (double e = 1.0; e <= 6.0; e += 1.0) {
             Assert.assertEquals(Region.Location.INSIDE,
-                                set.checkPoint(new Point1D(Math.pow(10.0, e))));
+                                set.checkPoint(Point1D.of(Math.pow(10.0, e))));
         }
         Assert.assertTrue(Double.isInfinite(set.getSize()));
         Assert.assertEquals(9.0, set.getInf(), 1.0e-10);
@@ -558,7 +558,7 @@ public class IntervalsSetTest {
     }
 
     private void assertLocation(Region.Location location, IntervalsSet set, double pt) {
-        Assert.assertEquals(location, set.checkPoint(new Point1D(pt)));
+        Assert.assertEquals(location, set.checkPoint(Point1D.of(pt)));
     }
 
     private void assertInterval(double expectedInf, double expectedSup, Interval actual, double tolerance) {
@@ -581,6 +581,6 @@ public class IntervalsSetTest {
 
     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 Point1D(location), direct, tolerance), null);
+        return new SubOrientedPoint(new OrientedPoint(Point1D.of(location), direct, tolerance), null);
     }
 }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java
index a986b91..37140ca 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java
@@ -26,7 +26,7 @@ public class OrientedPointTest {
     @Test
     public void testConstructor() {
         // act
-        OrientedPoint pt = new OrientedPoint(new Point1D(2.0), true, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Point1D.of(2.0), true, 1e-5);
 
         // assert
         Assert.assertEquals(2.0, pt.getLocation().getX(), Precision.EPSILON);
@@ -37,7 +37,7 @@ public class OrientedPointTest {
     @Test
     public void testCopySelf() {
         // arrange
-        OrientedPoint orig = new OrientedPoint(new Point1D(2.0), true, 1e-5);
+        OrientedPoint orig = new OrientedPoint(Point1D.of(2.0), true, 1e-5);
 
         // act
         OrientedPoint copy = orig.copySelf();
@@ -52,37 +52,37 @@ public class OrientedPointTest {
     @Test
     public void testGetOffset_direct_point() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(new Point1D(-1.0), true, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Point1D.of(-1.0), true, 1e-5);
 
         // act/assert
-        Assert.assertEquals(-99, pt.getOffset(new Point1D(-100)), Precision.EPSILON);
-        Assert.assertEquals(-1, pt.getOffset(new Point1D(-2)), Precision.EPSILON);
-        Assert.assertEquals(-0.01, pt.getOffset(new Point1D(-1.01)), Precision.EPSILON);
-        Assert.assertEquals(0.0, pt.getOffset(new Point1D(-1.0)), Precision.EPSILON);
-        Assert.assertEquals(0.01, pt.getOffset(new Point1D(-0.99)), Precision.EPSILON);
-        Assert.assertEquals(1, pt.getOffset(new Point1D(0)), Precision.EPSILON);
-        Assert.assertEquals(101, pt.getOffset(new Point1D(100)), Precision.EPSILON);
+        Assert.assertEquals(-99, pt.getOffset(Point1D.of(-100)), Precision.EPSILON);
+        Assert.assertEquals(-1, pt.getOffset(Point1D.of(-2)), Precision.EPSILON);
+        Assert.assertEquals(-0.01, pt.getOffset(Point1D.of(-1.01)), Precision.EPSILON);
+        Assert.assertEquals(0.0, pt.getOffset(Point1D.of(-1.0)), Precision.EPSILON);
+        Assert.assertEquals(0.01, pt.getOffset(Point1D.of(-0.99)), Precision.EPSILON);
+        Assert.assertEquals(1, pt.getOffset(Point1D.of(0)), Precision.EPSILON);
+        Assert.assertEquals(101, pt.getOffset(Point1D.of(100)), Precision.EPSILON);
     }
 
     @Test
     public void testGetOffset_notDirect_point() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(new Point1D(-1.0), false, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Point1D.of(-1.0), false, 1e-5);
 
         // act/assert
-        Assert.assertEquals(99, pt.getOffset(new Point1D(-100)), Precision.EPSILON);
-        Assert.assertEquals(1, pt.getOffset(new Point1D(-2)), Precision.EPSILON);
-        Assert.assertEquals(0.01, pt.getOffset(new Point1D(-1.01)), Precision.EPSILON);
-        Assert.assertEquals(0.0, pt.getOffset(new Point1D(-1.0)), Precision.EPSILON);
-        Assert.assertEquals(-0.01, pt.getOffset(new Point1D(-0.99)), Precision.EPSILON);
-        Assert.assertEquals(-1, pt.getOffset(new Point1D(0)), Precision.EPSILON);
-        Assert.assertEquals(-101, pt.getOffset(new Point1D(100)), Precision.EPSILON);
+        Assert.assertEquals(99, pt.getOffset(Point1D.of(-100)), Precision.EPSILON);
+        Assert.assertEquals(1, pt.getOffset(Point1D.of(-2)), Precision.EPSILON);
+        Assert.assertEquals(0.01, pt.getOffset(Point1D.of(-1.01)), Precision.EPSILON);
+        Assert.assertEquals(0.0, pt.getOffset(Point1D.of(-1.0)), Precision.EPSILON);
+        Assert.assertEquals(-0.01, pt.getOffset(Point1D.of(-0.99)), Precision.EPSILON);
+        Assert.assertEquals(-1, pt.getOffset(Point1D.of(0)), Precision.EPSILON);
+        Assert.assertEquals(-101, pt.getOffset(Point1D.of(100)), Precision.EPSILON);
     }
 
     @Test
     public void testWholeHyperplane() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(new Point1D(1.0), false, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Point1D.of(1.0), false, 1e-5);
 
         // act
         SubOrientedPoint subPt = pt.wholeHyperplane();
@@ -95,7 +95,7 @@ public class OrientedPointTest {
     @Test
     public void testWholeSpace() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(new Point1D(1.0), false, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Point1D.of(1.0), false, 1e-5);
 
         // act
         IntervalsSet set = pt.wholeSpace();
@@ -108,10 +108,10 @@ public class OrientedPointTest {
     @Test
     public void testSameOrientationAs() {
         // arrange
-        OrientedPoint notDirect1 = new OrientedPoint(new Point1D(1.0), false, 1e-5);
-        OrientedPoint notDirect2 = new OrientedPoint(new Point1D(1.0), false, 1e-5);
-        OrientedPoint direct1 = new OrientedPoint(new Point1D(1.0), true, 1e-5);
-        OrientedPoint direct2 = new OrientedPoint(new Point1D(1.0), true, 1e-5);
+        OrientedPoint notDirect1 = new OrientedPoint(Point1D.of(1.0), false, 1e-5);
+        OrientedPoint notDirect2 = new OrientedPoint(Point1D.of(1.0), false, 1e-5);
+        OrientedPoint direct1 = new OrientedPoint(Point1D.of(1.0), true, 1e-5);
+        OrientedPoint direct2 = new OrientedPoint(Point1D.of(1.0), true, 1e-5);
 
         // act/assert
         Assert.assertTrue(notDirect1.sameOrientationAs(notDirect1));
@@ -129,19 +129,19 @@ public class OrientedPointTest {
     @Test
     public void testProject() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(new Point1D(1.0), true, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Point1D.of(1.0), true, 1e-5);
 
         // act/assert
-        Assert.assertEquals(1.0, pt.project(new Point1D(-1.0)).getX(), Precision.EPSILON);
-        Assert.assertEquals(1.0, pt.project(new Point1D(0.0)).getX(), Precision.EPSILON);
-        Assert.assertEquals(1.0, pt.project(new Point1D(1.0)).getX(), Precision.EPSILON);
-        Assert.assertEquals(1.0, pt.project(new Point1D(100.0)).getX(), Precision.EPSILON);
+        Assert.assertEquals(1.0, pt.project(Point1D.of(-1.0)).getX(), Precision.EPSILON);
+        Assert.assertEquals(1.0, pt.project(Point1D.of(0.0)).getX(), Precision.EPSILON);
+        Assert.assertEquals(1.0, pt.project(Point1D.of(1.0)).getX(), Precision.EPSILON);
+        Assert.assertEquals(1.0, pt.project(Point1D.of(100.0)).getX(), Precision.EPSILON);
     }
 
     @Test
     public void testRevertSelf() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(new Point1D(2.0), true, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Point1D.of(2.0), true, 1e-5);
 
         // act
         pt.revertSelf();
@@ -151,7 +151,7 @@ public class OrientedPointTest {
         Assert.assertFalse(pt.isDirect());
         Assert.assertEquals(1e-5, pt.getTolerance(), Precision.EPSILON);
 
-        Assert.assertEquals(1, pt.getOffset(new Point1D(1.0)), Precision.EPSILON);
-        Assert.assertEquals(-1, pt.getOffset(new Point1D(3.0)), Precision.EPSILON);
+        Assert.assertEquals(1, pt.getOffset(Point1D.of(1.0)), Precision.EPSILON);
+        Assert.assertEquals(-1, pt.getOffset(Point1D.of(3.0)), Precision.EPSILON);
     }
 }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
index 702abef..f17af96 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
@@ -197,13 +197,13 @@ public class Point1DTest {
     @Test
     public void testOf_coordinateArg() {
         // act/assert
-        checkPoint(Point1D.of(new Vector1D(0)), 0.0);
-        checkPoint(Point1D.of(new Vector1D(-1)), -1.0);
-        checkPoint(Point1D.of(new Vector1D(1)), 1.0);
-        checkPoint(Point1D.of(new Vector1D(Math.PI)), Math.PI);
-        checkPoint(Point1D.of(new Vector1D(Double.NaN)), Double.NaN);
-        checkPoint(Point1D.of(new Vector1D(Double.NEGATIVE_INFINITY)), Double.NEGATIVE_INFINITY);
-        checkPoint(Point1D.of(new Vector1D(Double.POSITIVE_INFINITY)), Double.POSITIVE_INFINITY);
+        checkPoint(Point1D.of(Vector1D.of(0)), 0.0);
+        checkPoint(Point1D.of(Vector1D.of(-1)), -1.0);
+        checkPoint(Point1D.of(Vector1D.of(1)), 1.0);
+        checkPoint(Point1D.of(Vector1D.of(Math.PI)), Math.PI);
+        checkPoint(Point1D.of(Vector1D.of(Double.NaN)), Double.NaN);
+        checkPoint(Point1D.of(Vector1D.of(Double.NEGATIVE_INFINITY)), Double.NEGATIVE_INFINITY);
+        checkPoint(Point1D.of(Vector1D.of(Double.POSITIVE_INFINITY)), Double.POSITIVE_INFINITY);
     }
 
     @Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPointTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPointTest.java
index 6cf8de7..ab3c9d9 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPointTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPointTest.java
@@ -28,7 +28,7 @@ public class SubOrientedPointTest {
     @Test
     public void testGetSize() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(new Point1D(1), true, TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Point1D.of(1), true, TEST_TOLERANCE);
         SubOrientedPoint pt = hyperplane.wholeHyperplane();
 
         // act/assert
@@ -38,7 +38,7 @@ public class SubOrientedPointTest {
     @Test
     public void testIsEmpty() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(new Point1D(1), true, TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Point1D.of(1), true, TEST_TOLERANCE);
         SubOrientedPoint pt = hyperplane.wholeHyperplane();
 
         // act/assert
@@ -48,10 +48,10 @@ public class SubOrientedPointTest {
     @Test
     public void testBuildNew() {
         // arrange
-        OrientedPoint originalHyperplane = new OrientedPoint(new Point1D(1), true, TEST_TOLERANCE);
+        OrientedPoint originalHyperplane = new OrientedPoint(Point1D.of(1), true, TEST_TOLERANCE);
         SubOrientedPoint pt = originalHyperplane.wholeHyperplane();
 
-        OrientedPoint hyperplane = new OrientedPoint(new Point1D(2), true, TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Point1D.of(2), true, TEST_TOLERANCE);
         IntervalsSet intervals = new IntervalsSet(2, 3, TEST_TOLERANCE);
 
         // act
@@ -66,11 +66,11 @@ public class SubOrientedPointTest {
     @Test
     public void testSplit_resultOnMinusSide() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(new Point1D(1), true, TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Point1D.of(1), true, TEST_TOLERANCE);
         IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
         SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-        OrientedPoint splitter = new OrientedPoint(new Point1D(2), true, TEST_TOLERANCE);
+        OrientedPoint splitter = new OrientedPoint(Point1D.of(2), true, TEST_TOLERANCE);
 
         // act
         SplitSubHyperplane<Point1D> split = pt.split(splitter);
@@ -92,11 +92,11 @@ public class SubOrientedPointTest {
     @Test
     public void testSplit_resultOnPlusSide() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(new Point1D(1), true, TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Point1D.of(1), true, TEST_TOLERANCE);
         IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
         SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-        OrientedPoint splitter = new OrientedPoint(new Point1D(0), true, TEST_TOLERANCE);
+        OrientedPoint splitter = new OrientedPoint(Point1D.of(0), true, TEST_TOLERANCE);
 
         // act
         SplitSubHyperplane<Point1D> split = pt.split(splitter);
@@ -118,11 +118,11 @@ public class SubOrientedPointTest {
     @Test
     public void testSplit_equivalentHyperplanes() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(new Point1D(1), true, TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Point1D.of(1), true, TEST_TOLERANCE);
         IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
         SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-        OrientedPoint splitter = new OrientedPoint(new Point1D(1), true, TEST_TOLERANCE);
+        OrientedPoint splitter = new OrientedPoint(Point1D.of(1), true, TEST_TOLERANCE);
 
         // act
         SplitSubHyperplane<Point1D> split = pt.split(splitter);
@@ -137,23 +137,23 @@ public class SubOrientedPointTest {
     @Test
     public void testSplit_usesToleranceFromParentHyperplane() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(new Point1D(1), true, 0.1);
+        OrientedPoint hyperplane = new OrientedPoint(Point1D.of(1), true, 0.1);
         SubOrientedPoint pt = hyperplane.wholeHyperplane();
 
         // act/assert
-        SplitSubHyperplane<Point1D> plusSplit = pt.split(new OrientedPoint(new Point1D(0.899), true, 1e-10));
+        SplitSubHyperplane<Point1D> plusSplit = pt.split(new OrientedPoint(Point1D.of(0.899), true, 1e-10));
         Assert.assertNull(plusSplit.getMinus());
         Assert.assertNotNull(plusSplit.getPlus());
 
-        SplitSubHyperplane<Point1D> lowWithinTolerance = pt.split(new OrientedPoint(new Point1D(0.901), true, 1e-10));
+        SplitSubHyperplane<Point1D> lowWithinTolerance = pt.split(new OrientedPoint(Point1D.of(0.901), true, 1e-10));
         Assert.assertNull(lowWithinTolerance.getMinus());
         Assert.assertNull(lowWithinTolerance.getPlus());
 
-        SplitSubHyperplane<Point1D> highWithinTolerance = pt.split(new OrientedPoint(new Point1D(1.09), true, 1e-10));
+        SplitSubHyperplane<Point1D> highWithinTolerance = pt.split(new OrientedPoint(Point1D.of(1.09), true, 1e-10));
         Assert.assertNull(highWithinTolerance.getMinus());
         Assert.assertNull(highWithinTolerance.getPlus());
 
-        SplitSubHyperplane<Point1D> minusSplit = pt.split(new OrientedPoint(new Point1D(1.101), true, 1e-10));
+        SplitSubHyperplane<Point1D> minusSplit = pt.split(new OrientedPoint(Point1D.of(1.101), true, 1e-10));
         Assert.assertNotNull(minusSplit.getMinus());
         Assert.assertNull(minusSplit.getPlus());
     }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/LineTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/LineTest.java
index 6a6a87b..e49c61b 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/LineTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/LineTest.java
@@ -23,8 +23,8 @@ public class LineTest {
 
     @Test
     public void testContains() {
-        Point3D p1 = new Point3D(0, 0, 1);
-        Line l = new Line(p1, new Point3D(0, 0, 2), 1.0e-10);
+        Point3D p1 = Point3D.of(0, 0, 1);
+        Line l = new Line(p1, Point3D.of(0, 0, 2), 1.0e-10);
         Assert.assertTrue(l.contains(p1));
         Assert.assertTrue(l.contains(Point3D.vectorCombination(1.0, p1, 0.3, l.getDirection())));
         Vector3D u = l.getDirection().orthogonal();
@@ -37,8 +37,8 @@ public class LineTest {
 
     @Test
     public void testSimilar() {
-        Point3D p1  = new Point3D (1.2, 3.4, -5.8);
-        Point3D p2  = new Point3D (3.4, -5.8, 1.2);
+        Point3D p1  = Point3D.of(1.2, 3.4, -5.8);
+        Point3D p2  = Point3D.of(3.4, -5.8, 1.2);
         Line     lA  = new Line(p1, p2, 1.0e-10);
         Line     lB  = new Line(p2, p1, 1.0e-10);
         Assert.assertTrue(lA.isSimilarTo(lB));
@@ -47,89 +47,89 @@ public class LineTest {
 
     @Test
     public void testPointDistance() {
-        Line l = new Line(new Point3D(0, 1, 1), new Point3D(0, 2, 2), 1.0e-10);
-        Assert.assertEquals(Math.sqrt(3.0 / 2.0), l.distance(new Point3D(1, 0, 1)), 1.0e-10);
-        Assert.assertEquals(0, l.distance(new Point3D(0, -4, -4)), 1.0e-10);
+        Line l = new Line(Point3D.of(0, 1, 1), Point3D.of(0, 2, 2), 1.0e-10);
+        Assert.assertEquals(Math.sqrt(3.0 / 2.0), l.distance(Point3D.of(1, 0, 1)), 1.0e-10);
+        Assert.assertEquals(0, l.distance(Point3D.of(0, -4, -4)), 1.0e-10);
     }
 
     @Test
     public void testLineDistance() {
-        Line l = new Line(new Point3D(0, 1, 1), new Point3D(0, 2, 2), 1.0e-10);
+        Line l = new Line(Point3D.of(0, 1, 1), Point3D.of(0, 2, 2), 1.0e-10);
         Assert.assertEquals(1.0,
-                            l.distance(new Line(new Point3D(1, 0, 1), new Point3D(1, 0, 2), 1.0e-10)),
+                            l.distance(new Line(Point3D.of(1, 0, 1), Point3D.of(1, 0, 2), 1.0e-10)),
                             1.0e-10);
         Assert.assertEquals(0.5,
-                            l.distance(new Line(new Point3D(-0.5, 0, 0), new Point3D(-0.5, -1, -1), 1.0e-10)),
+                            l.distance(new Line(Point3D.of(-0.5, 0, 0), Point3D.of(-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 Point3D(0, -4, -4), new Point3D(0, -5, -5), 1.0e-10)),
+                            l.distance(new Line(Point3D.of(0, -4, -4), Point3D.of(0, -5, -5), 1.0e-10)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.distance(new Line(new Point3D(0, -4, -4), new Point3D(0, -3, -4), 1.0e-10)),
+                            l.distance(new Line(Point3D.of(0, -4, -4), Point3D.of(0, -3, -4), 1.0e-10)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.distance(new Line(new Point3D(0, -4, -4), new Point3D(1, -4, -4), 1.0e-10)),
+                            l.distance(new Line(Point3D.of(0, -4, -4), Point3D.of(1, -4, -4), 1.0e-10)),
                             1.0e-10);
         Assert.assertEquals(Math.sqrt(8),
-                            l.distance(new Line(new Point3D(0, -4, 0), new Point3D(1, -4, 0), 1.0e-10)),
+                            l.distance(new Line(Point3D.of(0, -4, 0), Point3D.of(1, -4, 0), 1.0e-10)),
                             1.0e-10);
     }
 
     @Test
     public void testClosest() {
-        Line l = new Line(new Point3D(0, 1, 1), new Point3D(0, 2, 2), 1.0e-10);
+        Line l = new Line(Point3D.of(0, 1, 1), Point3D.of(0, 2, 2), 1.0e-10);
         Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(new Point3D(1, 0, 1), new Point3D(1, 0, 2), 1.0e-10)).distance(new Point3D(0, 0, 0)),
+                            l.closestPoint(new Line(Point3D.of(1, 0, 1), Point3D.of(1, 0, 2), 1.0e-10)).distance(Point3D.of(0, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.5,
-                            l.closestPoint(new Line(new Point3D(-0.5, 0, 0), new Point3D(-0.5, -1, -1), 1.0e-10)).distance(new Point3D(-0.5, 0, 0)),
+                            l.closestPoint(new Line(Point3D.of(-0.5, 0, 0), Point3D.of(-0.5, -1, -1), 1.0e-10)).distance(Point3D.of(-0.5, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.closestPoint(l).distance(new Point3D(0, 0, 0)),
+                            l.closestPoint(l).distance(Point3D.of(0, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(new Point3D(0, -4, -4), new Point3D(0, -5, -5), 1.0e-10)).distance(new Point3D(0, 0, 0)),
+                            l.closestPoint(new Line(Point3D.of(0, -4, -4), Point3D.of(0, -5, -5), 1.0e-10)).distance(Point3D.of(0, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(new Point3D(0, -4, -4), new Point3D(0, -3, -4), 1.0e-10)).distance(new Point3D(0, -4, -4)),
+                            l.closestPoint(new Line(Point3D.of(0, -4, -4), Point3D.of(0, -3, -4), 1.0e-10)).distance(Point3D.of(0, -4, -4)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(new Point3D(0, -4, -4), new Point3D(1, -4, -4), 1.0e-10)).distance(new Point3D(0, -4, -4)),
+                            l.closestPoint(new Line(Point3D.of(0, -4, -4), Point3D.of(1, -4, -4), 1.0e-10)).distance(Point3D.of(0, -4, -4)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(new Point3D(0, -4, 0), new Point3D(1, -4, 0), 1.0e-10)).distance(new Point3D(0, -2, -2)),
+                            l.closestPoint(new Line(Point3D.of(0, -4, 0), Point3D.of(1, -4, 0), 1.0e-10)).distance(Point3D.of(0, -2, -2)),
                             1.0e-10);
     }
 
     @Test
     public void testIntersection() {
-        Line l = new Line(new Point3D(0, 1, 1), new Point3D(0, 2, 2), 1.0e-10);
-        Assert.assertNull(l.intersection(new Line(new Point3D(1, 0, 1), new Point3D(1, 0, 2), 1.0e-10)));
-        Assert.assertNull(l.intersection(new Line(new Point3D(-0.5, 0, 0), new Point3D(-0.5, -1, -1), 1.0e-10)));
+        Line l = new Line(Point3D.of(0, 1, 1), Point3D.of(0, 2, 2), 1.0e-10);
+        Assert.assertNull(l.intersection(new Line(Point3D.of(1, 0, 1), Point3D.of(1, 0, 2), 1.0e-10)));
+        Assert.assertNull(l.intersection(new Line(Point3D.of(-0.5, 0, 0), Point3D.of(-0.5, -1, -1), 1.0e-10)));
         Assert.assertEquals(0.0,
-                            l.intersection(l).distance(new Point3D(0, 0, 0)),
+                            l.intersection(l).distance(Point3D.of(0, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.intersection(new Line(new Point3D(0, -4, -4), new Point3D(0, -5, -5), 1.0e-10)).distance(new Point3D(0, 0, 0)),
+                            l.intersection(new Line(Point3D.of(0, -4, -4), Point3D.of(0, -5, -5), 1.0e-10)).distance(Point3D.of(0, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.intersection(new Line(new Point3D(0, -4, -4), new Point3D(0, -3, -4), 1.0e-10)).distance(new Point3D(0, -4, -4)),
+                            l.intersection(new Line(Point3D.of(0, -4, -4), Point3D.of(0, -3, -4), 1.0e-10)).distance(Point3D.of(0, -4, -4)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.intersection(new Line(new Point3D(0, -4, -4), new Point3D(1, -4, -4), 1.0e-10)).distance(new Point3D(0, -4, -4)),
+                            l.intersection(new Line(Point3D.of(0, -4, -4), Point3D.of(1, -4, -4), 1.0e-10)).distance(Point3D.of(0, -4, -4)),
                             1.0e-10);
-        Assert.assertNull(l.intersection(new Line(new Point3D(0, -4, 0), new Point3D(1, -4, 0), 1.0e-10)));
+        Assert.assertNull(l.intersection(new Line(Point3D.of(0, -4, 0), Point3D.of(1, -4, 0), 1.0e-10)));
     }
 
     @Test
     public void testRevert() {
 
         // setup
-        Line line = new Line(new Point3D(1653345.6696423641, 6170370.041579291, 90000),
-                             new Point3D(1650757.5050732433, 6160710.879908984, 0.9),
+        Line line = new Line(Point3D.of(1653345.6696423641, 6170370.041579291, 90000),
+                             Point3D.of(1650757.5050732433, 6160710.879908984, 0.9),
                              1.0e-10);
         Vector3D expected = line.getDirection().negate();
 
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PLYParser.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PLYParser.java
index 78ebefd..8a26afa 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PLYParser.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PLYParser.java
@@ -175,7 +175,7 @@ public class PLYParser {
                     fields.get(zIndex).getToken() != Token.UNKNOWN) {
                     complain();
                 }
-                vertices[i] = new Point3D(Double.parseDouble(fields.get(xIndex).getValue()),
+                vertices[i] = Point3D.of(Double.parseDouble(fields.get(xIndex).getValue()),
                                            Double.parseDouble(fields.get(yIndex).getValue()),
                                            Double.parseDouble(fields.get(zIndex).getValue()));
             }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
index f6080a8..d6e3039 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
@@ -27,18 +27,18 @@ public class PlaneTest {
 
     @Test
     public void testContains() {
-        Plane p = new Plane(new Point3D(0, 0, 1), new Vector3D(0, 0, 1), 1.0e-10);
-        Assert.assertTrue(p.contains(new Point3D(0, 0, 1)));
-        Assert.assertTrue(p.contains(new Point3D(17, -32, 1)));
-        Assert.assertTrue(! p.contains(new Point3D(17, -32, 1.001)));
+        Plane p = new Plane(Point3D.of(0, 0, 1), Vector3D.of(0, 0, 1), 1.0e-10);
+        Assert.assertTrue(p.contains(Point3D.of(0, 0, 1)));
+        Assert.assertTrue(p.contains(Point3D.of(17, -32, 1)));
+        Assert.assertTrue(! p.contains(Point3D.of(17, -32, 1.001)));
     }
 
     @Test
     public void testOffset() {
-        Point3D p1 = new Point3D(1, 1, 1);
-        Plane p = new Plane(p1, new Vector3D(0.2, 0, 0), 1.0e-10);
-        Assert.assertEquals(-5.0, p.getOffset(new Point3D(-4, 0, 0)), 1.0e-10);
-        Assert.assertEquals(+5.0, p.getOffset(new Point3D(6, 10, -12)), 1.0e-10);
+        Point3D p1 = Point3D.of(1, 1, 1);
+        Plane p = new Plane(p1, Vector3D.of(0.2, 0, 0), 1.0e-10);
+        Assert.assertEquals(-5.0, p.getOffset(Point3D.of(-4, 0, 0)), 1.0e-10);
+        Assert.assertEquals(+5.0, p.getOffset(Point3D.of(6, 10, -12)), 1.0e-10);
         Assert.assertEquals(0.3,
                             p.getOffset(Point3D.vectorCombination(1.0, p1, 0.3, p.getNormal())),
                             1.0e-10);
@@ -49,15 +49,15 @@ public class PlaneTest {
 
     @Test
     public void testPoint() {
-        Plane p = new Plane(new Point3D(2, -3, 1), new Vector3D(1, 4, 9), 1.0e-10);
+        Plane p = new Plane(Point3D.of(2, -3, 1), Vector3D.of(1, 4, 9), 1.0e-10);
         Assert.assertTrue(p.contains(p.getOrigin()));
     }
 
     @Test
     public void testThreePoints() {
-        Point3D p1 = new Point3D(1.2, 3.4, -5.8);
-        Point3D p2 = new Point3D(3.4, -5.8, 1.2);
-        Point3D p3 = new Point3D(-2.0, 4.3, 0.7);
+        Point3D p1 = Point3D.of(1.2, 3.4, -5.8);
+        Point3D p2 = Point3D.of(3.4, -5.8, 1.2);
+        Point3D p3 = Point3D.of(-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));
@@ -66,9 +66,9 @@ public class PlaneTest {
 
     @Test
     public void testRotate() {
-        Point3D p1 = new Point3D(1.2, 3.4, -5.8);
-        Point3D p2 = new Point3D(3.4, -5.8, 1.2);
-        Point3D p3 = new Point3D(-2.0, 4.3, 0.7);
+        Point3D p1 = Point3D.of(1.2, 3.4, -5.8);
+        Point3D p2 = Point3D.of(3.4, -5.8, 1.2);
+        Point3D p3 = Point3D.of(-2.0, 4.3, 0.7);
         Plane    p  = new Plane(p1, p2, p3, 1.0e-10);
         Vector3D oldNormal = p.getNormal();
 
@@ -91,9 +91,9 @@ public class PlaneTest {
 
     @Test
     public void testTranslate() {
-        Point3D p1 = new Point3D(1.2, 3.4, -5.8);
-        Point3D p2 = new Point3D(3.4, -5.8, 1.2);
-        Point3D p3 = new Point3D(-2.0, 4.3, 0.7);
+        Point3D p1 = Point3D.of(1.2, 3.4, -5.8);
+        Point3D p2 = Point3D.of(3.4, -5.8, 1.2);
+        Point3D p3 = Point3D.of(-2.0, 4.3, 0.7);
         Plane    p  = new Plane(p1, p2, p3, 1.0e-10);
 
         p = p.translate(Vector3D.linearCombination(2.0, p.getU(), -1.5, p.getV()));
@@ -115,22 +115,22 @@ public class PlaneTest {
 
     @Test
     public void testIntersection() {
-        Plane p = new Plane(new Point3D(1, 2, 3), new Vector3D(-4, 1, -5), 1.0e-10);
-        Line  l = new Line(new Point3D(0.2, -3.5, 0.7), new Point3D(1.2, -2.5, -0.3), 1.0e-10);
+        Plane p = new Plane(Point3D.of(1, 2, 3), Vector3D.of(-4, 1, -5), 1.0e-10);
+        Line  l = new Line(Point3D.of(0.2, -3.5, 0.7), Point3D.of(1.2, -2.5, -0.3), 1.0e-10);
         Point3D point = p.intersection(l);
         Assert.assertTrue(p.contains(point));
         Assert.assertTrue(l.contains(point));
-        Assert.assertNull(p.intersection(new Line(new Point3D(10, 10, 10),
-                                                  new Point3D(10, 10, 10).add(p.getNormal().orthogonal()),
+        Assert.assertNull(p.intersection(new Line(Point3D.of(10, 10, 10),
+                                                  Point3D.of(10, 10, 10).add(p.getNormal().orthogonal()),
                                                   1.0e-10)));
     }
 
     @Test
     public void testIntersection2() {
-        Point3D p1  = new Point3D (1.2, 3.4, -5.8);
-        Point3D p2  = new Point3D (3.4, -5.8, 1.2);
-        Plane    pA  = new Plane(p1, p2, new Point3D (-2.0, 4.3, 0.7), 1.0e-10);
-        Plane    pB  = new Plane(p1, new Point3D (11.4, -3.8, 5.1), p2, 1.0e-10);
+        Point3D p1  = Point3D.of(1.2, 3.4, -5.8);
+        Point3D p2  = Point3D.of(3.4, -5.8, 1.2);
+        Plane    pA  = new Plane(p1, p2, Point3D.of(-2.0, 4.3, 0.7), 1.0e-10);
+        Plane    pB  = new Plane(p1, Point3D.of(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));
@@ -139,10 +139,10 @@ public class PlaneTest {
 
     @Test
     public void testIntersection3() {
-        Point3D reference = new Point3D (1.2, 3.4, -5.8);
-        Plane p1 = new Plane(reference, new Vector3D(1, 3, 3), 1.0e-10);
-        Plane p2 = new Plane(reference, new Vector3D(-2, 4, 0), 1.0e-10);
-        Plane p3 = new Plane(reference, new Vector3D(7, 0, -4), 1.0e-10);
+        Point3D reference = Point3D.of(1.2, 3.4, -5.8);
+        Plane p1 = new Plane(reference, Vector3D.of(1, 3, 3), 1.0e-10);
+        Plane p2 = new Plane(reference, Vector3D.of(-2, 4, 0), 1.0e-10);
+        Plane p3 = new Plane(reference, Vector3D.of(7, 0, -4), 1.0e-10);
         Point3D p = Plane.intersection(p1, p2, p3);
         Assert.assertEquals(reference.getX(), p.getX(), 1.0e-10);
         Assert.assertEquals(reference.getY(), p.getY(), 1.0e-10);
@@ -151,11 +151,11 @@ public class PlaneTest {
 
     @Test
     public void testSimilar() {
-        Point3D p1  = new Point3D (1.2, 3.4, -5.8);
-        Point3D p2  = new Point3D (3.4, -5.8, 1.2);
-        Point3D p3  = new Point3D (-2.0, 4.3, 0.7);
+        Point3D p1  = Point3D.of(1.2, 3.4, -5.8);
+        Point3D p2  = Point3D.of(3.4, -5.8, 1.2);
+        Point3D p3  = Point3D.of(-2.0, 4.3, 0.7);
         Plane    pA  = new Plane(p1, p2, p3, 1.0e-10);
-        Plane    pB  = new Plane(p1, new Point3D (11.4, -3.8, 5.1), p2, 1.0e-10);
+        Plane    pB  = new Plane(p1, Point3D.of(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)));
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSetTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSetTest.java
index 2e04ec1..fe6c74d 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSetTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSetTest.java
@@ -60,11 +60,11 @@ public class PolyhedronsSetTest {
         Assert.assertTrue(polySet.isFull());
 
         checkPoints(Region.Location.INSIDE, polySet,
-                new Point3D(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
-                new Point3D(-100, -100, -100),
-                new Point3D(0, 0, 0),
-                new Point3D(100, 100, 100),
-                new Point3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
+                Point3D.of(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
+                Point3D.of(-100, -100, -100),
+                Point3D.of(0, 0, 0),
+                Point3D.of(100, 100, 100),
+                Point3D.of(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
     }
 
     @Test
@@ -81,11 +81,11 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(polySet.isFull());
 
         checkPoints(Region.Location.OUTSIDE, polySet,
-                new Point3D(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
-                new Point3D(-100, -100, -100),
-                new Point3D(0, 0, 0),
-                new Point3D(100, 100, 100),
-                new Point3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
+                Point3D.of(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
+                Point3D.of(-100, -100, -100),
+                Point3D.of(0, 0, 0),
+                Point3D.of(100, 100, 100),
+                Point3D.of(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
     }
 
     @Test
@@ -107,12 +107,12 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(polySet.isFull());
 
         checkPoints(Region.Location.INSIDE, polySet,
-                new Point3D(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
-                new Point3D(-100, -100, -100));
-        checkPoints(Region.Location.BOUNDARY, polySet, new Point3D(0, 0, 0));
+                Point3D.of(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
+                Point3D.of(-100, -100, -100));
+        checkPoints(Region.Location.BOUNDARY, polySet, Point3D.of(0, 0, 0));
         checkPoints(Region.Location.OUTSIDE, polySet,
-                new Point3D(100, 100, 100),
-                new Point3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
+                Point3D.of(100, 100, 100),
+                Point3D.of(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
     }
 
     @Test
@@ -133,12 +133,12 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(polySet.isFull());
 
         checkPoints(Region.Location.INSIDE, polySet,
-                new Point3D(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
-                new Point3D(-100, -100, -100),
-                new Point3D(100, 100, 100),
-                new Point3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
+                Point3D.of(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
+                Point3D.of(-100, -100, -100),
+                Point3D.of(100, 100, 100),
+                Point3D.of(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
         checkPoints(Region.Location.OUTSIDE, polySet,
-                new Point3D(0, 0, 0));
+                Point3D.of(0, 0, 0));
     }
 
     @Test
@@ -175,50 +175,50 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(polySet.isFull());
 
         checkPoints(Region.Location.OUTSIDE, polySet,
-                new Point3D(-1, 0, 0),
-                new Point3D(1, 0, 0),
-                new Point3D(0, -1, 0),
-                new Point3D(0, 1, 0),
-                new Point3D(0, 0, -1),
-                new Point3D(0, 0, 1),
-
-                new Point3D(1, 1, 1),
-                new Point3D(1, 1, -1),
-                new Point3D(1, -1, 1),
-                new Point3D(1, -1, -1),
-                new Point3D(-1, 1, 1),
-                new Point3D(-1, 1, -1),
-                new Point3D(-1, -1, 1),
-                new Point3D(-1, -1, -1));
+                Point3D.of(-1, 0, 0),
+                Point3D.of(1, 0, 0),
+                Point3D.of(0, -1, 0),
+                Point3D.of(0, 1, 0),
+                Point3D.of(0, 0, -1),
+                Point3D.of(0, 0, 1),
+
+                Point3D.of(1, 1, 1),
+                Point3D.of(1, 1, -1),
+                Point3D.of(1, -1, 1),
+                Point3D.of(1, -1, -1),
+                Point3D.of(-1, 1, 1),
+                Point3D.of(-1, 1, -1),
+                Point3D.of(-1, -1, 1),
+                Point3D.of(-1, -1, -1));
 
         checkPoints(Region.Location.BOUNDARY, polySet,
-                new Point3D(0.5, 0, 0),
-                new Point3D(-0.5, 0, 0),
-                new Point3D(0, 0.5, 0),
-                new Point3D(0, -0.5, 0),
-                new Point3D(0, 0, 0.5),
-                new Point3D(0, 0, -0.5),
-
-                new Point3D(0.5, 0.5, 0.5),
-                new Point3D(0.5, 0.5, -0.5),
-                new Point3D(0.5, -0.5, 0.5),
-                new Point3D(0.5, -0.5, -0.5),
-                new Point3D(-0.5, 0.5, 0.5),
-                new Point3D(-0.5, 0.5, -0.5),
-                new Point3D(-0.5, -0.5, 0.5),
-                new Point3D(-0.5, -0.5, -0.5));
+                Point3D.of(0.5, 0, 0),
+                Point3D.of(-0.5, 0, 0),
+                Point3D.of(0, 0.5, 0),
+                Point3D.of(0, -0.5, 0),
+                Point3D.of(0, 0, 0.5),
+                Point3D.of(0, 0, -0.5),
+
+                Point3D.of(0.5, 0.5, 0.5),
+                Point3D.of(0.5, 0.5, -0.5),
+                Point3D.of(0.5, -0.5, 0.5),
+                Point3D.of(0.5, -0.5, -0.5),
+                Point3D.of(-0.5, 0.5, 0.5),
+                Point3D.of(-0.5, 0.5, -0.5),
+                Point3D.of(-0.5, -0.5, 0.5),
+                Point3D.of(-0.5, -0.5, -0.5));
 
         checkPoints(Region.Location.INSIDE, polySet,
-                new Point3D(0, 0, 0),
-
-                new Point3D(0.4, 0.4, 0.4),
-                new Point3D(0.4, 0.4, -0.4),
-                new Point3D(0.4, -0.4, 0.4),
-                new Point3D(0.4, -0.4, -0.4),
-                new Point3D(-0.4, 0.4, 0.4),
-                new Point3D(-0.4, 0.4, -0.4),
-                new Point3D(-0.4, -0.4, 0.4),
-                new Point3D(-0.4, -0.4, -0.4));
+                Point3D.of(0, 0, 0),
+
+                Point3D.of(0.4, 0.4, 0.4),
+                Point3D.of(0.4, 0.4, -0.4),
+                Point3D.of(0.4, -0.4, 0.4),
+                Point3D.of(0.4, -0.4, -0.4),
+                Point3D.of(-0.4, 0.4, 0.4),
+                Point3D.of(-0.4, 0.4, -0.4),
+                Point3D.of(-0.4, -0.4, 0.4),
+                Point3D.of(-0.4, -0.4, -0.4));
     }
 
     @Test
@@ -226,7 +226,7 @@ public class PolyhedronsSetTest {
         // arrange
         List<SubHyperplane<Point3D>> boundaries = new ArrayList<>();
         boundaries.addAll(createBoxBoundaries(Point3D.ZERO, 1.0, TEST_TOLERANCE));
-        boundaries.addAll(createBoxBoundaries(new Point3D(2, 0, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(Point3D.of(2, 0, 0), 1.0, TEST_TOLERANCE));
 
         // act
         PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
@@ -235,26 +235,26 @@ public class PolyhedronsSetTest {
         Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
         Assert.assertEquals(2.0, polySet.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(12.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point3D(1, 0, 0), polySet.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point3D.of(1, 0, 0), polySet.getBarycenter(), TEST_TOLERANCE);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
         checkPoints(Region.Location.OUTSIDE, polySet,
-                new Point3D(-1, 0, 0),
-                new Point3D(1, 0, 0),
-                new Point3D(3, 0, 0));
+                Point3D.of(-1, 0, 0),
+                Point3D.of(1, 0, 0),
+                Point3D.of(3, 0, 0));
 
         checkPoints(Region.Location.INSIDE, polySet,
-                new Point3D(0, 0, 0),
-                new Point3D(2, 0, 0));
+                Point3D.of(0, 0, 0),
+                Point3D.of(2, 0, 0));
     }
 
     @Test
     public void testCreateFromBoundaries_twoBoxes_sharedSide() {
         // arrange
         List<SubHyperplane<Point3D>> boundaries = new ArrayList<>();
-        boundaries.addAll(createBoxBoundaries(new Point3D(0, 0, 0), 1.0, TEST_TOLERANCE));
-        boundaries.addAll(createBoxBoundaries(new Point3D(1, 0, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(Point3D.of(0, 0, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(Point3D.of(1, 0, 0), 1.0, TEST_TOLERANCE));
 
         // act
         PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
@@ -263,17 +263,17 @@ public class PolyhedronsSetTest {
         Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
         Assert.assertEquals(2.0, polySet.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(10.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point3D(0.5, 0, 0), polySet.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point3D.of(0.5, 0, 0), polySet.getBarycenter(), TEST_TOLERANCE);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
         checkPoints(Region.Location.OUTSIDE, polySet,
-                new Point3D(-1, 0, 0),
-                new Point3D(2, 0, 0));
+                Point3D.of(-1, 0, 0),
+                Point3D.of(2, 0, 0));
 
         checkPoints(Region.Location.INSIDE, polySet,
-                new Point3D(0, 0, 0),
-                new Point3D(1, 0, 0));
+                Point3D.of(0, 0, 0),
+                Point3D.of(1, 0, 0));
     }
 
     @Test
@@ -281,8 +281,8 @@ public class PolyhedronsSetTest {
         // arrange
         double tolerance = 1e-6;
         List<SubHyperplane<Point3D>> boundaries = new ArrayList<>();
-        boundaries.addAll(createBoxBoundaries(new Point3D(0, 0, 0), 1.0, tolerance));
-        boundaries.addAll(createBoxBoundaries(new Point3D(1 + 1e-7, 0, 0), 1.0, tolerance));
+        boundaries.addAll(createBoxBoundaries(Point3D.of(0, 0, 0), 1.0, tolerance));
+        boundaries.addAll(createBoxBoundaries(Point3D.of(1 + 1e-7, 0, 0), 1.0, tolerance));
 
         // act
         PolyhedronsSet polySet = new PolyhedronsSet(boundaries, tolerance);
@@ -291,25 +291,25 @@ public class PolyhedronsSetTest {
         Assert.assertEquals(tolerance, polySet.getTolerance(), Precision.EPSILON);
         Assert.assertEquals(2.0, polySet.getSize(), tolerance);
         Assert.assertEquals(10.0, polySet.getBoundarySize(), tolerance);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point3D(0.5 + 5e-8, 0, 0), polySet.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point3D.of(0.5 + 5e-8, 0, 0), polySet.getBarycenter(), TEST_TOLERANCE);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
         checkPoints(Region.Location.OUTSIDE, polySet,
-                new Point3D(-1, 0, 0),
-                new Point3D(2, 0, 0));
+                Point3D.of(-1, 0, 0),
+                Point3D.of(2, 0, 0));
 
         checkPoints(Region.Location.INSIDE, polySet,
-                new Point3D(0, 0, 0),
-                new Point3D(1, 0, 0));
+                Point3D.of(0, 0, 0),
+                Point3D.of(1, 0, 0));
     }
 
     @Test
     public void testCreateFromBoundaries_twoBoxes_sharedEdge() {
         // arrange
         List<SubHyperplane<Point3D>> boundaries = new ArrayList<>();
-        boundaries.addAll(createBoxBoundaries(new Point3D(0, 0, 0), 1.0, TEST_TOLERANCE));
-        boundaries.addAll(createBoxBoundaries(new Point3D(1, 1, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(Point3D.of(0, 0, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(Point3D.of(1, 1, 0), 1.0, TEST_TOLERANCE));
 
         // act
         PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
@@ -318,27 +318,27 @@ public class PolyhedronsSetTest {
         Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
         Assert.assertEquals(2.0, polySet.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(12.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point3D(0.5, 0.5, 0), polySet.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point3D.of(0.5, 0.5, 0), polySet.getBarycenter(), TEST_TOLERANCE);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
         checkPoints(Region.Location.OUTSIDE, polySet,
-                new Point3D(-1, 0, 0),
-                new Point3D(1, 0, 0),
-                new Point3D(0, 1, 0),
-                new Point3D(2, 1, 0));
+                Point3D.of(-1, 0, 0),
+                Point3D.of(1, 0, 0),
+                Point3D.of(0, 1, 0),
+                Point3D.of(2, 1, 0));
 
         checkPoints(Region.Location.INSIDE, polySet,
-                new Point3D(0, 0, 0),
-                new Point3D(1, 1, 0));
+                Point3D.of(0, 0, 0),
+                Point3D.of(1, 1, 0));
     }
 
     @Test
     public void testCreateFromBoundaries_twoBoxes_sharedPoint() {
         // arrange
         List<SubHyperplane<Point3D>> boundaries = new ArrayList<>();
-        boundaries.addAll(createBoxBoundaries(new Point3D(0, 0, 0), 1.0, TEST_TOLERANCE));
-        boundaries.addAll(createBoxBoundaries(new Point3D(1, 1, 1), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(Point3D.of(0, 0, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(Point3D.of(1, 1, 1), 1.0, TEST_TOLERANCE));
 
         // act
         PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
@@ -347,19 +347,19 @@ public class PolyhedronsSetTest {
         Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
         Assert.assertEquals(2.0, polySet.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(12.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point3D(0.5, 0.5, 0.5), polySet.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point3D.of(0.5, 0.5, 0.5), polySet.getBarycenter(), TEST_TOLERANCE);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
         checkPoints(Region.Location.OUTSIDE, polySet,
-                new Point3D(-1, 0, 0),
-                new Point3D(1, 0, 0),
-                new Point3D(0, 1, 1),
-                new Point3D(2, 1, 1));
+                Point3D.of(-1, 0, 0),
+                Point3D.of(1, 0, 0),
+                Point3D.of(0, 1, 1),
+                Point3D.of(2, 1, 1));
 
         checkPoints(Region.Location.INSIDE, polySet,
-                new Point3D(0, 0, 0),
-                new Point3D(1, 1, 1));
+                Point3D.of(0, 0, 0),
+                Point3D.of(1, 1, 1));
     }
 
     @Test
@@ -370,7 +370,7 @@ public class PolyhedronsSetTest {
         // assert
         Assert.assertEquals(1.0, tree.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(6.0, tree.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point3D(0.5, 0.5, 0.5), tree.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point3D.of(0.5, 0.5, 0.5), tree.getBarycenter(), TEST_TOLERANCE);
 
         for (double x = -0.25; x < 1.25; x += 0.1) {
             boolean xOK = (x >= 0.0) && (x <= 1.0);
@@ -380,25 +380,25 @@ public class PolyhedronsSetTest {
                     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 Point3D(x, y, z)));
+                    Assert.assertEquals(expected, tree.checkPoint(Point3D.of(x, y, z)));
                 }
             }
         }
         checkPoints(Region.Location.BOUNDARY, tree, new Point3D[] {
-            new Point3D(0.0, 0.5, 0.5),
-            new Point3D(1.0, 0.5, 0.5),
-            new Point3D(0.5, 0.0, 0.5),
-            new Point3D(0.5, 1.0, 0.5),
-            new Point3D(0.5, 0.5, 0.0),
-            new Point3D(0.5, 0.5, 1.0)
+            Point3D.of(0.0, 0.5, 0.5),
+            Point3D.of(1.0, 0.5, 0.5),
+            Point3D.of(0.5, 0.0, 0.5),
+            Point3D.of(0.5, 1.0, 0.5),
+            Point3D.of(0.5, 0.5, 0.0),
+            Point3D.of(0.5, 0.5, 1.0)
         });
         checkPoints(Region.Location.OUTSIDE, tree, new Point3D[] {
-            new Point3D(0.0, 1.2, 1.2),
-            new Point3D(1.0, 1.2, 1.2),
-            new Point3D(1.2, 0.0, 1.2),
-            new Point3D(1.2, 1.0, 1.2),
-            new Point3D(1.2, 1.2, 0.0),
-            new Point3D(1.2, 1.2, 1.0)
+            Point3D.of(0.0, 1.2, 1.2),
+            Point3D.of(1.0, 1.2, 1.2),
+            Point3D.of(1.2, 0.0, 1.2),
+            Point3D.of(1.2, 1.0, 1.2),
+            Point3D.of(1.2, 1.2, 0.0),
+            Point3D.of(1.2, 1.2, 1.0)
         });
     }
 
@@ -427,35 +427,35 @@ public class PolyhedronsSetTest {
                     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 Point3D(x, y, z)));
+                    Assert.assertEquals(expected, tree.checkPoint(Point3D.of(x, y, z)));
                 }
             }
         }
         checkPoints(Region.Location.BOUNDARY, tree, new Point3D[] {
-            new Point3D(0.0, 0.5, 0.5),
-            new Point3D(1.0, 0.5, 0.5),
-            new Point3D(0.5, 0.0, 0.5),
-            new Point3D(0.5, 1.0, 0.5),
-            new Point3D(0.5, 0.5, 0.0),
-            new Point3D(0.5, 0.5, 1.0)
+            Point3D.of(0.0, 0.5, 0.5),
+            Point3D.of(1.0, 0.5, 0.5),
+            Point3D.of(0.5, 0.0, 0.5),
+            Point3D.of(0.5, 1.0, 0.5),
+            Point3D.of(0.5, 0.5, 0.0),
+            Point3D.of(0.5, 0.5, 1.0)
         });
         checkPoints(Region.Location.INSIDE, tree, new Point3D[] {
-            new Point3D(0.0, 1.2, 1.2),
-            new Point3D(1.0, 1.2, 1.2),
-            new Point3D(1.2, 0.0, 1.2),
-            new Point3D(1.2, 1.0, 1.2),
-            new Point3D(1.2, 1.2, 0.0),
-            new Point3D(1.2, 1.2, 1.0)
+            Point3D.of(0.0, 1.2, 1.2),
+            Point3D.of(1.0, 1.2, 1.2),
+            Point3D.of(1.2, 0.0, 1.2),
+            Point3D.of(1.2, 1.0, 1.2),
+            Point3D.of(1.2, 1.2, 0.0),
+            Point3D.of(1.2, 1.2, 1.0)
         });
     }
 
     @Test
     public void testTetrahedron() {
         // arrange
-        Point3D vertex1 = new Point3D(1, 2, 3);
-        Point3D vertex2 = new Point3D(2, 2, 4);
-        Point3D vertex3 = new Point3D(2, 3, 3);
-        Point3D vertex4 = new Point3D(1, 3, 4);
+        Point3D vertex1 = Point3D.of(1, 2, 3);
+        Point3D vertex2 = Point3D.of(2, 2, 4);
+        Point3D vertex3 = Point3D.of(2, 3, 3);
+        Point3D vertex4 = Point3D.of(1, 3, 4);
 
         // act
         PolyhedronsSet tree =
@@ -468,7 +468,7 @@ public class PolyhedronsSetTest {
         // assert
         Assert.assertEquals(1.0 / 3.0, tree.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(2.0 * Math.sqrt(3.0), tree.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point3D(1.5, 2.5, 3.5), tree.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point3D.of(1.5, 2.5, 3.5), tree.getBarycenter(), TEST_TOLERANCE);
 
         double third = 1.0 / 3.0;
         checkPoints(Region.Location.BOUNDARY, tree, new Point3D[] {
@@ -479,10 +479,10 @@ public class PolyhedronsSetTest {
             Point3D.vectorCombination(third, vertex4, third, vertex1, third, vertex2)
         });
         checkPoints(Region.Location.OUTSIDE, tree, new Point3D[] {
-            new Point3D(1, 2, 4),
-            new Point3D(2, 2, 3),
-            new Point3D(2, 3, 4),
-            new Point3D(1, 3, 3)
+            Point3D.of(1, 2, 4),
+            Point3D.of(2, 2, 3),
+            Point3D.of(2, 3, 4),
+            Point3D.of(1, 3, 3)
         });
     }
 
@@ -494,42 +494,42 @@ public class PolyhedronsSetTest {
         double radius = 1.0;
 
         // act
-        PolyhedronsSet polySet = createSphere(new Point3D(1, 2, 3), radius, 8, 16);
+        PolyhedronsSet polySet = createSphere(Point3D.of(1, 2, 3), radius, 8, 16);
 
         // assert
         Assert.assertEquals(sphereVolume(radius), polySet.getSize(), approximationTolerance);
         Assert.assertEquals(sphereSurface(radius), polySet.getBoundarySize(), approximationTolerance);
-        EuclideanTestUtils.assertCoordinatesEqual(new Point3D(1, 2, 3), polySet.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point3D.of(1, 2, 3), polySet.getBarycenter(), TEST_TOLERANCE);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
         checkPoints(Region.Location.OUTSIDE, polySet,
-                new Point3D(-0.1, 2, 3),
-                new Point3D(2.1, 2, 3),
-                new Point3D(1, 0.9, 3),
-                new Point3D(1, 3.1, 3),
-                new Point3D(1, 2, 1.9),
-                new Point3D(1, 2, 4.1),
-                new Point3D(1.6, 2.6, 3.6));
+                Point3D.of(-0.1, 2, 3),
+                Point3D.of(2.1, 2, 3),
+                Point3D.of(1, 0.9, 3),
+                Point3D.of(1, 3.1, 3),
+                Point3D.of(1, 2, 1.9),
+                Point3D.of(1, 2, 4.1),
+                Point3D.of(1.6, 2.6, 3.6));
 
         checkPoints(Region.Location.INSIDE, polySet,
-                new Point3D(1, 2, 3),
-                new Point3D(0.1, 2, 3),
-                new Point3D(1.9, 2, 3),
-                new Point3D(1, 2.1, 3),
-                new Point3D(1, 2.9, 3),
-                new Point3D(1, 2, 2.1),
-                new Point3D(1, 2, 3.9),
-                new Point3D(1.5, 2.5, 3.5));
+                Point3D.of(1, 2, 3),
+                Point3D.of(0.1, 2, 3),
+                Point3D.of(1.9, 2, 3),
+                Point3D.of(1, 2.1, 3),
+                Point3D.of(1, 2.9, 3),
+                Point3D.of(1, 2, 2.1),
+                Point3D.of(1, 2, 3.9),
+                Point3D.of(1.5, 2.5, 3.5));
     }
 
     @Test
     public void testIsometry() {
         // arrange
-        Point3D vertex1 = new Point3D(1.1, 2.2, 3.3);
-        Point3D vertex2 = new Point3D(2.0, 2.4, 4.2);
-        Point3D vertex3 = new Point3D(2.8, 3.3, 3.7);
-        Point3D vertex4 = new Point3D(1.0, 3.6, 4.5);
+        Point3D vertex1 = Point3D.of(1.1, 2.2, 3.3);
+        Point3D vertex2 = Point3D.of(2.0, 2.4, 4.2);
+        Point3D vertex3 = Point3D.of(2.8, 3.3, 3.7);
+        Point3D vertex4 = Point3D.of(1.0, 3.6, 4.5);
 
         // act
         PolyhedronsSet tree =
@@ -541,9 +541,9 @@ public class PolyhedronsSetTest {
 
         // assert
         Point3D barycenter = tree.getBarycenter();
-        Vector3D s = new Vector3D(10.2, 4.3, -6.7);
-        Point3D c = new Point3D(-0.2, 2.1, -3.2);
-        Rotation r = new Rotation(new Vector3D(6.2, -4.4, 2.1), 0.12, RotationConvention.VECTOR_OPERATOR);
+        Vector3D s = Vector3D.of(10.2, 4.3, -6.7);
+        Point3D c = Point3D.of(-0.2, 2.1, -3.2);
+        Rotation r = new Rotation(Vector3D.of(6.2, -4.4, 2.1), 0.12, RotationConvention.VECTOR_OPERATOR);
 
         tree = tree.rotate(c, r).translate(s);
 
@@ -626,7 +626,7 @@ public class PolyhedronsSetTest {
             new PolyhedronsSet(x - l, x + l, y - w, y + w, z - w, z + w, TEST_TOLERANCE);
 
         // assert
-        EuclideanTestUtils.assertCoordinatesEqual(new Point3D(x, y, z), tree.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point3D.of(x, y, z), tree.getBarycenter(), TEST_TOLERANCE);
         Assert.assertEquals(8 * l * w * w, tree.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(8 * w * (2 * l + w), tree.getBoundarySize(), TEST_TOLERANCE);
     }
@@ -651,7 +651,7 @@ public class PolyhedronsSetTest {
         PolyhedronsSet tree = (PolyhedronsSet) factory.union(xBeam, factory.union(yBeam, zBeam));
 
         // assert
-        EuclideanTestUtils.assertCoordinatesEqual(new Point3D(x, y, z), tree.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point3D.of(x, y, z), tree.getBarycenter(), TEST_TOLERANCE);
         Assert.assertEquals(8 * w * w * (3 * l - 2 * w), tree.getSize(), TEST_TOLERANCE);
         Assert.assertEquals(24 * w * (2 * l - w), tree.getBoundarySize(), TEST_TOLERANCE);
     }
@@ -682,9 +682,9 @@ public class PolyhedronsSetTest {
             int idxA = indices[idx] * 3;
             int idxB = indices[idx + 1] * 3;
             int idxC = indices[idx + 2] * 3;
-            Point3D v_1 = new Point3D(coords[idxA], coords[idxA + 1], coords[idxA + 2]);
-            Point3D v_2 = new Point3D(coords[idxB], coords[idxB + 1], coords[idxB + 2]);
-            Point3D v_3 = new Point3D(coords[idxC], coords[idxC + 1], coords[idxC + 2]);
+            Point3D v_1 = Point3D.of(coords[idxA], coords[idxA + 1], coords[idxA + 2]);
+            Point3D v_2 = Point3D.of(coords[idxB], coords[idxB + 1], coords[idxB + 2]);
+            Point3D v_3 = Point3D.of(coords[idxC], coords[idxC + 1], coords[idxC + 2]);
             Point3D[] vertices = {v_1, v_2, v_3};
             Plane polyPlane = new Plane(v_1, v_2, v_3, TEST_TOLERANCE);
             ArrayList<SubHyperplane<Point2D>> lines = new ArrayList<>();
@@ -745,14 +745,14 @@ public class PolyhedronsSetTest {
         double xmin=-1,xmax=1;
         double ymin=-1,ymax=1;
         double zmin=-1,zmax=1;
-        verts[0]=new Point3D(xmin,ymin,zmin);
-        verts[1]=new Point3D(xmax,ymin,zmin);
-        verts[2]=new Point3D(xmax,ymax,zmin);
-        verts[3]=new Point3D(xmin,ymax,zmin);
-        verts[4]=new Point3D(xmin,ymin,zmax);
-        verts[5]=new Point3D(xmax,ymin,zmax);
-        verts[6]=new Point3D(xmax,ymax,zmax);
-        verts[7]=new Point3D(xmin,ymax,zmax);
+        verts[0]=Point3D.of(xmin,ymin,zmin);
+        verts[1]=Point3D.of(xmax,ymin,zmin);
+        verts[2]=Point3D.of(xmax,ymax,zmin);
+        verts[3]=Point3D.of(xmin,ymax,zmin);
+        verts[4]=Point3D.of(xmin,ymin,zmax);
+        verts[5]=Point3D.of(xmax,ymin,zmax);
+        verts[6]=Point3D.of(xmax,ymax,zmax);
+        verts[7]=Point3D.of(xmin,ymax,zmax);
         //
         int[][] faces=new int[12][];
         faces[0]=new int[]{3,1,0};  // bottom (-z)
@@ -815,7 +815,7 @@ public class PolyhedronsSetTest {
 
     @Test
     public void testCreateFromBRep_wrongNumberOfPoints() throws IOException, ParseException {
-        checkError(Arrays.asList(Point3D.ZERO, new Point3D(1, 0, 0), new Point3D(0, 1, 0), new Point3D(0, 0, 1)),
+        checkError(Arrays.asList(Point3D.ZERO, Point3D.of(1, 0, 0), Point3D.of(0, 1, 0), Point3D.of(0, 0, 1)),
                    Arrays.asList(new int[] { 0, 1, 2 }, new int[] {2, 3}),
                    "");
     }
@@ -849,45 +849,45 @@ public class PolyhedronsSetTest {
         List<SubHyperplane<Point3D>> boundaries = createBoxBoundaries(Point3D.ZERO, 2.0, TEST_TOLERANCE);
         PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
 
-        Line xPlus = new Line(Point3D.ZERO, new Point3D(1, 0, 0), TEST_TOLERANCE);
-        Line xMinus = new Line(Point3D.ZERO, new Point3D(-1, 0, 0), TEST_TOLERANCE);
+        Line xPlus = new Line(Point3D.ZERO, Point3D.of(1, 0, 0), TEST_TOLERANCE);
+        Line xMinus = new Line(Point3D.ZERO, Point3D.of(-1, 0, 0), TEST_TOLERANCE);
 
-        Line yPlus = new Line(Point3D.ZERO, new Point3D(0, 1, 0), TEST_TOLERANCE);
-        Line yMinus = new Line(Point3D.ZERO, new Point3D(0, -1, 0), TEST_TOLERANCE);
+        Line yPlus = new Line(Point3D.ZERO, Point3D.of(0, 1, 0), TEST_TOLERANCE);
+        Line yMinus = new Line(Point3D.ZERO, Point3D.of(0, -1, 0), TEST_TOLERANCE);
 
-        Line zPlus = new Line(Point3D.ZERO, new Point3D(0, 0, 1), TEST_TOLERANCE);
-        Line zMinus = new Line(Point3D.ZERO, new Point3D(0, 0, -1), TEST_TOLERANCE);
+        Line zPlus = new Line(Point3D.ZERO, Point3D.of(0, 0, 1), TEST_TOLERANCE);
+        Line zMinus = new Line(Point3D.ZERO, Point3D.of(0, 0, -1), TEST_TOLERANCE);
 
         // act/assert
-        assertSubPlaneNormal(new Vector3D(-1, 0, 0), polySet.firstIntersection(new Point3D(-1.1, 0, 0), xPlus));
-        assertSubPlaneNormal(new Vector3D(-1, 0, 0), polySet.firstIntersection(new Point3D(-1, 0, 0), xPlus));
-        assertSubPlaneNormal(new Vector3D(1, 0, 0), polySet.firstIntersection(new Point3D(-0.9, 0, 0), xPlus));
-        Assert.assertEquals(null, polySet.firstIntersection(new Point3D(1.1, 0, 0), xPlus));
-
-        assertSubPlaneNormal(new Vector3D(1, 0, 0), polySet.firstIntersection(new Point3D(1.1, 0, 0), xMinus));
-        assertSubPlaneNormal(new Vector3D(1, 0, 0), polySet.firstIntersection(new Point3D(1, 0, 0), xMinus));
-        assertSubPlaneNormal(new Vector3D(-1, 0, 0), polySet.firstIntersection(new Point3D(0.9, 0, 0), xMinus));
-        Assert.assertEquals(null, polySet.firstIntersection(new Point3D(-1.1, 0, 0), xMinus));
-
-        assertSubPlaneNormal(new Vector3D(0, -1, 0), polySet.firstIntersection(new Point3D(0, -1.1, 0), yPlus));
-        assertSubPlaneNormal(new Vector3D(0, -1, 0), polySet.firstIntersection(new Point3D(0, -1, 0), yPlus));
-        assertSubPlaneNormal(new Vector3D(0, 1, 0), polySet.firstIntersection(new Point3D(0, -0.9, 0), yPlus));
-        Assert.assertEquals(null, polySet.firstIntersection(new Point3D(0, 1.1, 0), yPlus));
-
-        assertSubPlaneNormal(new Vector3D(0, 1, 0), polySet.firstIntersection(new Point3D(0, 1.1, 0), yMinus));
-        assertSubPlaneNormal(new Vector3D(0, 1, 0), polySet.firstIntersection(new Point3D(0, 1, 0), yMinus));
-        assertSubPlaneNormal(new Vector3D(0, -1, 0), polySet.firstIntersection(new Point3D(0, 0.9, 0), yMinus));
-        Assert.assertEquals(null, polySet.firstIntersection(new Point3D(0, -1.1, 0), yMinus));
-
-        assertSubPlaneNormal(new Vector3D(0, 0, -1), polySet.firstIntersection(new Point3D(0, 0, -1.1), zPlus));
-        assertSubPlaneNormal(new Vector3D(0, 0, -1), polySet.firstIntersection(new Point3D(0, 0, -1), zPlus));
-        assertSubPlaneNormal(new Vector3D(0, 0, 1), polySet.firstIntersection(new Point3D(0, 0, -0.9), zPlus));
-        Assert.assertEquals(null, polySet.firstIntersection(new Point3D(0, 0, 1.1), zPlus));
-
-        assertSubPlaneNormal(new Vector3D(0, 0, 1), polySet.firstIntersection(new Point3D(0, 0, 1.1), zMinus));
-        assertSubPlaneNormal(new Vector3D(0, 0, 1), polySet.firstIntersection(new Point3D(0, 0, 1), zMinus));
-        assertSubPlaneNormal(new Vector3D(0, 0, -1), polySet.firstIntersection(new Point3D(0, 0, 0.9), zMinus));
-        Assert.assertEquals(null, polySet.firstIntersection(new Point3D(0, 0, -1.1), zMinus));
+        assertSubPlaneNormal(Vector3D.of(-1, 0, 0), polySet.firstIntersection(Point3D.of(-1.1, 0, 0), xPlus));
+        assertSubPlaneNormal(Vector3D.of(-1, 0, 0), polySet.firstIntersection(Point3D.of(-1, 0, 0), xPlus));
+        assertSubPlaneNormal(Vector3D.of(1, 0, 0), polySet.firstIntersection(Point3D.of(-0.9, 0, 0), xPlus));
+        Assert.assertEquals(null, polySet.firstIntersection(Point3D.of(1.1, 0, 0), xPlus));
+
+        assertSubPlaneNormal(Vector3D.of(1, 0, 0), polySet.firstIntersection(Point3D.of(1.1, 0, 0), xMinus));
+        assertSubPlaneNormal(Vector3D.of(1, 0, 0), polySet.firstIntersection(Point3D.of(1, 0, 0), xMinus));
+        assertSubPlaneNormal(Vector3D.of(-1, 0, 0), polySet.firstIntersection(Point3D.of(0.9, 0, 0), xMinus));
+        Assert.assertEquals(null, polySet.firstIntersection(Point3D.of(-1.1, 0, 0), xMinus));
+
+        assertSubPlaneNormal(Vector3D.of(0, -1, 0), polySet.firstIntersection(Point3D.of(0, -1.1, 0), yPlus));
+        assertSubPlaneNormal(Vector3D.of(0, -1, 0), polySet.firstIntersection(Point3D.of(0, -1, 0), yPlus));
+        assertSubPlaneNormal(Vector3D.of(0, 1, 0), polySet.firstIntersection(Point3D.of(0, -0.9, 0), yPlus));
+        Assert.assertEquals(null, polySet.firstIntersection(Point3D.of(0, 1.1, 0), yPlus));
+
+        assertSubPlaneNormal(Vector3D.of(0, 1, 0), polySet.firstIntersection(Point3D.of(0, 1.1, 0), yMinus));
+        assertSubPlaneNormal(Vector3D.of(0, 1, 0), polySet.firstIntersection(Point3D.of(0, 1, 0), yMinus));
+        assertSubPlaneNormal(Vector3D.of(0, -1, 0), polySet.firstIntersection(Point3D.of(0, 0.9, 0), yMinus));
+        Assert.assertEquals(null, polySet.firstIntersection(Point3D.of(0, -1.1, 0), yMinus));
+
+        assertSubPlaneNormal(Vector3D.of(0, 0, -1), polySet.firstIntersection(Point3D.of(0, 0, -1.1), zPlus));
+        assertSubPlaneNormal(Vector3D.of(0, 0, -1), polySet.firstIntersection(Point3D.of(0, 0, -1), zPlus));
+        assertSubPlaneNormal(Vector3D.of(0, 0, 1), polySet.firstIntersection(Point3D.of(0, 0, -0.9), zPlus));
+        Assert.assertEquals(null, polySet.firstIntersection(Point3D.of(0, 0, 1.1), zPlus));
+
+        assertSubPlaneNormal(Vector3D.of(0, 0, 1), polySet.firstIntersection(Point3D.of(0, 0, 1.1), zMinus));
+        assertSubPlaneNormal(Vector3D.of(0, 0, 1), polySet.firstIntersection(Point3D.of(0, 0, 1), zMinus));
+        assertSubPlaneNormal(Vector3D.of(0, 0, -1), polySet.firstIntersection(Point3D.of(0, 0, 0.9), zMinus));
+        Assert.assertEquals(null, polySet.firstIntersection(Point3D.of(0, 0, -1.1), zMinus));
     }
 
     // Issue 1211
@@ -902,7 +902,7 @@ public class PolyhedronsSetTest {
         int nrays = 1000;
         for (int i = 0; i < nrays; i++) {
             Point3D origin    = Point3D.ZERO;
-            Vector3D direction = new Vector3D(2 * random.nextDouble() - 1,
+            Vector3D direction = Vector3D.of(2 * random.nextDouble() - 1,
                                               2 * random.nextDouble() - 1,
                                               2 * random.nextDouble() - 1).normalize();
             Line line = new Line(origin, origin.add(direction), polyset.getTolerance());
@@ -922,7 +922,7 @@ public class PolyhedronsSetTest {
         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 Point3D(size * 0.5, size * 0.5, size), radius, 8, 16);
+        PolyhedronsSet sphere = createSphere(Point3D.of(size * 0.5, size * 0.5, size), radius, 8, 16);
 
         // act
         PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Point3D>().union(box, sphere);
@@ -938,20 +938,20 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(result.isFull());
 
         checkPoints(Region.Location.OUTSIDE, result,
-                new Point3D(-0.1, 0.5, 0.5),
-                new Point3D(1.1, 0.5, 0.5),
-                new Point3D(0.5, -0.1, 0.5),
-                new Point3D(0.5, 1.1, 0.5),
-                new Point3D(0.5, 0.5, -0.1),
-                new Point3D(0.5, 0.5, 1.6));
+                Point3D.of(-0.1, 0.5, 0.5),
+                Point3D.of(1.1, 0.5, 0.5),
+                Point3D.of(0.5, -0.1, 0.5),
+                Point3D.of(0.5, 1.1, 0.5),
+                Point3D.of(0.5, 0.5, -0.1),
+                Point3D.of(0.5, 0.5, 1.6));
 
         checkPoints(Region.Location.INSIDE, result,
-                new Point3D(0.1, 0.5, 0.5),
-                new Point3D(0.9, 0.5, 0.5),
-                new Point3D(0.5, 0.1, 0.5),
-                new Point3D(0.5, 0.9, 0.5),
-                new Point3D(0.5, 0.5, 0.1),
-                new Point3D(0.5, 0.5, 1.4));
+                Point3D.of(0.1, 0.5, 0.5),
+                Point3D.of(0.9, 0.5, 0.5),
+                Point3D.of(0.5, 0.1, 0.5),
+                Point3D.of(0.5, 0.9, 0.5),
+                Point3D.of(0.5, 0.5, 0.1),
+                Point3D.of(0.5, 0.5, 1.4));
     }
 
     @Test
@@ -973,20 +973,20 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(result.isFull());
 
         checkPoints(Region.Location.OUTSIDE, result,
-                new Point3D(-1.1, 0, 0),
-                new Point3D(1.1, 0, 0),
-                new Point3D(0, -1.1, 0),
-                new Point3D(0, 1.1, 0),
-                new Point3D(0, 0, -1.1),
-                new Point3D(0, 0, 1.1));
+                Point3D.of(-1.1, 0, 0),
+                Point3D.of(1.1, 0, 0),
+                Point3D.of(0, -1.1, 0),
+                Point3D.of(0, 1.1, 0),
+                Point3D.of(0, 0, -1.1),
+                Point3D.of(0, 0, 1.1));
 
         checkPoints(Region.Location.INSIDE, result,
-                new Point3D(-0.9, 0, 0),
-                new Point3D(0.9, 0, 0),
-                new Point3D(0, -0.9, 0),
-                new Point3D(0, 0.9, 0),
-                new Point3D(0, 0, -0.9),
-                new Point3D(0, 0, 0.9),
+                Point3D.of(-0.9, 0, 0),
+                Point3D.of(0.9, 0, 0),
+                Point3D.of(0, -0.9, 0),
+                Point3D.of(0, 0.9, 0),
+                Point3D.of(0, 0, -0.9),
+                Point3D.of(0, 0, 0.9),
                 Point3D.ZERO);
     }
 
@@ -997,7 +997,7 @@ public class PolyhedronsSetTest {
         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 Point3D(size * 0.5, size * 0.5, size), radius, 8, 16);
+        PolyhedronsSet sphere = createSphere(Point3D.of(size * 0.5, size * 0.5, size), radius, 8, 16);
 
         // act
         PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Point3D>().intersection(box, sphere);
@@ -1012,20 +1012,20 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(result.isFull());
 
         checkPoints(Region.Location.OUTSIDE, result,
-                new Point3D(-0.1, 0.5, 1.0),
-                new Point3D(1.1, 0.5, 1.0),
-                new Point3D(0.5, -0.1, 1.0),
-                new Point3D(0.5, 1.1, 1.0),
-                new Point3D(0.5, 0.5, 0.4),
-                new Point3D(0.5, 0.5, 1.1));
+                Point3D.of(-0.1, 0.5, 1.0),
+                Point3D.of(1.1, 0.5, 1.0),
+                Point3D.of(0.5, -0.1, 1.0),
+                Point3D.of(0.5, 1.1, 1.0),
+                Point3D.of(0.5, 0.5, 0.4),
+                Point3D.of(0.5, 0.5, 1.1));
 
         checkPoints(Region.Location.INSIDE, result,
-                new Point3D(0.1, 0.5, 0.9),
-                new Point3D(0.9, 0.5, 0.9),
-                new Point3D(0.5, 0.1, 0.9),
-                new Point3D(0.5, 0.9, 0.9),
-                new Point3D(0.5, 0.5, 0.6),
-                new Point3D(0.5, 0.5, 0.9));
+                Point3D.of(0.1, 0.5, 0.9),
+                Point3D.of(0.9, 0.5, 0.9),
+                Point3D.of(0.5, 0.1, 0.9),
+                Point3D.of(0.5, 0.9, 0.9),
+                Point3D.of(0.5, 0.5, 0.6),
+                Point3D.of(0.5, 0.5, 0.9));
     }
 
     @Test
@@ -1047,20 +1047,20 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(result.isFull());
 
         checkPoints(Region.Location.OUTSIDE, result,
-                new Point3D(-1.1, 0, 0),
-                new Point3D(1.1, 0, 0),
-                new Point3D(0, -1.1, 0),
-                new Point3D(0, 1.1, 0),
-                new Point3D(0, 0, -1.1),
-                new Point3D(0, 0, 1.1));
+                Point3D.of(-1.1, 0, 0),
+                Point3D.of(1.1, 0, 0),
+                Point3D.of(0, -1.1, 0),
+                Point3D.of(0, 1.1, 0),
+                Point3D.of(0, 0, -1.1),
+                Point3D.of(0, 0, 1.1));
 
         checkPoints(Region.Location.INSIDE, result,
-                new Point3D(-0.9, 0, 0),
-                new Point3D(0.9, 0, 0),
-                new Point3D(0, -0.9, 0),
-                new Point3D(0, 0.9, 0),
-                new Point3D(0, 0, -0.9),
-                new Point3D(0, 0, 0.9),
+                Point3D.of(-0.9, 0, 0),
+                Point3D.of(0.9, 0, 0),
+                Point3D.of(0, -0.9, 0),
+                Point3D.of(0, 0.9, 0),
+                Point3D.of(0, 0, -0.9),
+                Point3D.of(0, 0, 0.9),
                 Point3D.ZERO);
     }
 
@@ -1090,21 +1090,21 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(result.isFull());
 
         checkPoints(Region.Location.OUTSIDE, result,
-                new Point3D(-0.1, -0.1, -0.1),
-                new Point3D(0.75, 0.75, 0.75),
-                new Point3D(1.6, 1.6, 1.6));
+                Point3D.of(-0.1, -0.1, -0.1),
+                Point3D.of(0.75, 0.75, 0.75),
+                Point3D.of(1.6, 1.6, 1.6));
 
         checkPoints(Region.Location.BOUNDARY, result,
-                new Point3D(0, 0, 0),
-                new Point3D(0.5, 0.5, 0.5),
-                new Point3D(1, 1, 1),
-                new Point3D(1.5, 1.5, 1.5));
+                Point3D.of(0, 0, 0),
+                Point3D.of(0.5, 0.5, 0.5),
+                Point3D.of(1, 1, 1),
+                Point3D.of(1.5, 1.5, 1.5));
 
         checkPoints(Region.Location.INSIDE, result,
-                new Point3D(0.1, 0.1, 0.1),
-                new Point3D(0.4, 0.4, 0.4),
-                new Point3D(1.1, 1.1, 1.1),
-                new Point3D(1.4, 1.4, 1.4));
+                Point3D.of(0.1, 0.1, 0.1),
+                Point3D.of(0.4, 0.4, 0.4),
+                Point3D.of(1.1, 1.1, 1.1),
+                Point3D.of(1.4, 1.4, 1.4));
     }
 
     @Test
@@ -1114,7 +1114,7 @@ public class PolyhedronsSetTest {
         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 Point3D(size * 0.5, size * 0.5, size), radius, 8, 16);
+        PolyhedronsSet sphere = createSphere(Point3D.of(size * 0.5, size * 0.5, size), radius, 8, 16);
 
         // act
         PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Point3D>().xor(box, sphere);
@@ -1130,21 +1130,21 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(result.isFull());
 
         checkPoints(Region.Location.OUTSIDE, result,
-                new Point3D(-0.1, 0.5, 0.5),
-                new Point3D(1.1, 0.5, 0.5),
-                new Point3D(0.5, -0.1, 0.5),
-                new Point3D(0.5, 1.1, 0.5),
-                new Point3D(0.5, 0.5, -0.1),
-                new Point3D(0.5, 0.5, 1.6),
-                new Point3D(0.5, 0.5, 0.9));
+                Point3D.of(-0.1, 0.5, 0.5),
+                Point3D.of(1.1, 0.5, 0.5),
+                Point3D.of(0.5, -0.1, 0.5),
+                Point3D.of(0.5, 1.1, 0.5),
+                Point3D.of(0.5, 0.5, -0.1),
+                Point3D.of(0.5, 0.5, 1.6),
+                Point3D.of(0.5, 0.5, 0.9));
 
         checkPoints(Region.Location.INSIDE, result,
-                new Point3D(0.1, 0.5, 0.5),
-                new Point3D(0.9, 0.5, 0.5),
-                new Point3D(0.5, 0.1, 0.5),
-                new Point3D(0.5, 0.9, 0.5),
-                new Point3D(0.5, 0.5, 0.1),
-                new Point3D(0.5, 0.5, 1.4));
+                Point3D.of(0.1, 0.5, 0.5),
+                Point3D.of(0.9, 0.5, 0.5),
+                Point3D.of(0.5, 0.1, 0.5),
+                Point3D.of(0.5, 0.9, 0.5),
+                Point3D.of(0.5, 0.5, 0.1),
+                Point3D.of(0.5, 0.5, 1.4));
     }
 
     @Test
@@ -1165,18 +1165,18 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(result.isFull());
 
         checkPoints(Region.Location.OUTSIDE, result,
-                new Point3D(-1.1, 0, 0),
-                new Point3D(1.1, 0, 0),
-                new Point3D(0, -1.1, 0),
-                new Point3D(0, 1.1, 0),
-                new Point3D(0, 0, -1.1),
-                new Point3D(0, 0, 1.1),
-                new Point3D(-0.9, 0, 0),
-                new Point3D(0.9, 0, 0),
-                new Point3D(0, -0.9, 0),
-                new Point3D(0, 0.9, 0),
-                new Point3D(0, 0, -0.9),
-                new Point3D(0, 0, 0.9),
+                Point3D.of(-1.1, 0, 0),
+                Point3D.of(1.1, 0, 0),
+                Point3D.of(0, -1.1, 0),
+                Point3D.of(0, 1.1, 0),
+                Point3D.of(0, 0, -1.1),
+                Point3D.of(0, 0, 1.1),
+                Point3D.of(-0.9, 0, 0),
+                Point3D.of(0.9, 0, 0),
+                Point3D.of(0, -0.9, 0),
+                Point3D.of(0, 0.9, 0),
+                Point3D.of(0, 0, -0.9),
+                Point3D.of(0, 0, 0.9),
                 Point3D.ZERO);
     }
 
@@ -1187,7 +1187,7 @@ public class PolyhedronsSetTest {
         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 Point3D(size * 0.5, size * 0.5, size), radius, 8, 16);
+        PolyhedronsSet sphere = createSphere(Point3D.of(size * 0.5, size * 0.5, size), radius, 8, 16);
 
         // act
         PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Point3D>().difference(box, sphere);
@@ -1202,20 +1202,20 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(result.isFull());
 
         checkPoints(Region.Location.OUTSIDE, result,
-                new Point3D(-0.1, 0.5, 1.0),
-                new Point3D(1.1, 0.5, 1.0),
-                new Point3D(0.5, -0.1, 1.0),
-                new Point3D(0.5, 1.1, 1.0),
-                new Point3D(0.5, 0.5, -0.1),
-                new Point3D(0.5, 0.5, 0.6));
+                Point3D.of(-0.1, 0.5, 1.0),
+                Point3D.of(1.1, 0.5, 1.0),
+                Point3D.of(0.5, -0.1, 1.0),
+                Point3D.of(0.5, 1.1, 1.0),
+                Point3D.of(0.5, 0.5, -0.1),
+                Point3D.of(0.5, 0.5, 0.6));
 
         checkPoints(Region.Location.INSIDE, result,
-                new Point3D(0.1, 0.5, 0.4),
-                new Point3D(0.9, 0.5, 0.4),
-                new Point3D(0.5, 0.1, 0.4),
-                new Point3D(0.5, 0.9, 0.4),
-                new Point3D(0.5, 0.5, 0.1),
-                new Point3D(0.5, 0.5, 0.4));
+                Point3D.of(0.1, 0.5, 0.4),
+                Point3D.of(0.9, 0.5, 0.4),
+                Point3D.of(0.5, 0.1, 0.4),
+                Point3D.of(0.5, 0.9, 0.4),
+                Point3D.of(0.5, 0.5, 0.1),
+                Point3D.of(0.5, 0.5, 0.4));
     }
 
     @Test
@@ -1236,18 +1236,18 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(result.isFull());
 
         checkPoints(Region.Location.OUTSIDE, result,
-                new Point3D(-1.1, 0, 0),
-                new Point3D(1.1, 0, 0),
-                new Point3D(0, -1.1, 0),
-                new Point3D(0, 1.1, 0),
-                new Point3D(0, 0, -1.1),
-                new Point3D(0, 0, 1.1),
-                new Point3D(-0.9, 0, 0),
-                new Point3D(0.9, 0, 0),
-                new Point3D(0, -0.9, 0),
-                new Point3D(0, 0.9, 0),
-                new Point3D(0, 0, -0.9),
-                new Point3D(0, 0, 0.9),
+                Point3D.of(-1.1, 0, 0),
+                Point3D.of(1.1, 0, 0),
+                Point3D.of(0, -1.1, 0),
+                Point3D.of(0, 1.1, 0),
+                Point3D.of(0, 0, -1.1),
+                Point3D.of(0, 0, 1.1),
+                Point3D.of(-0.9, 0, 0),
+                Point3D.of(0.9, 0, 0),
+                Point3D.of(0, -0.9, 0),
+                Point3D.of(0, 0.9, 0),
+                Point3D.of(0, 0, -0.9),
+                Point3D.of(0, 0, 0.9),
                 Point3D.ZERO);
     }
 
@@ -1258,9 +1258,9 @@ public class PolyhedronsSetTest {
         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 Point3D(size * 0.5, size * 0.5, size), radius, 8, 16);
-        PolyhedronsSet sphereToRemove1 = createSphere(new Point3D(size * 0.5, 0, size * 0.5), radius, 8, 16);
-        PolyhedronsSet sphereToRemove2 = createSphere(new Point3D(size * 0.5, 1, size * 0.5), radius, 8, 16);
+        PolyhedronsSet sphereToAdd = createSphere(Point3D.of(size * 0.5, size * 0.5, size), radius, 8, 16);
+        PolyhedronsSet sphereToRemove1 = createSphere(Point3D.of(size * 0.5, 0, size * 0.5), radius, 8, 16);
+        PolyhedronsSet sphereToRemove2 = createSphere(Point3D.of(size * 0.5, 1, size * 0.5), radius, 8, 16);
 
         RegionFactory<Point3D> factory = new RegionFactory<Point3D>();
 
@@ -1280,20 +1280,20 @@ public class PolyhedronsSetTest {
         Assert.assertFalse(result.isFull());
 
         checkPoints(Region.Location.OUTSIDE, result,
-                new Point3D(-0.1, 0.5, 0.5),
-                new Point3D(1.1, 0.5, 0.5),
-                new Point3D(0.5, 0.4, 0.5),
-                new Point3D(0.5, 0.6, 0.5),
-                new Point3D(0.5, 0.5, -0.1),
-                new Point3D(0.5, 0.5, 1.6));
+                Point3D.of(-0.1, 0.5, 0.5),
+                Point3D.of(1.1, 0.5, 0.5),
+                Point3D.of(0.5, 0.4, 0.5),
+                Point3D.of(0.5, 0.6, 0.5),
+                Point3D.of(0.5, 0.5, -0.1),
+                Point3D.of(0.5, 0.5, 1.6));
 
         checkPoints(Region.Location.INSIDE, result,
-                new Point3D(0.1, 0.5, 0.1),
-                new Point3D(0.9, 0.5, 0.1),
-                new Point3D(0.5, 0.4, 0.1),
-                new Point3D(0.5, 0.6, 0.1),
-                new Point3D(0.5, 0.5, 0.1),
-                new Point3D(0.5, 0.5, 1.4));
+                Point3D.of(0.1, 0.5, 0.1),
+                Point3D.of(0.9, 0.5, 0.1),
+                Point3D.of(0.5, 0.4, 0.1),
+                Point3D.of(0.5, 0.6, 0.1),
+                Point3D.of(0.5, 0.5, 0.1),
+                Point3D.of(0.5, 0.5, 1.4));
     }
 
     @Test
@@ -1302,12 +1302,12 @@ public class PolyhedronsSetTest {
         PolyhedronsSet polySet = new PolyhedronsSet(0, 1, 0, 1, 0, 1, TEST_TOLERANCE);
 
         // act/assert
-        checkProjectToBoundary(polySet, new Point3D(0.4, 0.5, 0.5),
-                new Point3D(0, 0.5, 0.5), -0.4);
-        checkProjectToBoundary(polySet, new Point3D(1.5, 0.5, 0.5),
-                new Point3D(1, 0.5, 0.5), 0.5);
-        checkProjectToBoundary(polySet, new Point3D(2, 2, 2),
-                new Point3D(1, 1, 1), Math.sqrt(3));
+        checkProjectToBoundary(polySet, Point3D.of(0.4, 0.5, 0.5),
+                Point3D.of(0, 0.5, 0.5), -0.4);
+        checkProjectToBoundary(polySet, Point3D.of(1.5, 0.5, 0.5),
+                Point3D.of(1, 0.5, 0.5), 0.5);
+        checkProjectToBoundary(polySet, Point3D.of(2, 2, 2),
+                Point3D.of(1, 1, 1), Math.sqrt(3));
     }
 
     @Test
@@ -1317,12 +1317,12 @@ public class PolyhedronsSetTest {
         polySet = (PolyhedronsSet) new RegionFactory<Point3D>().getComplement(polySet);
 
         // act/assert
-        checkProjectToBoundary(polySet, new Point3D(0.4, 0.5, 0.5),
-                new Point3D(0, 0.5, 0.5), 0.4);
-        checkProjectToBoundary(polySet, new Point3D(1.5, 0.5, 0.5),
-                new Point3D(1, 0.5, 0.5), -0.5);
-        checkProjectToBoundary(polySet, new Point3D(2, 2, 2),
-                new Point3D(1, 1, 1), -Math.sqrt(3));
+        checkProjectToBoundary(polySet, Point3D.of(0.4, 0.5, 0.5),
+                Point3D.of(0, 0.5, 0.5), 0.4);
+        checkProjectToBoundary(polySet, Point3D.of(1.5, 0.5, 0.5),
+                Point3D.of(1, 0.5, 0.5), -0.5);
+        checkProjectToBoundary(polySet, Point3D.of(2, 2, 2),
+                Point3D.of(1, 1, 1), -Math.sqrt(3));
     }
 
     private void checkProjectToBoundary(PolyhedronsSet poly, Point3D toProject,
@@ -1356,54 +1356,54 @@ public class PolyhedronsSetTest {
 
         double offset = size * 0.5;
 
-        Plane xMinus = new Plane(center.add(new Vector3D(-offset, 0, 0)), Vector3D.MINUS_X, tolerance);
-        Plane xPlus = new Plane(center.add(new Vector3D(offset, 0, 0)), Vector3D.PLUS_X, tolerance);
-        Plane yPlus = new Plane(center.add(new Vector3D(0, offset, 0)), Vector3D.PLUS_Y, tolerance);
-        Plane yMinus = new Plane(center.add(new Vector3D(0, -offset, 0)), Vector3D.MINUS_Y, tolerance);
-        Plane zPlus = new Plane(center.add(new Vector3D(0, 0, offset)), Vector3D.PLUS_Z, tolerance);
-        Plane zMinus = new Plane(center.add(new Vector3D(0, 0, -offset)), Vector3D.MINUS_Z, tolerance);
+        Plane xMinus = new Plane(center.add(Vector3D.of(-offset, 0, 0)), Vector3D.MINUS_X, tolerance);
+        Plane xPlus = new Plane(center.add(Vector3D.of(offset, 0, 0)), Vector3D.PLUS_X, tolerance);
+        Plane yPlus = new Plane(center.add(Vector3D.of(0, offset, 0)), Vector3D.PLUS_Y, tolerance);
+        Plane yMinus = new Plane(center.add(Vector3D.of(0, -offset, 0)), Vector3D.MINUS_Y, tolerance);
+        Plane zPlus = new Plane(center.add(Vector3D.of(0, 0, offset)), Vector3D.PLUS_Z, tolerance);
+        Plane zMinus = new Plane(center.add(Vector3D.of(0, 0, -offset)), Vector3D.MINUS_Z, tolerance);
 
         // +x
         boundaries.add(createSubPlane(xPlus,
-                        center.add(new Vector3D(offset, offset, offset)),
-                        center.add(new Vector3D(offset, -offset, offset)),
-                        center.add(new Vector3D(offset, -offset, -offset)),
-                        center.add(new Vector3D(offset, offset, -offset))));
+                        center.add(Vector3D.of(offset, offset, offset)),
+                        center.add(Vector3D.of(offset, -offset, offset)),
+                        center.add(Vector3D.of(offset, -offset, -offset)),
+                        center.add(Vector3D.of(offset, offset, -offset))));
 
         // -x
         boundaries.add(createSubPlane(xMinus,
-                        center.add(new Vector3D(-offset, -offset, offset)),
-                        center.add(new Vector3D(-offset, offset, offset)),
-                        center.add(new Vector3D(-offset, offset, -offset)),
-                        center.add(new Vector3D(-offset, -offset, -offset))));
+                        center.add(Vector3D.of(-offset, -offset, offset)),
+                        center.add(Vector3D.of(-offset, offset, offset)),
+                        center.add(Vector3D.of(-offset, offset, -offset)),
+                        center.add(Vector3D.of(-offset, -offset, -offset))));
 
         // +y
         boundaries.add(createSubPlane(yPlus,
-                        center.add(new Vector3D(-offset, offset, offset)),
-                        center.add(new Vector3D(offset, offset, offset)),
-                        center.add(new Vector3D(offset, offset, -offset)),
-                        center.add(new Vector3D(-offset, offset, -offset))));
+                        center.add(Vector3D.of(-offset, offset, offset)),
+                        center.add(Vector3D.of(offset, offset, offset)),
+                        center.add(Vector3D.of(offset, offset, -offset)),
+                        center.add(Vector3D.of(-offset, offset, -offset))));
 
         // -y
         boundaries.add(createSubPlane(yMinus,
-                        center.add(new Vector3D(-offset, -offset, offset)),
-                        center.add(new Vector3D(-offset, -offset, -offset)),
-                        center.add(new Vector3D(offset, -offset, -offset)),
-                        center.add(new Vector3D(offset, -offset, offset))));
+                        center.add(Vector3D.of(-offset, -offset, offset)),
+                        center.add(Vector3D.of(-offset, -offset, -offset)),
+                        center.add(Vector3D.of(offset, -offset, -offset)),
+                        center.add(Vector3D.of(offset, -offset, offset))));
 
         // +z
         boundaries.add(createSubPlane(zPlus,
-                        center.add(new Vector3D(-offset, -offset, offset)),
-                        center.add(new Vector3D(offset, -offset, offset)),
-                        center.add(new Vector3D(offset, offset, offset)),
-                        center.add(new Vector3D(-offset, offset, offset))));
+                        center.add(Vector3D.of(-offset, -offset, offset)),
+                        center.add(Vector3D.of(offset, -offset, offset)),
+                        center.add(Vector3D.of(offset, offset, offset)),
+                        center.add(Vector3D.of(-offset, offset, offset))));
 
         // -z
         boundaries.add(createSubPlane(zMinus,
-                        center.add(new Vector3D(-offset, -offset, -offset)),
-                        center.add(new Vector3D(-offset, offset, -offset)),
-                        center.add(new Vector3D(offset, offset, -offset)),
-                        center.add(new Vector3D(offset, -offset, -offset))));
+                        center.add(Vector3D.of(-offset, -offset, -offset)),
+                        center.add(Vector3D.of(-offset, offset, -offset)),
+                        center.add(Vector3D.of(offset, offset, -offset)),
+                        center.add(Vector3D.of(offset, -offset, -offset))));
 
         return boundaries;
     }
@@ -1423,8 +1423,8 @@ public class PolyhedronsSetTest {
         List<Plane> planes = new ArrayList<>();
 
         // add top and bottom planes (+/- z)
-        Point3D topZ = new Point3D(center.getX(), center.getY(), center.getZ() + radius);
-        Point3D bottomZ = new Point3D(center.getX(), center.getY(), center.getZ() - radius);
+        Point3D topZ = Point3D.of(center.getX(), center.getY(), center.getZ() + radius);
+        Point3D bottomZ = Point3D.of(center.getX(), center.getY(), center.getZ() - radius);
 
         planes.add(new Plane(topZ, Vector3D.PLUS_Z, TEST_TOLERANCE));
         planes.add(new Plane(bottomZ, Vector3D.MINUS_Z, TEST_TOLERANCE));
@@ -1457,7 +1457,7 @@ public class PolyhedronsSetTest {
                 x = Math.cos(hAngle) * stackRadius;
                 y = Math.sin(hAngle) * stackRadius;
 
-                norm = new Vector3D(x, y, stackHeight).normalize();
+                norm = Vector3D.of(x, y, stackHeight).normalize();
                 pt = center.add(norm.scalarMultiply(adjustedRadius));
 
                 planes.add(new Plane(pt, norm, TEST_TOLERANCE));
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RotationTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RotationTest.java
index 875575b..ca28f44 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RotationTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RotationTest.java
@@ -51,22 +51,22 @@ public class RotationTest {
   @Deprecated
   public void testAxisAngleDeprecated() {
 
-    Rotation r = new Rotation(new Vector3D(10, 10, 10), 2 * Math.PI / 3);
+    Rotation r = new Rotation(Vector3D.of(10, 10, 10), 2 * Math.PI / 3);
     checkVector(r.applyTo(Vector3D.PLUS_X), Vector3D.PLUS_Y);
     checkVector(r.applyTo(Vector3D.PLUS_Y), Vector3D.PLUS_Z);
     checkVector(r.applyTo(Vector3D.PLUS_Z), Vector3D.PLUS_X);
     double s = 1 / Math.sqrt(3);
-    checkVector(r.getAxis(), new Vector3D(s, s, s));
+    checkVector(r.getAxis(), Vector3D.of(s, s, s));
     checkAngle(r.getAngle(), 2 * Math.PI / 3);
 
     try {
-      new Rotation(new Vector3D(0, 0, 0), 2 * Math.PI / 3);
+      new Rotation(Vector3D.of(0, 0, 0), 2 * Math.PI / 3);
       Assert.fail("an exception should have been thrown");
     } catch (IllegalArgumentException e) {
     }
 
     r = new Rotation(Vector3D.PLUS_Z, 1.5 * Math.PI);
-    checkVector(r.getAxis(), new Vector3D(0, 0, -1));
+    checkVector(r.getAxis(), Vector3D.of(0, 0, -1));
     checkAngle(r.getAngle(), 0.5 * Math.PI);
 
     r = new Rotation(Vector3D.PLUS_Y, Math.PI);
@@ -80,24 +80,24 @@ public class RotationTest {
   @Test
   public void testAxisAngleVectorOperator() {
 
-    Rotation r = new Rotation(new Vector3D(10, 10, 10), 2 * Math.PI / 3, RotationConvention.VECTOR_OPERATOR);
+    Rotation r = new Rotation(Vector3D.of(10, 10, 10), 2 * Math.PI / 3, RotationConvention.VECTOR_OPERATOR);
     checkVector(r.applyTo(Vector3D.PLUS_X), Vector3D.PLUS_Y);
     checkVector(r.applyTo(Vector3D.PLUS_Y), Vector3D.PLUS_Z);
     checkVector(r.applyTo(Vector3D.PLUS_Z), Vector3D.PLUS_X);
     double s = 1 / Math.sqrt(3);
-    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), new Vector3D( s,  s,  s));
-    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), new Vector3D(-s, -s, -s));
+    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), Vector3D.of( s,  s,  s));
+    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), Vector3D.of(-s, -s, -s));
     checkAngle(r.getAngle(), 2 * Math.PI / 3);
 
     try {
-      new Rotation(new Vector3D(0, 0, 0), 2 * Math.PI / 3, RotationConvention.VECTOR_OPERATOR);
+      new Rotation(Vector3D.of(0, 0, 0), 2 * Math.PI / 3, RotationConvention.VECTOR_OPERATOR);
       Assert.fail("an exception should have been thrown");
     } catch (IllegalArgumentException e) {
     }
 
     r = new Rotation(Vector3D.PLUS_Z, 1.5 * Math.PI, RotationConvention.VECTOR_OPERATOR);
-    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), new Vector3D(0, 0, -1));
-    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), new Vector3D(0, 0, +1));
+    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), Vector3D.of(0, 0, -1));
+    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), Vector3D.of(0, 0, +1));
     checkAngle(r.getAngle(), 0.5 * Math.PI);
 
     r = new Rotation(Vector3D.PLUS_Y, Math.PI, RotationConvention.VECTOR_OPERATOR);
@@ -113,24 +113,24 @@ public class RotationTest {
   @Test
   public void testAxisAngleFrameTransform() {
 
-    Rotation r = new Rotation(new Vector3D(10, 10, 10), 2 * Math.PI / 3, RotationConvention.FRAME_TRANSFORM);
+    Rotation r = new Rotation(Vector3D.of(10, 10, 10), 2 * Math.PI / 3, RotationConvention.FRAME_TRANSFORM);
     checkVector(r.applyTo(Vector3D.PLUS_X), Vector3D.PLUS_Z);
     checkVector(r.applyTo(Vector3D.PLUS_Y), Vector3D.PLUS_X);
     checkVector(r.applyTo(Vector3D.PLUS_Z), Vector3D.PLUS_Y);
     double s = 1 / Math.sqrt(3);
-    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), new Vector3D( s,  s,  s));
-    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), new Vector3D(-s, -s, -s));
+    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), Vector3D.of( s,  s,  s));
+    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), Vector3D.of(-s, -s, -s));
     checkAngle(r.getAngle(), 2 * Math.PI / 3);
 
     try {
-      new Rotation(new Vector3D(0, 0, 0), 2 * Math.PI / 3, RotationConvention.FRAME_TRANSFORM);
+      new Rotation(Vector3D.of(0, 0, 0), 2 * Math.PI / 3, RotationConvention.FRAME_TRANSFORM);
       Assert.fail("an exception should have been thrown");
     } catch (IllegalArgumentException e) {
     }
 
     r = new Rotation(Vector3D.PLUS_Z, 1.5 * Math.PI, RotationConvention.FRAME_TRANSFORM);
-    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), new Vector3D(0, 0, -1));
-    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), new Vector3D(0, 0, +1));
+    checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), Vector3D.of(0, 0, -1));
+    checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), Vector3D.of(0, 0, +1));
     checkAngle(r.getAngle(), 0.5 * Math.PI);
 
     r = new Rotation(Vector3D.PLUS_Y, Math.PI, RotationConvention.FRAME_TRANSFORM);
@@ -185,8 +185,8 @@ public class RotationTest {
   @Test
   public void testVectorOnePair() {
 
-    Vector3D u = new Vector3D(3, 2, 1);
-    Vector3D v = new Vector3D(-4, 2, 2);
+    Vector3D u = Vector3D.of(3, 2, 1);
+    Vector3D v = Vector3D.of(-4, 2, 2);
     Rotation r = new Rotation(u, v);
     checkVector(r.applyTo(u.scalarMultiply(v.getNorm())), v.scalarMultiply(u.getNorm()));
 
@@ -204,10 +204,10 @@ public class RotationTest {
   @Test
   public void testVectorTwoPairs() {
 
-    Vector3D u1 = new Vector3D(3, 0, 0);
-    Vector3D u2 = new Vector3D(0, 5, 0);
-    Vector3D v1 = new Vector3D(0, 0, 2);
-    Vector3D v2 = new Vector3D(-2, 0, 2);
+    Vector3D u1 = Vector3D.of(3, 0, 0);
+    Vector3D u2 = Vector3D.of(0, 5, 0);
+    Vector3D v1 = Vector3D.of(0, 0, 2);
+    Vector3D v2 = Vector3D.of(-2, 0, 2);
     Rotation r = new Rotation(u1, u2, v1, v2);
     checkVector(r.applyTo(Vector3D.PLUS_X), Vector3D.PLUS_Z);
     checkVector(r.applyTo(Vector3D.PLUS_Y), Vector3D.MINUS_X);
@@ -223,8 +223,8 @@ public class RotationTest {
 
     double sqrt = Math.sqrt(2) / 2;
     r = new Rotation(Vector3D.PLUS_X,  Vector3D.PLUS_Y,
-                     new Vector3D(0.5, 0.5,  sqrt),
-                     new Vector3D(0.5, 0.5, -sqrt));
+                     Vector3D.of(0.5, 0.5,  sqrt),
+                     Vector3D.of(0.5, 0.5, -sqrt));
     checkRotation(r, sqrt, 0.5, 0.5, 0);
 
     r = new Rotation(u1, u2, u1, u1.crossProduct(u2));
@@ -362,11 +362,11 @@ public class RotationTest {
     }
 
     checkVector(r.applyTo(Vector3D.PLUS_X),
-                new Vector3D(m3[0][0], m3[1][0], m3[2][0]));
+                Vector3D.of(m3[0][0], m3[1][0], m3[2][0]));
     checkVector(r.applyTo(Vector3D.PLUS_Y),
-                new Vector3D(m3[0][1], m3[1][1], m3[2][1]));
+                Vector3D.of(m3[0][1], m3[1][1], m3[2][1]));
     checkVector(r.applyTo(Vector3D.PLUS_Z),
-                new Vector3D(m3[0][2], m3[1][2], m3[2][2]));
+                Vector3D.of(m3[0][2], m3[1][2], m3[2][2]));
 
     double[][] m4 = { { 1.0,  0.0,  0.0 },
                       { 0.0, -1.0,  0.0 },
@@ -524,7 +524,7 @@ public class RotationTest {
   @Test
   public void testQuaternion() {
 
-    Rotation r1 = new Rotation(new Vector3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
+    Rotation r1 = new Rotation(Vector3D.of(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(),
@@ -532,7 +532,7 @@ public class RotationTest {
     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) {
-          Vector3D u = new Vector3D(x, y, z);
+          Vector3D u = Vector3D.of(x, y, z);
           checkVector(r2.applyTo(u), r1.applyTo(u));
         }
       }
@@ -546,14 +546,14 @@ public class RotationTest {
   @Test
   public void testApplyTo() {
 
-    Rotation r1 = new Rotation(new Vector3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
-    Rotation r2 = new Rotation(new Vector3D(-1, 3, 2), 0.3, RotationConvention.VECTOR_OPERATOR);
+    Rotation r1 = new Rotation(Vector3D.of(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
+    Rotation r2 = new Rotation(Vector3D.of(-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) {
-          Vector3D u = new Vector3D(x, y, z);
+          Vector3D u = Vector3D.of(x, y, z);
           checkVector(r2.applyTo(r1.applyTo(u)), r3.applyTo(u));
         }
       }
@@ -564,14 +564,14 @@ public class RotationTest {
   @Test
   public void testComposeVectorOperator() {
 
-    Rotation r1 = new Rotation(new Vector3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
-    Rotation r2 = new Rotation(new Vector3D(-1, 3, 2), 0.3, RotationConvention.VECTOR_OPERATOR);
+    Rotation r1 = new Rotation(Vector3D.of(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
+    Rotation r2 = new Rotation(Vector3D.of(-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) {
-          Vector3D u = new Vector3D(x, y, z);
+          Vector3D u = Vector3D.of(x, y, z);
           checkVector(r2.applyTo(r1.applyTo(u)), r3.applyTo(u));
         }
       }
@@ -582,8 +582,8 @@ public class RotationTest {
   @Test
   public void testComposeFrameTransform() {
 
-    Rotation r1 = new Rotation(new Vector3D(2, -3, 5), 1.7, RotationConvention.FRAME_TRANSFORM);
-    Rotation r2 = new Rotation(new Vector3D(-1, 3, 2), 0.3, RotationConvention.FRAME_TRANSFORM);
+    Rotation r1 = new Rotation(Vector3D.of(2, -3, 5), 1.7, RotationConvention.FRAME_TRANSFORM);
+    Rotation r2 = new Rotation(Vector3D.of(-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);
@@ -591,7 +591,7 @@ public class RotationTest {
     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) {
-          Vector3D u = new Vector3D(x, y, z);
+          Vector3D u = Vector3D.of(x, y, z);
           checkVector(r1.applyTo(r2.applyTo(u)), r3.applyTo(u));
         }
       }
@@ -602,14 +602,14 @@ public class RotationTest {
   @Test
   public void testApplyInverseToRotation() {
 
-    Rotation r1 = new Rotation(new Vector3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
-    Rotation r2 = new Rotation(new Vector3D(-1, 3, 2), 0.3, RotationConvention.VECTOR_OPERATOR);
+    Rotation r1 = new Rotation(Vector3D.of(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
+    Rotation r2 = new Rotation(Vector3D.of(-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) {
-          Vector3D u = new Vector3D(x, y, z);
+          Vector3D u = Vector3D.of(x, y, z);
           checkVector(r2.applyInverseTo(r1.applyTo(u)), r3.applyTo(u));
         }
       }
@@ -620,14 +620,14 @@ public class RotationTest {
   @Test
   public void testComposeInverseVectorOperator() {
 
-    Rotation r1 = new Rotation(new Vector3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
-    Rotation r2 = new Rotation(new Vector3D(-1, 3, 2), 0.3, RotationConvention.VECTOR_OPERATOR);
+    Rotation r1 = new Rotation(Vector3D.of(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
+    Rotation r2 = new Rotation(Vector3D.of(-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) {
-          Vector3D u = new Vector3D(x, y, z);
+          Vector3D u = Vector3D.of(x, y, z);
           checkVector(r2.applyInverseTo(r1.applyTo(u)), r3.applyTo(u));
         }
       }
@@ -638,8 +638,8 @@ public class RotationTest {
   @Test
   public void testComposeInverseFrameTransform() {
 
-    Rotation r1 = new Rotation(new Vector3D(2, -3, 5), 1.7, RotationConvention.FRAME_TRANSFORM);
-    Rotation r2 = new Rotation(new Vector3D(-1, 3, 2), 0.3, RotationConvention.FRAME_TRANSFORM);
+    Rotation r1 = new Rotation(Vector3D.of(2, -3, 5), 1.7, RotationConvention.FRAME_TRANSFORM);
+    Rotation r2 = new Rotation(Vector3D.of(-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);
@@ -647,7 +647,7 @@ public class RotationTest {
     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) {
-          Vector3D u = new Vector3D(x, y, z);
+          Vector3D u = Vector3D.of(x, y, z);
           checkVector(r1.applyTo(r2.applyInverseTo(u)), r3.applyTo(u));
         }
       }
@@ -658,12 +658,12 @@ public class RotationTest {
   @Test
   public void testArray() {
 
-      Rotation r = new Rotation(new Vector3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
+      Rotation r = new Rotation(Vector3D.of(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) {
-                  Vector3D u = new Vector3D(x, y, z);
+                  Vector3D u = Vector3D.of(x, y, z);
                   Vector3D v = r.applyTo(u);
                   double[] inOut = new double[] { x, y, z };
                   r.applyTo(inOut, inOut);
@@ -683,10 +683,10 @@ public class RotationTest {
   @Test
   public void testApplyInverseTo() {
 
-    Rotation r = new Rotation(new Vector3D(2, -3, 5), 1.7, RotationConvention.VECTOR_OPERATOR);
+    Rotation r = new Rotation(Vector3D.of(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) {
-          Vector3D u = new Vector3D(Math.cos(lambda) * Math.cos(phi),
+          Vector3D u = Vector3D.of(Math.cos(lambda) * Math.cos(phi),
                                     Math.sin(lambda) * Math.cos(phi),
                                     Math.sin(phi));
           r.applyInverseTo(r.applyTo(u));
@@ -698,7 +698,7 @@ public class RotationTest {
     r = Rotation.IDENTITY;
     for (double lambda = 0; lambda < 6.2; lambda += 0.2) {
       for (double phi = -1.55; phi < 1.55; phi += 0.2) {
-          Vector3D u = new Vector3D(Math.cos(lambda) * Math.cos(phi),
+          Vector3D u = Vector3D.of(Math.cos(lambda) * Math.cos(phi),
                                     Math.sin(lambda) * Math.cos(phi),
                                     Math.sin(phi));
           checkVector(u, r.applyInverseTo(r.applyTo(u)));
@@ -709,7 +709,7 @@ public class RotationTest {
     r = new Rotation(Vector3D.PLUS_Z, Math.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) {
-          Vector3D u = new Vector3D(Math.cos(lambda) * Math.cos(phi),
+          Vector3D u = Vector3D.of(Math.cos(lambda) * Math.cos(phi),
                                     Math.sin(lambda) * Math.cos(phi),
                                     Math.sin(phi));
           checkVector(u, r.applyInverseTo(r.applyTo(u)));
@@ -721,10 +721,10 @@ public class RotationTest {
 
   @Test
   public void testIssue639() {
-      Vector3D u1 = new Vector3D(-1321008684645961.0 /  268435456.0,
+      Vector3D u1 = Vector3D.of(-1321008684645961.0 /  268435456.0,
                                  -5774608829631843.0 /  268435456.0,
                                  -3822921525525679.0 / 4294967296.0);
-      Vector3D u2 =new Vector3D( -5712344449280879.0 /    2097152.0,
+      Vector3D u2 =Vector3D.of( -5712344449280879.0 /    2097152.0,
                                  -2275058564560979.0 /    1048576.0,
                                   4423475992255071.0 /      65536.0);
       Rotation rot = new Rotation(u1, u2, Vector3D.PLUS_X,Vector3D.PLUS_Z);
@@ -736,11 +736,11 @@ public class RotationTest {
 
   @Test
   public void testIssue801() {
-      Vector3D u1 = new Vector3D(0.9999988431610581, -0.0015210774290851095, 0.0);
-      Vector3D u2 = new Vector3D(0.0, 0.0, 1.0);
+      Vector3D u1 = Vector3D.of(0.9999988431610581, -0.0015210774290851095, 0.0);
+      Vector3D u2 = Vector3D.of(0.0, 0.0, 1.0);
 
-      Vector3D v1 = new Vector3D(0.9999999999999999, 0.0, 0.0);
-      Vector3D v2 = new Vector3D(0.0, 0.0, -1.0);
+      Vector3D v1 = Vector3D.of(0.9999999999999999, 0.0, 0.0);
+      Vector3D v2 = Vector3D.of(0.0, 0.0, -1.0);
 
       Rotation quat = new Rotation(u1, u2, v1, v2);
       double q2 = quat.getQ0() * quat.getQ0() +
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLineTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLineTest.java
index c076b9e..49e31a2 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLineTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLineTest.java
@@ -28,19 +28,19 @@ public class SubLineTest {
 
     @Test
     public void testEndPoints() {
-        Point3D p1 = new Point3D(-1, -7, 2);
-        Point3D p2 = new Point3D(7, -1, 0);
+        Point3D p1 = Point3D.of(-1, -7, 2);
+        Point3D p2 = Point3D.of(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 Point3D(-1, -7, 2).distance(segments.get(0).getStart()), 1.0e-10);
-        Assert.assertEquals(0.0, new Point3D( 7, -1, 0).distance(segments.get(0).getEnd()), 1.0e-10);
+        Assert.assertEquals(0.0, Point3D.of(-1, -7, 2).distance(segments.get(0).getStart()), 1.0e-10);
+        Assert.assertEquals(0.0, Point3D.of( 7, -1, 0).distance(segments.get(0).getEnd()), 1.0e-10);
     }
 
     @Test
     public void testNoEndPoints() {
-        SubLine wholeLine = new Line(new Point3D(-1, 7, 2), new Point3D(7, 1, 0), 1.0e-10).wholeLine();
+        SubLine wholeLine = new Line(Point3D.of(-1, 7, 2), Point3D.of(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()) &&
@@ -59,7 +59,7 @@ public class SubLineTest {
 
     @Test
     public void testNoSegments() {
-        SubLine empty = new SubLine(new Line(new Point3D(-1, -7, 2), new Point3D(7, -1, 0), 1.0e-10),
+        SubLine empty = new SubLine(new Line(Point3D.of(-1, -7, 2), Point3D.of(7, -1, 0), 1.0e-10),
                                     (IntervalsSet) new RegionFactory<Point1D>().getComplement(new IntervalsSet(1.0e-10)));
         List<Segment> segments = empty.getSegments();
         Assert.assertEquals(0, segments.size());
@@ -67,7 +67,7 @@ public class SubLineTest {
 
     @Test
     public void testSeveralSegments() {
-        SubLine twoSubs = new SubLine(new Line(new Point3D(-1, -7, 2), new Point3D(7, -1, 0), 1.0e-10),
+        SubLine twoSubs = new SubLine(new Line(Point3D.of(-1, -7, 2), Point3D.of(7, -1, 0), 1.0e-10),
                                       (IntervalsSet) new RegionFactory<Point1D>().union(new IntervalsSet(1, 2, 1.0e-10),
                                                                                             new IntervalsSet(3, 4, 1.0e-10)));
         List<Segment> segments = twoSubs.getSegments();
@@ -76,7 +76,7 @@ public class SubLineTest {
 
     @Test
     public void testHalfInfiniteNeg() {
-        SubLine empty = new SubLine(new Line(new Point3D(-1, -7, 2), new Point3D(7, -1, -2), 1.0e-10),
+        SubLine empty = new SubLine(new Line(Point3D.of(-1, -7, 2), Point3D.of(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());
@@ -86,16 +86,16 @@ public class SubLineTest {
                           segments.get(0).getStart().getY() < 0);
         Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getZ()) &&
                           segments.get(0).getStart().getZ() > 0);
-        Assert.assertEquals(0.0, new Point3D(3, -4, 0).distance(segments.get(0).getEnd()), 1.0e-10);
+        Assert.assertEquals(0.0, Point3D.of(3, -4, 0).distance(segments.get(0).getEnd()), 1.0e-10);
     }
 
     @Test
     public void testHalfInfinitePos() {
-        SubLine empty = new SubLine(new Line(new Point3D(-1, -7, 2), new Point3D(7, -1, -2), 1.0e-10),
+        SubLine empty = new SubLine(new Line(Point3D.of(-1, -7, 2), Point3D.of(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 Point3D(3, -4, 0).distance(segments.get(0).getStart()), 1.0e-10);
+        Assert.assertEquals(0.0, Point3D.of(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()) &&
@@ -106,56 +106,56 @@ public class SubLineTest {
 
     @Test
     public void testIntersectionInsideInside() {
-        SubLine sub1 = new SubLine(new Point3D(1, 1, 1), new Point3D(3, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point3D(2, 0, 0), new Point3D(2, 2, 2), 1.0e-10);
-        Assert.assertEquals(0.0, new Point3D(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
-        Assert.assertEquals(0.0, new Point3D(2, 1, 1).distance(sub1.intersection(sub2, false)), 1.0e-12);
+        SubLine sub1 = new SubLine(Point3D.of(1, 1, 1), Point3D.of(3, 1, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point3D.of(2, 0, 0), Point3D.of(2, 2, 2), 1.0e-10);
+        Assert.assertEquals(0.0, Point3D.of(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
+        Assert.assertEquals(0.0, Point3D.of(2, 1, 1).distance(sub1.intersection(sub2, false)), 1.0e-12);
     }
 
     @Test
     public void testIntersectionInsideBoundary() {
-        SubLine sub1 = new SubLine(new Point3D(1, 1, 1), new Point3D(3, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point3D(2, 0, 0), new Point3D(2, 1, 1), 1.0e-10);
-        Assert.assertEquals(0.0, new Point3D(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
+        SubLine sub1 = new SubLine(Point3D.of(1, 1, 1), Point3D.of(3, 1, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point3D.of(2, 0, 0), Point3D.of(2, 1, 1), 1.0e-10);
+        Assert.assertEquals(0.0, Point3D.of(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionInsideOutside() {
-        SubLine sub1 = new SubLine(new Point3D(1, 1, 1), new Point3D(3, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point3D(2, 0, 0), new Point3D(2, 0.5, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Point3D.of(1, 1, 1), Point3D.of(3, 1, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point3D.of(2, 0, 0), Point3D.of(2, 0.5, 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 Point3D(1, 1, 1), new Point3D(2, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point3D(2, 0, 0), new Point3D(2, 1, 1), 1.0e-10);
-        Assert.assertEquals(0.0, new Point3D(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
+        SubLine sub1 = new SubLine(Point3D.of(1, 1, 1), Point3D.of(2, 1, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point3D.of(2, 0, 0), Point3D.of(2, 1, 1), 1.0e-10);
+        Assert.assertEquals(0.0, Point3D.of(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionBoundaryOutside() {
-        SubLine sub1 = new SubLine(new Point3D(1, 1, 1), new Point3D(2, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point3D(2, 0, 0), new Point3D(2, 0.5, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Point3D.of(1, 1, 1), Point3D.of(2, 1, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point3D.of(2, 0, 0), Point3D.of(2, 0.5, 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 Point3D(1, 1, 1), new Point3D(1.5, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point3D(2, 0, 0), new Point3D(2, 0.5, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Point3D.of(1, 1, 1), Point3D.of(1.5, 1, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point3D.of(2, 0, 0), Point3D.of(2, 0.5, 0.5), 1.0e-10);
         Assert.assertNull(sub1.intersection(sub2, true));
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionNotIntersecting() {
-        SubLine sub1 = new SubLine(new Point3D(1, 1, 1), new Point3D(1.5, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point3D(2, 3, 0), new Point3D(2, 3, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Point3D.of(1, 1, 1), Point3D.of(1.5, 1, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point3D.of(2, 3, 0), Point3D.of(2, 3, 0.5), 1.0e-10);
         Assert.assertNull(sub1.intersection(sub2, true));
         Assert.assertNull(sub1.intersection(sub2, false));
     }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/LineTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/LineTest.java
index 60ea0ad..f1bcebf 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/LineTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/LineTest.java
@@ -25,49 +25,49 @@ public class LineTest {
 
     @Test
     public void testContains() {
-        Line l = new Line(new Point2D(0, 1), new Point2D(1, 2), 1.0e-10);
-        Assert.assertTrue(l.contains(new Point2D(0, 1)));
-        Assert.assertTrue(l.contains(new Point2D(1, 2)));
-        Assert.assertTrue(l.contains(new Point2D(7, 8)));
-        Assert.assertTrue(! l.contains(new Point2D(8, 7)));
+        Line l = new Line(Point2D.of(0, 1), Point2D.of(1, 2), 1.0e-10);
+        Assert.assertTrue(l.contains(Point2D.of(0, 1)));
+        Assert.assertTrue(l.contains(Point2D.of(1, 2)));
+        Assert.assertTrue(l.contains(Point2D.of(7, 8)));
+        Assert.assertTrue(! l.contains(Point2D.of(8, 7)));
     }
 
     @Test
     public void testAbscissa() {
-        Line l = new Line(new Point2D(2, 1), new Point2D(-2, -2), 1.0e-10);
+        Line l = new Line(Point2D.of(2, 1), Point2D.of(-2, -2), 1.0e-10);
         Assert.assertEquals(0.0,
-                            (l.toSubSpace(new Point2D(-3,  4))).getX(),
+                            (l.toSubSpace(Point2D.of(-3,  4))).getX(),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            (l.toSubSpace(new Point2D( 3, -4))).getX(),
+                            (l.toSubSpace(Point2D.of( 3, -4))).getX(),
                             1.0e-10);
         Assert.assertEquals(-5.0,
-                            (l.toSubSpace(new Point2D( 7, -1))).getX(),
+                            (l.toSubSpace(Point2D.of( 7, -1))).getX(),
                             1.0e-10);
         Assert.assertEquals(5.0,
-                             (l.toSubSpace(new Point2D(-1, -7))).getX(),
+                             (l.toSubSpace(Point2D.of(-1, -7))).getX(),
                              1.0e-10);
     }
 
     @Test
     public void testOffset() {
-        Line l = new Line(new Point2D(2, 1), new Point2D(-2, -2), 1.0e-10);
-        Assert.assertEquals(-5.0, l.getOffset(new Point2D(5, -3)), 1.0e-10);
-        Assert.assertEquals(+5.0, l.getOffset(new Point2D(-5, 2)), 1.0e-10);
+        Line l = new Line(Point2D.of(2, 1), Point2D.of(-2, -2), 1.0e-10);
+        Assert.assertEquals(-5.0, l.getOffset(Point2D.of(5, -3)), 1.0e-10);
+        Assert.assertEquals(+5.0, l.getOffset(Point2D.of(-5, 2)), 1.0e-10);
     }
 
     @Test
     public void testDistance() {
-        Line l = new Line(new Point2D(2, 1), new Point2D(-2, -2), 1.0e-10);
-        Assert.assertEquals(+5.0, l.distance(new Point2D(5, -3)), 1.0e-10);
-        Assert.assertEquals(+5.0, l.distance(new Point2D(-5, 2)), 1.0e-10);
+        Line l = new Line(Point2D.of(2, 1), Point2D.of(-2, -2), 1.0e-10);
+        Assert.assertEquals(+5.0, l.distance(Point2D.of(5, -3)), 1.0e-10);
+        Assert.assertEquals(+5.0, l.distance(Point2D.of(-5, 2)), 1.0e-10);
     }
 
     @Test
     public void testPointAt() {
-        Line l = new Line(new Point2D(2, 1), new Point2D(-2, -2), 1.0e-10);
+        Line l = new Line(Point2D.of(2, 1), Point2D.of(-2, -2), 1.0e-10);
         for (double a = -2.0; a < 2.0; a += 0.2) {
-            Point1D pA = new Point1D(a);
+            Point1D pA = Point1D.of(a);
             Point2D point = l.toSpace(pA);
             Assert.assertEquals(a, (l.toSubSpace(point)).getX(), 1.0e-10);
             Assert.assertEquals(0.0, l.getOffset(point),   1.0e-10);
@@ -81,34 +81,34 @@ public class LineTest {
 
     @Test
     public void testOriginOffset() {
-        Line l1 = new Line(new Point2D(0, 1), new Point2D(1, 2), 1.0e-10);
+        Line l1 = new Line(Point2D.of(0, 1), Point2D.of(1, 2), 1.0e-10);
         Assert.assertEquals(Math.sqrt(0.5), l1.getOriginOffset(), 1.0e-10);
-        Line l2 = new Line(new Point2D(1, 2), new Point2D(0, 1), 1.0e-10);
+        Line l2 = new Line(Point2D.of(1, 2), Point2D.of(0, 1), 1.0e-10);
         Assert.assertEquals(-Math.sqrt(0.5), l2.getOriginOffset(), 1.0e-10);
     }
 
     @Test
     public void testParallel() {
-        Line l1 = new Line(new Point2D(0, 1), new Point2D(1, 2), 1.0e-10);
-        Line l2 = new Line(new Point2D(2, 2), new Point2D(3, 3), 1.0e-10);
+        Line l1 = new Line(Point2D.of(0, 1), Point2D.of(1, 2), 1.0e-10);
+        Line l2 = new Line(Point2D.of(2, 2), Point2D.of(3, 3), 1.0e-10);
         Assert.assertTrue(l1.isParallelTo(l2));
-        Line l3 = new Line(new Point2D(1, 0), new Point2D(0.5, -0.5), 1.0e-10);
+        Line l3 = new Line(Point2D.of(1, 0), Point2D.of(0.5, -0.5), 1.0e-10);
         Assert.assertTrue(l1.isParallelTo(l3));
-        Line l4 = new Line(new Point2D(1, 0), new Point2D(0.5, -0.51), 1.0e-10);
+        Line l4 = new Line(Point2D.of(1, 0), Point2D.of(0.5, -0.51), 1.0e-10);
         Assert.assertTrue(! l1.isParallelTo(l4));
     }
 
     @Test
     public void testTransform() {
 
-        Line l1 = new Line(new Point2D(1.0 ,1.0), new Point2D(4.0 ,1.0), 1.0e-10);
+        Line l1 = new Line(Point2D.of(1.0 ,1.0), Point2D.of(4.0 ,1.0), 1.0e-10);
         Transform<Point2D, Point1D> t1 =
             Line.getTransform(0.0, 0.5, -1.0, 0.0, 1.0, 1.5);
         Assert.assertEquals(0.5 * Math.PI,
                             ((Line) t1.apply(l1)).getAngle(),
                             1.0e-10);
 
-        Line l2 = new Line(new Point2D(0.0, 0.0), new Point2D(1.0, 1.0), 1.0e-10);
+        Line l2 = new Line(Point2D.of(0.0, 0.0), Point2D.of(1.0, 1.0), 1.0e-10);
         Transform<Point2D, Point1D> t2 =
             Line.getTransform(0.0, 0.5, -1.0, 0.0, 1.0, 1.5);
         Assert.assertEquals(Math.atan2(1.0, -2.0),
@@ -119,8 +119,8 @@ public class LineTest {
 
     @Test
     public void testIntersection() {
-        Line    l1 = new Line(new Point2D( 0, 1), new Point2D(1, 2), 1.0e-10);
-        Line    l2 = new Line(new Point2D(-1, 2), new Point2D(2, 1), 1.0e-10);
+        Line    l1 = new Line(Point2D.of( 0, 1), Point2D.of(1, 2), 1.0e-10);
+        Line    l2 = new Line(Point2D.of(-1, 2), Point2D.of(2, 1), 1.0e-10);
         Point2D p  = l1.intersection(l2);
         Assert.assertEquals(0.5, p.getX(), 1.0e-10);
         Assert.assertEquals(1.5, p.getY(), 1.0e-10);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/NestedLoopsTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/NestedLoopsTest.java
index 26cec45..8521c9f 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/NestedLoopsTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/NestedLoopsTest.java
@@ -31,11 +31,11 @@ public class NestedLoopsTest {
     @SuppressWarnings("unchecked")
     @Test
     public void testNestedLoops() throws Exception {
-        Point2D oneOne = new Point2D(1.0, 1.0);
-        Point2D oneNegativeOne = new Point2D(1.0, -1.0);
-        Point2D negativeOneNegativeOne = new Point2D(-1.0, -1.0);
-        Point2D negativeOneOne = new Point2D(-1.0, 1.0);
-        Point2D origin = new Point2D(0, 0);
+        Point2D oneOne = Point2D.of(1.0, 1.0);
+        Point2D oneNegativeOne = Point2D.of(1.0, -1.0);
+        Point2D negativeOneNegativeOne = Point2D.of(-1.0, -1.0);
+        Point2D negativeOneOne = Point2D.of(-1.0, 1.0);
+        Point2D origin = Point2D.of(0, 0);
 
         Point2D [] vertices = new Point2D[]{
                 oneOne,
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolygonsSetTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolygonsSetTest.java
index f565ea6..55eaa86 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolygonsSetTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolygonsSetTest.java
@@ -55,13 +55,13 @@ public class PolygonsSetTest {
         EuclideanTestUtils.assertCoordinatesEqual(Point2D.NaN, poly.getBarycenter(), TEST_TOLERANCE);
 
         checkPoints(Region.Location.INSIDE, poly,
-                new Point2D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY),
+                Point2D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY),
                 Point2D.ZERO,
-                new Point2D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
+                Point2D.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
 
         for (double y = -1; y < 1; y += 0.1) {
             for (double x = -1; x < 1; x += 0.1) {
-                EuclideanTestUtils.assertNegativeInfinity(poly.projectToBoundary(new Point2D(x, y)).getOffset());
+                EuclideanTestUtils.assertNegativeInfinity(poly.projectToBoundary(Point2D.of(x, y)).getOffset());
             }
         }
     }
@@ -81,14 +81,14 @@ public class PolygonsSetTest {
         EuclideanTestUtils.assertCoordinatesEqual(Point2D.NaN, poly.getBarycenter(), TEST_TOLERANCE);
 
         checkPoints(Region.Location.OUTSIDE, poly,
-                new Point2D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY),
+                Point2D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY),
                 Point2D.ZERO,
-                new Point2D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
+                Point2D.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
 
 
         for (double y = -1; y < 1; y += 0.1) {
             for (double x = -1; x < 1; x += 0.1) {
-                EuclideanTestUtils.assertPositiveInfinity(poly.projectToBoundary(new Point2D(x, y)).getOffset());
+                EuclideanTestUtils.assertPositiveInfinity(poly.projectToBoundary(Point2D.of(x, y)).getOffset());
             }
         }
     }
@@ -96,7 +96,7 @@ public class PolygonsSetTest {
     @Test
     public void testInfiniteLines_single() {
         // arrange
-        Line line = new Line(new Point2D(0, 0), new Point2D(1, 1), TEST_TOLERANCE);
+        Line line = new Line(Point2D.of(0, 0), Point2D.of(1, 1), TEST_TOLERANCE);
 
         List<SubHyperplane<Point2D>> boundaries = new ArrayList<SubHyperplane<Point2D>>();
         boundaries.add(line.wholeHyperplane());
@@ -115,25 +115,25 @@ public class PolygonsSetTest {
         checkVertexLoopsEquivalent(new Point2D[][] {
             {
                 null,
-                line.toSpace(new Point1D(-Float.MAX_VALUE)),
-                line.toSpace(new Point1D(Float.MAX_VALUE))
+                line.toSpace(Point1D.of(-Float.MAX_VALUE)),
+                line.toSpace(Point1D.of(Float.MAX_VALUE))
             }
         }, poly.getVertices());
 
         checkPoints(Region.Location.OUTSIDE, poly,
-                new Point2D(1, -1),
-                new Point2D(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY));
+                Point2D.of(1, -1),
+                Point2D.of(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY));
         checkPoints(Region.Location.INSIDE, poly,
-                new Point2D(-1, 1),
-                new Point2D(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+                Point2D.of(-1, 1),
+                Point2D.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
         checkPoints(Region.Location.BOUNDARY, poly, Point2D.ZERO);
     }
 
     @Test
     public void testInfiniteLines_twoIntersecting() {
         // arrange
-        Line line1 = new Line(new Point2D(0, 0), new Point2D(1, 1), TEST_TOLERANCE);
-        Line line2 = new Line(new Point2D(1, -1), new Point2D(0, 0), TEST_TOLERANCE);
+        Line line1 = new Line(Point2D.of(0, 0), Point2D.of(1, 1), TEST_TOLERANCE);
+        Line line2 = new Line(Point2D.of(1, -1), Point2D.of(0, 0), TEST_TOLERANCE);
 
         List<SubHyperplane<Point2D>> boundaries = new ArrayList<SubHyperplane<Point2D>>();
         boundaries.add(line1.wholeHyperplane());
@@ -153,25 +153,25 @@ public class PolygonsSetTest {
         checkVertexLoopsEquivalent(new Point2D[][] {
             {
                 null,
-                line2.toSpace(new Point1D(-Float.MAX_VALUE)),
-                line2.toSpace(new Point1D(Float.MAX_VALUE))
+                line2.toSpace(Point1D.of(-Float.MAX_VALUE)),
+                line2.toSpace(Point1D.of(Float.MAX_VALUE))
             }
         }, poly.getVertices());
 
         checkPoints(Region.Location.INSIDE, poly,
-                new Point2D(-1, 0),
-                new Point2D(-Float.MAX_VALUE, Float.MAX_VALUE / 2.0));
+                Point2D.of(-1, 0),
+                Point2D.of(-Float.MAX_VALUE, Float.MAX_VALUE / 2.0));
         checkPoints(Region.Location.OUTSIDE, poly,
-                new Point2D(1, 0),
-                new Point2D(Float.MAX_VALUE, Float.MAX_VALUE / 2.0));
+                Point2D.of(1, 0),
+                Point2D.of(Float.MAX_VALUE, Float.MAX_VALUE / 2.0));
         checkPoints(Region.Location.BOUNDARY, poly, Point2D.ZERO);
     }
 
     @Test
     public void testInfiniteLines_twoParallel_facingIn() {
         // arrange
-        Line line1 = new Line(new Point2D(1, 1), new Point2D(0, 1), TEST_TOLERANCE);
-        Line line2 = new Line(new Point2D(0, -1), new Point2D(1, -1), TEST_TOLERANCE);
+        Line line1 = new Line(Point2D.of(1, 1), Point2D.of(0, 1), TEST_TOLERANCE);
+        Line line2 = new Line(Point2D.of(0, -1), Point2D.of(1, -1), TEST_TOLERANCE);
 
         List<SubHyperplane<Point2D>> boundaries = new ArrayList<SubHyperplane<Point2D>>();
         boundaries.add(line1.wholeHyperplane());
@@ -191,33 +191,33 @@ public class PolygonsSetTest {
         checkVertexLoopsEquivalent(new Point2D[][] {
             {
                 null,
-                line1.toSpace(new Point1D(-Float.MAX_VALUE)),
-                line1.toSpace(new Point1D(Float.MAX_VALUE))
+                line1.toSpace(Point1D.of(-Float.MAX_VALUE)),
+                line1.toSpace(Point1D.of(Float.MAX_VALUE))
             },
             {
                 null,
-                line2.toSpace(new Point1D(-Float.MAX_VALUE)),
-                line2.toSpace(new Point1D(Float.MAX_VALUE))
+                line2.toSpace(Point1D.of(-Float.MAX_VALUE)),
+                line2.toSpace(Point1D.of(Float.MAX_VALUE))
             }
         }, poly.getVertices());
 
         checkPoints(Region.Location.INSIDE, poly,
-                new Point2D(0, 0),
-                new Point2D(0, 0.9),
-                new Point2D(0, -0.9));
+                Point2D.of(0, 0),
+                Point2D.of(0, 0.9),
+                Point2D.of(0, -0.9));
         checkPoints(Region.Location.OUTSIDE, poly,
-                new Point2D(0, 1.1),
-                new Point2D(0, -1.1));
+                Point2D.of(0, 1.1),
+                Point2D.of(0, -1.1));
         checkPoints(Region.Location.BOUNDARY, poly,
-                new Point2D(0, 1),
-                new Point2D(0, -1));
+                Point2D.of(0, 1),
+                Point2D.of(0, -1));
     }
 
     @Test
     public void testInfiniteLines_twoParallel_facingOut() {
         // arrange
-        Line line1 = new Line(new Point2D(0, 1), new Point2D(1, 1), TEST_TOLERANCE);
-        Line line2 = new Line(new Point2D(1, -1), new Point2D(0, -1), TEST_TOLERANCE);
+        Line line1 = new Line(Point2D.of(0, 1), Point2D.of(1, 1), TEST_TOLERANCE);
+        Line line2 = new Line(Point2D.of(1, -1), Point2D.of(0, -1), TEST_TOLERANCE);
 
         List<SubHyperplane<Point2D>> boundaries = new ArrayList<SubHyperplane<Point2D>>();
         boundaries.add(line1.wholeHyperplane());
@@ -237,38 +237,38 @@ public class PolygonsSetTest {
         checkVertexLoopsEquivalent(new Point2D[][] {
             {
                 null,
-                line1.toSpace(new Point1D(-Float.MAX_VALUE)),
-                line1.toSpace(new Point1D(Float.MAX_VALUE))
+                line1.toSpace(Point1D.of(-Float.MAX_VALUE)),
+                line1.toSpace(Point1D.of(Float.MAX_VALUE))
             },
             {
                 null,
-                line2.toSpace(new Point1D(-Float.MAX_VALUE)),
-                line2.toSpace(new Point1D(Float.MAX_VALUE))
+                line2.toSpace(Point1D.of(-Float.MAX_VALUE)),
+                line2.toSpace(Point1D.of(Float.MAX_VALUE))
             }
         }, poly.getVertices());
 
         checkPoints(Region.Location.OUTSIDE, poly,
-                new Point2D(0, 0),
-                new Point2D(0, 0.9),
-                new Point2D(0, -0.9));
+                Point2D.of(0, 0),
+                Point2D.of(0, 0.9),
+                Point2D.of(0, -0.9));
         checkPoints(Region.Location.INSIDE, poly,
-                new Point2D(0, 1.1),
-                new Point2D(0, -1.1));
+                Point2D.of(0, 1.1),
+                Point2D.of(0, -1.1));
         checkPoints(Region.Location.BOUNDARY, poly,
-                new Point2D(0, 1),
-                new Point2D(0, -1));
+                Point2D.of(0, 1),
+                Point2D.of(0, -1));
     }
 
     @Test
     public void testMixedFiniteAndInfiniteLines_explicitInfiniteBoundaries() {
         // arrange
-        Line line1 = new Line(new Point2D(3, 3), new Point2D(0, 3), TEST_TOLERANCE);
-        Line line2 = new Line(new Point2D(0, -3), new Point2D(3, -3), TEST_TOLERANCE);
+        Line line1 = new Line(Point2D.of(3, 3), Point2D.of(0, 3), TEST_TOLERANCE);
+        Line line2 = new Line(Point2D.of(0, -3), Point2D.of(3, -3), TEST_TOLERANCE);
 
         List<SubHyperplane<Point2D>> boundaries = new ArrayList<SubHyperplane<Point2D>>();
         boundaries.add(line1.wholeHyperplane());
         boundaries.add(line2.wholeHyperplane());
-        boundaries.add(buildSegment(new Point2D(0, 3), new Point2D(0, -3)));
+        boundaries.add(buildSegment(Point2D.of(0, 3), Point2D.of(0, -3)));
 
         // act
         PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
@@ -284,25 +284,25 @@ public class PolygonsSetTest {
         checkVertexLoopsEquivalent(new Point2D[][] {
             {
                 null,
-                new Point2D(1, 3), // dummy point
-                new Point2D(0, 3),
-                new Point2D(0, -3),
-                new Point2D(1, -3) // dummy point
+                Point2D.of(1, 3), // dummy point
+                Point2D.of(0, 3),
+                Point2D.of(0, -3),
+                Point2D.of(1, -3) // dummy point
             }
         }, poly.getVertices());
 
         checkPoints(Region.Location.INSIDE, poly,
-                new Point2D(0.1, 2.9),
-                new Point2D(0.1, 0),
-                new Point2D(0.1, -2.9));
+                Point2D.of(0.1, 2.9),
+                Point2D.of(0.1, 0),
+                Point2D.of(0.1, -2.9));
         checkPoints(Region.Location.OUTSIDE, poly,
-                new Point2D(0, 3.1),
-                new Point2D(-0.5, 0),
-                new Point2D(0, -3.1));
+                Point2D.of(0, 3.1),
+                Point2D.of(-0.5, 0),
+                Point2D.of(0, -3.1));
         checkPoints(Region.Location.BOUNDARY, poly,
-                new Point2D(3, 3),
-                new Point2D(0, 0),
-                new Point2D(3, -3));
+                Point2D.of(3, 3),
+                Point2D.of(0, 0),
+                Point2D.of(3, -3));
     }
 
     // The polygon in this test is created from finite boundaries but the generated
@@ -313,11 +313,11 @@ public class PolygonsSetTest {
     @Test
     public void testMixedFiniteAndInfiniteLines_impliedInfiniteBoundaries() {
         // arrange
-        Line line = new Line(new Point2D(3, 0), new Point2D(3, 3), TEST_TOLERANCE);
+        Line line = new Line(Point2D.of(3, 0), Point2D.of(3, 3), TEST_TOLERANCE);
 
         List<SubHyperplane<Point2D>> boundaries = new ArrayList<SubHyperplane<Point2D>>();
-        boundaries.add(buildSegment(new Point2D(0, 3), new Point2D(0, 0)));
-        boundaries.add(buildSegment(new Point2D(0, 0), new Point2D(3, 0)));
+        boundaries.add(buildSegment(Point2D.of(0, 3), Point2D.of(0, 0)));
+        boundaries.add(buildSegment(Point2D.of(0, 0), Point2D.of(3, 0)));
         boundaries.add(new SubLine(line, new IntervalsSet(0, Double.POSITIVE_INFINITY, TEST_TOLERANCE)));
 
         // act
@@ -334,29 +334,29 @@ public class PolygonsSetTest {
         checkVertexLoopsEquivalent(new Point2D[][] {
             {
                 null,
-                new Point2D(0, 1), // dummy point
-                new Point2D(0, 0),
-                new Point2D(3, 0),
-                new Point2D(3, 1) // dummy point
+                Point2D.of(0, 1), // dummy point
+                Point2D.of(0, 0),
+                Point2D.of(3, 0),
+                Point2D.of(3, 1) // dummy point
             }
         }, poly.getVertices());
 
         checkPoints(Region.Location.INSIDE, poly,
-                new Point2D(0.1, Float.MAX_VALUE),
-                new Point2D(0.1, 0.1),
-                new Point2D(1.5, 0.1),
-                new Point2D(2.9, 0.1),
-                new Point2D(2.9, Float.MAX_VALUE));
+                Point2D.of(0.1, Float.MAX_VALUE),
+                Point2D.of(0.1, 0.1),
+                Point2D.of(1.5, 0.1),
+                Point2D.of(2.9, 0.1),
+                Point2D.of(2.9, Float.MAX_VALUE));
         checkPoints(Region.Location.OUTSIDE, poly,
-                new Point2D(-0.1, Float.MAX_VALUE),
-                new Point2D(-0.1, 0.1),
-                new Point2D(1.5, -0.1),
-                new Point2D(3.1, 0.1),
-                new Point2D(3.1, Float.MAX_VALUE));
+                Point2D.of(-0.1, Float.MAX_VALUE),
+                Point2D.of(-0.1, 0.1),
+                Point2D.of(1.5, -0.1),
+                Point2D.of(3.1, 0.1),
+                Point2D.of(3.1, Float.MAX_VALUE));
         checkPoints(Region.Location.BOUNDARY, poly,
-                new Point2D(0, 1),
-                new Point2D(1, 0),
-                new Point2D(3, 1));
+                Point2D.of(0, 1),
+                Point2D.of(1, 0),
+                Point2D.of(3, 1));
     }
 
     @Test
@@ -369,42 +369,42 @@ public class PolygonsSetTest {
         Assert.assertEquals(8.0, box.getBoundarySize(), TEST_TOLERANCE);
         Assert.assertFalse(box.isEmpty());
         Assert.assertFalse(box.isFull());
-        EuclideanTestUtils.assertCoordinatesEqual(new Point2D(1, 0), box.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Point2D.of(1, 0), box.getBarycenter(), TEST_TOLERANCE);
 
         checkVertexLoopsEquivalent(new Point2D[][] {
             {
-                new Point2D(2, -1),
-                new Point2D(2, 1),
-                new Point2D(0, 1),
-                new Point2D(0, -1)
+                Point2D.of(2, -1),
+                Point2D.of(2, 1),
+                Point2D.of(0, 1),
+                Point2D.of(0, -1)
             }
         }, box.getVertices());
 
         checkPoints(Region.Location.INSIDE, box,
-                new Point2D(0.1, 0),
-                new Point2D(1.9, 0),
-                new Point2D(1, 0.9),
-                new Point2D(1, -0.9));
+                Point2D.of(0.1, 0),
+                Point2D.of(1.9, 0),
+                Point2D.of(1, 0.9),
+                Point2D.of(1, -0.9));
         checkPoints(Region.Location.OUTSIDE, box,
-                new Point2D(-0.1, 0),
-                new Point2D(2.1, 0),
-                new Point2D(1, -1.1),
-                new Point2D(1, 1.1));
+                Point2D.of(-0.1, 0),
+                Point2D.of(2.1, 0),
+                Point2D.of(1, -1.1),
+                Point2D.of(1, 1.1));
         checkPoints(Region.Location.BOUNDARY, box,
-                new Point2D(0, 0),
-                new Point2D(2, 0),
-                new Point2D(1, 1),
-                new Point2D(1, -1));
+                Point2D.of(0, 0),
+                Point2D.of(2, 0),
+                Point2D.of(1, 1),
+                Point2D.of(1, -1));
     }
 
     @Test
     public void testInvertedBox() {
         // arrange
         List<SubHyperplane<Point2D>> boundaries = new ArrayList<SubHyperplane<Point2D>>();
-        boundaries.add(buildSegment(new Point2D(0, -1), new Point2D(0, 1)));
-        boundaries.add(buildSegment(new Point2D(2, 1), new Point2D(2, -1)));
-        boundaries.add(buildSegment(new Point2D(0, 1), new Point2D(2, 1)));
-        boundaries.add(buildSegment(new Point2D(2, -1), new Point2D(0, -1)));
+        boundaries.add(buildSegment(Point2D.of(0, -1), Point2D.of(0, 1)));
+        boundaries.add(buildSegment(Point2D.of(2, 1), Point2D.of(2, -1)));
+        boundaries.add(buildSegment(Point2D.of(0, 1), Point2D.of(2, 1)));
+        boundaries.add(buildSegment(Point2D.of(2, -1), Point2D.of(0, -1)));
 
         // act
         PolygonsSet box = new PolygonsSet(boundaries, TEST_TOLERANCE);
@@ -418,28 +418,28 @@ public class PolygonsSetTest {
 
         checkVertexLoopsEquivalent(new Point2D[][] {
             {
-                new Point2D(0, -1),
-                new Point2D(0, 1),
-                new Point2D(2, 1),
-                new Point2D(2, -1)
+                Point2D.of(0, -1),
+                Point2D.of(0, 1),
+                Point2D.of(2, 1),
+                Point2D.of(2, -1)
             }
         }, box.getVertices());
 
         checkPoints(Region.Location.OUTSIDE, box,
-                new Point2D(0.1, 0),
-                new Point2D(1.9, 0),
-                new Point2D(1, 0.9),
-                new Point2D(1, -0.9));
+                Point2D.of(0.1, 0),
+                Point2D.of(1.9, 0),
+                Point2D.of(1, 0.9),
+                Point2D.of(1, -0.9));
         checkPoints(Region.Location.INSIDE, box,
-                new Point2D(-0.1, 0),
-                new Point2D(2.1, 0),
-                new Point2D(1, -1.1),
-                new Point2D(1, 1.1));
+                Point2D.of(-0.1, 0),
+                Point2D.of(2.1, 0),
+                Point2D.of(1, -1.1),
+                Point2D.of(1, 1.1));
         checkPoints(Region.Location.BOUNDARY, box,
-                new Point2D(0, 0),
-                new Point2D(2, 0),
-                new Point2D(1, 1),
-                new Point2D(1, -1));
+                Point2D.of(0, 0),
+                Point2D.of(2, 0),
+                Point2D.of(1, 1),
+                Point2D.of(1, -1));
     }
 
     @Test
@@ -447,16 +447,16 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices = new Point2D[][] {
             new Point2D[] {
-                new Point2D(36.0, 22.0),
-                new Point2D(39.0, 32.0),
-                new Point2D(19.0, 32.0),
-                new Point2D( 6.0, 16.0),
-                new Point2D(31.0, 10.0),
-                new Point2D(42.0, 16.0),
-                new Point2D(34.0, 20.0),
-                new Point2D(29.0, 19.0),
-                new Point2D(23.0, 22.0),
-                new Point2D(33.0, 25.0)
+                Point2D.of(36.0, 22.0),
+                Point2D.of(39.0, 32.0),
+                Point2D.of(19.0, 32.0),
+                Point2D.of( 6.0, 16.0),
+                Point2D.of(31.0, 10.0),
+                Point2D.of(42.0, 16.0),
+                Point2D.of(34.0, 20.0),
+                Point2D.of(29.0, 19.0),
+                Point2D.of(23.0, 22.0),
+                Point2D.of(33.0, 25.0)
             }
         };
 
@@ -465,22 +465,22 @@ public class PolygonsSetTest {
 
         // assert
         checkPoints(Region.Location.INSIDE, set,
-            new Point2D(30.0, 15.0),
-            new Point2D(15.0, 20.0),
-            new Point2D(24.0, 25.0),
-            new Point2D(35.0, 30.0),
-            new Point2D(19.0, 17.0));
+            Point2D.of(30.0, 15.0),
+            Point2D.of(15.0, 20.0),
+            Point2D.of(24.0, 25.0),
+            Point2D.of(35.0, 30.0),
+            Point2D.of(19.0, 17.0));
         checkPoints(Region.Location.OUTSIDE, set,
-            new Point2D(50.0, 30.0),
-            new Point2D(30.0, 35.0),
-            new Point2D(10.0, 25.0),
-            new Point2D(10.0, 10.0),
-            new Point2D(40.0, 10.0),
-            new Point2D(50.0, 15.0),
-            new Point2D(30.0, 22.0));
+            Point2D.of(50.0, 30.0),
+            Point2D.of(30.0, 35.0),
+            Point2D.of(10.0, 25.0),
+            Point2D.of(10.0, 10.0),
+            Point2D.of(40.0, 10.0),
+            Point2D.of(50.0, 15.0),
+            Point2D.of(30.0, 22.0));
         checkPoints(Region.Location.BOUNDARY, set,
-            new Point2D(30.0, 32.0),
-            new Point2D(34.0, 20.0));
+            Point2D.of(30.0, 32.0),
+            Point2D.of(34.0, 20.0));
 
         checkVertexLoopsEquivalent(vertices, set.getVertices());
     }
@@ -490,16 +490,16 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.0, 0.0),
-                new Point2D( 0.0, 2.0),
-                new Point2D(-0.1, 2.0),
-                new Point2D(-0.1, 1.0),
-                new Point2D(-0.3, 1.0),
-                new Point2D(-0.3, 1.5),
-                new Point2D(-1.3, 1.5),
-                new Point2D(-1.3, 2.0),
-                new Point2D(-1.8, 2.0),
-                new Point2D(-1.8 - 1.0 / Math.sqrt(2.0),
+                Point2D.of( 0.0, 0.0),
+                Point2D.of( 0.0, 2.0),
+                Point2D.of(-0.1, 2.0),
+                Point2D.of(-0.1, 1.0),
+                Point2D.of(-0.3, 1.0),
+                Point2D.of(-0.3, 1.5),
+                Point2D.of(-1.3, 1.5),
+                Point2D.of(-1.3, 2.0),
+                Point2D.of(-1.8, 2.0),
+                Point2D.of(-1.8 - 1.0 / Math.sqrt(2.0),
                             2.0 - 1.0 / Math.sqrt(2.0))
             }
         };
@@ -518,15 +518,15 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices = new Point2D[][] {
             new Point2D[] {
-                new Point2D(0.0, 0.0),
-                new Point2D(3.0, 0.0),
-                new Point2D(3.0, 3.0),
-                new Point2D(0.0, 3.0)
+                Point2D.of(0.0, 0.0),
+                Point2D.of(3.0, 0.0),
+                Point2D.of(3.0, 3.0),
+                Point2D.of(0.0, 3.0)
             }, new Point2D[] {
-                new Point2D(1.0, 2.0),
-                new Point2D(2.0, 2.0),
-                new Point2D(2.0, 1.0),
-                new Point2D(1.0, 1.0)
+                Point2D.of(1.0, 2.0),
+                Point2D.of(2.0, 2.0),
+                Point2D.of(2.0, 1.0),
+                Point2D.of(1.0, 1.0)
             }
         };
 
@@ -535,34 +535,34 @@ public class PolygonsSetTest {
 
         // assert
         checkPoints(Region.Location.INSIDE, set, new Point2D[] {
-            new Point2D(0.5, 0.5),
-            new Point2D(1.5, 0.5),
-            new Point2D(2.5, 0.5),
-            new Point2D(0.5, 1.5),
-            new Point2D(2.5, 1.5),
-            new Point2D(0.5, 2.5),
-            new Point2D(1.5, 2.5),
-            new Point2D(2.5, 2.5),
-            new Point2D(0.5, 1.0)
+            Point2D.of(0.5, 0.5),
+            Point2D.of(1.5, 0.5),
+            Point2D.of(2.5, 0.5),
+            Point2D.of(0.5, 1.5),
+            Point2D.of(2.5, 1.5),
+            Point2D.of(0.5, 2.5),
+            Point2D.of(1.5, 2.5),
+            Point2D.of(2.5, 2.5),
+            Point2D.of(0.5, 1.0)
         });
         checkPoints(Region.Location.OUTSIDE, set, new Point2D[] {
-            new Point2D(1.5, 1.5),
-            new Point2D(3.5, 1.0),
-            new Point2D(4.0, 1.5),
-            new Point2D(6.0, 6.0)
+            Point2D.of(1.5, 1.5),
+            Point2D.of(3.5, 1.0),
+            Point2D.of(4.0, 1.5),
+            Point2D.of(6.0, 6.0)
         });
         checkPoints(Region.Location.BOUNDARY, set, new Point2D[] {
-            new Point2D(1.0, 1.0),
-            new Point2D(1.5, 0.0),
-            new Point2D(1.5, 1.0),
-            new Point2D(1.5, 2.0),
-            new Point2D(1.5, 3.0),
-            new Point2D(3.0, 3.0)
+            Point2D.of(1.0, 1.0),
+            Point2D.of(1.5, 0.0),
+            Point2D.of(1.5, 1.0),
+            Point2D.of(1.5, 2.0),
+            Point2D.of(1.5, 3.0),
+            Point2D.of(3.0, 3.0)
         });
         checkVertexLoopsEquivalent(vertices, set.getVertices());
 
         for (double x = -0.999; x < 3.999; x += 0.11) {
-            Point2D v = new Point2D(x, x + 0.5);
+            Point2D v = Point2D.of(x, x + 0.5);
             BoundaryProjection<Point2D> projection = set.projectToBoundary(v);
             Assert.assertTrue(projection.getOriginal() == v);
             Point2D p = projection.getProjected();
@@ -589,7 +589,7 @@ public class PolygonsSetTest {
             } else {
                 Assert.assertEquals(3.0,      p.getX(), TEST_TOLERANCE);
                 Assert.assertEquals(3.0,      p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(+v.distance(new Point2D(3, 3)), projection.getOffset(), TEST_TOLERANCE);
+                Assert.assertEquals(+v.distance(Point2D.of(3, 3)), projection.getOffset(), TEST_TOLERANCE);
             }
         }
     }
@@ -599,13 +599,13 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices = new Point2D[][] {
             new Point2D[] {
-                new Point2D(0.0, 1.0),
-                new Point2D(2.0, 1.0),
-                new Point2D(1.0, 2.0)
+                Point2D.of(0.0, 1.0),
+                Point2D.of(2.0, 1.0),
+                Point2D.of(1.0, 2.0)
             }, new Point2D[] {
-                new Point2D(4.0, 0.0),
-                new Point2D(5.0, 1.0),
-                new Point2D(3.0, 1.0)
+                Point2D.of(4.0, 0.0),
+                Point2D.of(5.0, 1.0),
+                Point2D.of(3.0, 1.0)
             }
         };
 
@@ -613,21 +613,21 @@ public class PolygonsSetTest {
         PolygonsSet set = buildSet(vertices);
 
         // assert
-        Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Point2D(1.0, 1.5)));
+        Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(Point2D.of(1.0, 1.5)));
         checkPoints(Region.Location.INSIDE, set, new Point2D[] {
-            new Point2D(1.0, 1.5),
-            new Point2D(4.5, 0.8)
+            Point2D.of(1.0, 1.5),
+            Point2D.of(4.5, 0.8)
         });
         checkPoints(Region.Location.OUTSIDE, set, new Point2D[] {
-            new Point2D(1.0, 0.0),
-            new Point2D(3.5, 1.2),
-            new Point2D(2.5, 1.0),
-            new Point2D(3.0, 4.0)
+            Point2D.of(1.0, 0.0),
+            Point2D.of(3.5, 1.2),
+            Point2D.of(2.5, 1.0),
+            Point2D.of(3.0, 4.0)
         });
         checkPoints(Region.Location.BOUNDARY, set, new Point2D[] {
-            new Point2D(1.0, 1.0),
-            new Point2D(3.5, 0.5),
-            new Point2D(0.0, 1.0)
+            Point2D.of(1.0, 1.0),
+            Point2D.of(3.5, 0.5),
+            Point2D.of(0.0, 1.0)
         });
         checkVertexLoopsEquivalent(vertices, set.getVertices());
     }
@@ -637,12 +637,12 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices = new Point2D[][] {
             new Point2D[] {
-                new Point2D(1.0, 0.0),
-                new Point2D(2.0, 1.0),
-                new Point2D(3.0, 1.0),
-                new Point2D(2.0, 2.0),
-                new Point2D(1.0, 1.0),
-                new Point2D(0.0, 1.0)
+                Point2D.of(1.0, 0.0),
+                Point2D.of(2.0, 1.0),
+                Point2D.of(3.0, 1.0),
+                Point2D.of(2.0, 2.0),
+                Point2D.of(1.0, 1.0),
+                Point2D.of(0.0, 1.0)
             }
         };
 
@@ -658,14 +658,14 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.0,  0.0),
-                new Point2D( 1.0,  0.0),
-                new Point2D( 1.0,  1.0),
-                new Point2D( 0.0,  1.0),
-                new Point2D( 0.0,  0.0),
-                new Point2D(-1.0,  0.0),
-                new Point2D(-1.0, -1.0),
-                new Point2D( 0.0, -1.0)
+                Point2D.of( 0.0,  0.0),
+                Point2D.of( 1.0,  0.0),
+                Point2D.of( 1.0,  1.0),
+                Point2D.of( 0.0,  1.0),
+                Point2D.of( 0.0,  0.0),
+                Point2D.of(-1.0,  0.0),
+                Point2D.of(-1.0, -1.0),
+                Point2D.of( 0.0, -1.0)
             }
         };
 
@@ -675,16 +675,16 @@ public class PolygonsSetTest {
         // assert
         checkVertexLoopsEquivalent(new Point2D[][] {
             {
-                new Point2D( 0.0,  0.0),
-                new Point2D( 1.0,  0.0),
-                new Point2D( 1.0,  1.0),
-                new Point2D( 0.0,  1.0)
+                Point2D.of( 0.0,  0.0),
+                Point2D.of( 1.0,  0.0),
+                Point2D.of( 1.0,  1.0),
+                Point2D.of( 0.0,  1.0)
             },
             {
-                new Point2D( 0.0,  0.0),
-                new Point2D(-1.0,  0.0),
-                new Point2D(-1.0, -1.0),
-                new Point2D( 0.0, -1.0)
+                Point2D.of( 0.0,  0.0),
+                Point2D.of(-1.0,  0.0),
+                Point2D.of(-1.0, -1.0),
+                Point2D.of( 0.0, -1.0)
             }
         }, set.getVertices());
     }
@@ -694,14 +694,14 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.0,  0.0),
-                new Point2D( 2.0,  0.0),
-                new Point2D( 2.0,  1.0),
-                new Point2D( 3.0,  1.0),
-                new Point2D( 3.0,  3.0),
-                new Point2D( 1.0,  3.0),
-                new Point2D( 1.0,  2.0),
-                new Point2D( 0.0,  2.0)
+                Point2D.of( 0.0,  0.0),
+                Point2D.of( 2.0,  0.0),
+                Point2D.of( 2.0,  1.0),
+                Point2D.of( 3.0,  1.0),
+                Point2D.of( 3.0,  3.0),
+                Point2D.of( 1.0,  3.0),
+                Point2D.of( 1.0,  2.0),
+                Point2D.of( 0.0,  2.0)
             }
         };
 
@@ -709,34 +709,34 @@ public class PolygonsSetTest {
         PolygonsSet set = buildSet(vertices);
 
         // assert
-        Line l1 = new Line(new Point2D(-1.5, 0.0), Math.PI / 4, TEST_TOLERANCE);
+        Line l1 = new Line(Point2D.of(-1.5, 0.0), Math.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);
-        Point2D p10Lower = l1.toSpace(new Point1D(v10.getInf()));
+        Point2D p10Lower = l1.toSpace(Point1D.of(v10.getInf()));
         Assert.assertEquals(0.0, p10Lower.getX(), TEST_TOLERANCE);
         Assert.assertEquals(1.5, p10Lower.getY(), TEST_TOLERANCE);
-        Point2D p10Upper = l1.toSpace(new Point1D(v10.getSup()));
+        Point2D p10Upper = l1.toSpace(Point1D.of(v10.getSup()));
         Assert.assertEquals(0.5, p10Upper.getX(), TEST_TOLERANCE);
         Assert.assertEquals(2.0, p10Upper.getY(), TEST_TOLERANCE);
         Interval v11 = i1.get(1);
-        Point2D p11Lower = l1.toSpace(new Point1D(v11.getInf()));
+        Point2D p11Lower = l1.toSpace(Point1D.of(v11.getInf()));
         Assert.assertEquals(1.0, p11Lower.getX(), TEST_TOLERANCE);
         Assert.assertEquals(2.5, p11Lower.getY(), TEST_TOLERANCE);
-        Point2D p11Upper = l1.toSpace(new Point1D(v11.getSup()));
+        Point2D p11Upper = l1.toSpace(Point1D.of(v11.getSup()));
         Assert.assertEquals(1.5, p11Upper.getX(), TEST_TOLERANCE);
         Assert.assertEquals(3.0, p11Upper.getY(), TEST_TOLERANCE);
 
-        Line l2 = new Line(new Point2D(-1.0, 2.0), 0, TEST_TOLERANCE);
+        Line l2 = new Line(Point2D.of(-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);
-        Point2D p20Lower = l2.toSpace(new Point1D(v20.getInf()));
+        Point2D p20Lower = l2.toSpace(Point1D.of(v20.getInf()));
         Assert.assertEquals(1.0, p20Lower.getX(), TEST_TOLERANCE);
         Assert.assertEquals(2.0, p20Lower.getY(), TEST_TOLERANCE);
-        Point2D p20Upper = l2.toSpace(new Point1D(v20.getSup()));
+        Point2D p20Upper = l2.toSpace(Point1D.of(v20.getSup()));
         Assert.assertEquals(3.0, p20Upper.getX(), TEST_TOLERANCE);
         Assert.assertEquals(2.0, p20Upper.getY(), TEST_TOLERANCE);
     }
@@ -746,18 +746,18 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices1 = new Point2D[][] {
             new Point2D[] {
-                new Point2D(0.0, 0.0),
-                new Point2D(4.0, 0.0),
-                new Point2D(1.4, 1.5),
-                new Point2D(0.0, 3.5)
+                Point2D.of(0.0, 0.0),
+                Point2D.of(4.0, 0.0),
+                Point2D.of(1.4, 1.5),
+                Point2D.of(0.0, 3.5)
             }
         };
         PolygonsSet set1 = buildSet(vertices1);
         Point2D[][] vertices2 = new Point2D[][] {
             new Point2D[] {
-                new Point2D(1.4,  0.2),
-                new Point2D(2.8, -1.2),
-                new Point2D(2.5,  0.6)
+                Point2D.of(1.4,  0.2),
+                Point2D.of(2.8, -1.2),
+                Point2D.of(2.5,  0.6)
             }
         };
         PolygonsSet set2 = buildSet(vertices2);
@@ -772,13 +772,13 @@ public class PolygonsSetTest {
         checkVertexLoopsEquivalent(vertices2, set2.getVertices());
         checkVertexLoopsEquivalent(new Point2D[][] {
             new Point2D[] {
-                new Point2D(0.0,  0.0),
-                new Point2D(1.6,  0.0),
-                new Point2D(2.8, -1.2),
-                new Point2D(2.6,  0.0),
-                new Point2D(4.0,  0.0),
-                new Point2D(1.4,  1.5),
-                new Point2D(0.0,  3.5)
+                Point2D.of(0.0,  0.0),
+                Point2D.of(1.6,  0.0),
+                Point2D.of(2.8, -1.2),
+                Point2D.of(2.6,  0.0),
+                Point2D.of(4.0,  0.0),
+                Point2D.of(1.4,  1.5),
+                Point2D.of(0.0,  3.5)
             }
         }, set.getVertices());
     }
@@ -788,19 +788,19 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices1 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.0,  0.0),
-                new Point2D( 2.0,  0.0),
-                new Point2D( 2.0,  2.0),
-                new Point2D( 0.0,  2.0)
+                Point2D.of( 0.0,  0.0),
+                Point2D.of( 2.0,  0.0),
+                Point2D.of( 2.0,  2.0),
+                Point2D.of( 0.0,  2.0)
             }
         };
         PolygonsSet set1 = buildSet(vertices1);
         Point2D[][] vertices2 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 1.0,  1.0),
-                new Point2D( 3.0,  1.0),
-                new Point2D( 3.0,  3.0),
-                new Point2D( 1.0,  3.0)
+                Point2D.of( 1.0,  1.0),
+                Point2D.of( 3.0,  1.0),
+                Point2D.of( 3.0,  3.0),
+                Point2D.of( 1.0,  3.0)
             }
         };
         PolygonsSet set2 = buildSet(vertices2);
@@ -814,41 +814,41 @@ public class PolygonsSetTest {
         checkVertexLoopsEquivalent(vertices2, set2.getVertices());
         checkVertexLoopsEquivalent(new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.0,  0.0),
-                new Point2D( 2.0,  0.0),
-                new Point2D( 2.0,  1.0),
-                new Point2D( 3.0,  1.0),
-                new Point2D( 3.0,  3.0),
-                new Point2D( 1.0,  3.0),
-                new Point2D( 1.0,  2.0),
-                new Point2D( 0.0,  2.0)
+                Point2D.of( 0.0,  0.0),
+                Point2D.of( 2.0,  0.0),
+                Point2D.of( 2.0,  1.0),
+                Point2D.of( 3.0,  1.0),
+                Point2D.of( 3.0,  3.0),
+                Point2D.of( 1.0,  3.0),
+                Point2D.of( 1.0,  2.0),
+                Point2D.of( 0.0,  2.0)
             }
         }, set.getVertices());
 
         checkPoints(Region.Location.INSIDE, set, new Point2D[] {
-            new Point2D(1.0, 1.0),
-            new Point2D(0.5, 0.5),
-            new Point2D(2.0, 2.0),
-            new Point2D(2.5, 2.5),
-            new Point2D(0.5, 1.5),
-            new Point2D(1.5, 1.5),
-            new Point2D(1.5, 0.5),
-            new Point2D(1.5, 2.5),
-            new Point2D(2.5, 1.5),
-            new Point2D(2.5, 2.5)
+            Point2D.of(1.0, 1.0),
+            Point2D.of(0.5, 0.5),
+            Point2D.of(2.0, 2.0),
+            Point2D.of(2.5, 2.5),
+            Point2D.of(0.5, 1.5),
+            Point2D.of(1.5, 1.5),
+            Point2D.of(1.5, 0.5),
+            Point2D.of(1.5, 2.5),
+            Point2D.of(2.5, 1.5),
+            Point2D.of(2.5, 2.5)
         });
         checkPoints(Region.Location.OUTSIDE, set, new Point2D[] {
-            new Point2D(-0.5, 0.5),
-            new Point2D( 0.5, 2.5),
-            new Point2D( 2.5, 0.5),
-            new Point2D( 3.5, 2.5)
+            Point2D.of(-0.5, 0.5),
+            Point2D.of( 0.5, 2.5),
+            Point2D.of( 2.5, 0.5),
+            Point2D.of( 3.5, 2.5)
         });
         checkPoints(Region.Location.BOUNDARY, set, new Point2D[] {
-            new Point2D(0.0, 0.0),
-            new Point2D(0.5, 2.0),
-            new Point2D(2.0, 0.5),
-            new Point2D(2.5, 1.0),
-            new Point2D(3.0, 2.5)
+            Point2D.of(0.0, 0.0),
+            Point2D.of(0.5, 2.0),
+            Point2D.of(2.0, 0.5),
+            Point2D.of(2.5, 1.0),
+            Point2D.of(3.0, 2.5)
         });
     }
 
@@ -857,19 +857,19 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices1 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.0,  0.0),
-                new Point2D( 2.0,  0.0),
-                new Point2D( 2.0,  2.0),
-                new Point2D( 0.0,  2.0)
+                Point2D.of( 0.0,  0.0),
+                Point2D.of( 2.0,  0.0),
+                Point2D.of( 2.0,  2.0),
+                Point2D.of( 0.0,  2.0)
             }
         };
         PolygonsSet set1 = buildSet(vertices1);
         Point2D[][] vertices2 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 1.0,  1.0),
-                new Point2D( 3.0,  1.0),
-                new Point2D( 3.0,  3.0),
-                new Point2D( 1.0,  3.0)
+                Point2D.of( 1.0,  1.0),
+                Point2D.of( 3.0,  1.0),
+                Point2D.of( 3.0,  3.0),
+                Point2D.of( 1.0,  3.0)
             }
         };
         PolygonsSet set2 = buildSet(vertices2);
@@ -883,27 +883,27 @@ public class PolygonsSetTest {
         checkVertexLoopsEquivalent(vertices2, set2.getVertices());
         checkVertexLoopsEquivalent(new Point2D[][] {
             new Point2D[] {
-                new Point2D( 1.0,  1.0),
-                new Point2D( 2.0,  1.0),
-                new Point2D( 2.0,  2.0),
-                new Point2D( 1.0,  2.0)
+                Point2D.of( 1.0,  1.0),
+                Point2D.of( 2.0,  1.0),
+                Point2D.of( 2.0,  2.0),
+                Point2D.of( 1.0,  2.0)
             }
         }, set.getVertices());
 
         checkPoints(Region.Location.INSIDE, set, new Point2D[] {
-            new Point2D(1.5, 1.5)
+            Point2D.of(1.5, 1.5)
         });
         checkPoints(Region.Location.OUTSIDE, set, new Point2D[] {
-            new Point2D(0.5, 1.5),
-            new Point2D(2.5, 1.5),
-            new Point2D(1.5, 0.5),
-            new Point2D(0.5, 0.5)
+            Point2D.of(0.5, 1.5),
+            Point2D.of(2.5, 1.5),
+            Point2D.of(1.5, 0.5),
+            Point2D.of(0.5, 0.5)
         });
         checkPoints(Region.Location.BOUNDARY, set, new Point2D[] {
-            new Point2D(1.0, 1.0),
-            new Point2D(2.0, 2.0),
-            new Point2D(1.0, 1.5),
-            new Point2D(1.5, 2.0)
+            Point2D.of(1.0, 1.0),
+            Point2D.of(2.0, 2.0),
+            Point2D.of(1.0, 1.5),
+            Point2D.of(1.5, 2.0)
         });
     }
 
@@ -912,19 +912,19 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices1 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.0,  0.0),
-                new Point2D( 2.0,  0.0),
-                new Point2D( 2.0,  2.0),
-                new Point2D( 0.0,  2.0)
+                Point2D.of( 0.0,  0.0),
+                Point2D.of( 2.0,  0.0),
+                Point2D.of( 2.0,  2.0),
+                Point2D.of( 0.0,  2.0)
             }
         };
         PolygonsSet set1 = buildSet(vertices1);
         Point2D[][] vertices2 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 1.0,  1.0),
-                new Point2D( 3.0,  1.0),
-                new Point2D( 3.0,  3.0),
-                new Point2D( 1.0,  3.0)
+                Point2D.of( 1.0,  1.0),
+                Point2D.of( 3.0,  1.0),
+                Point2D.of( 3.0,  3.0),
+                Point2D.of( 1.0,  3.0)
             }
         };
         PolygonsSet set2 = buildSet(vertices2);
@@ -938,49 +938,49 @@ public class PolygonsSetTest {
         checkVertexLoopsEquivalent(vertices2, set2.getVertices());
         checkVertexLoopsEquivalent(new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.0,  0.0),
-                new Point2D( 2.0,  0.0),
-                new Point2D( 2.0,  1.0),
-                new Point2D( 3.0,  1.0),
-                new Point2D( 3.0,  3.0),
-                new Point2D( 1.0,  3.0),
-                new Point2D( 1.0,  2.0),
-                new Point2D( 0.0,  2.0)
+                Point2D.of( 0.0,  0.0),
+                Point2D.of( 2.0,  0.0),
+                Point2D.of( 2.0,  1.0),
+                Point2D.of( 3.0,  1.0),
+                Point2D.of( 3.0,  3.0),
+                Point2D.of( 1.0,  3.0),
+                Point2D.of( 1.0,  2.0),
+                Point2D.of( 0.0,  2.0)
             },
             new Point2D[] {
-                new Point2D( 1.0,  1.0),
-                new Point2D( 1.0,  2.0),
-                new Point2D( 2.0,  2.0),
-                new Point2D( 2.0,  1.0)
+                Point2D.of( 1.0,  1.0),
+                Point2D.of( 1.0,  2.0),
+                Point2D.of( 2.0,  2.0),
+                Point2D.of( 2.0,  1.0)
             }
         }, set.getVertices());
 
         checkPoints(Region.Location.INSIDE, set, new Point2D[] {
-            new Point2D(0.5, 0.5),
-            new Point2D(2.5, 2.5),
-            new Point2D(0.5, 1.5),
-            new Point2D(1.5, 0.5),
-            new Point2D(1.5, 2.5),
-            new Point2D(2.5, 1.5),
-            new Point2D(2.5, 2.5)
+            Point2D.of(0.5, 0.5),
+            Point2D.of(2.5, 2.5),
+            Point2D.of(0.5, 1.5),
+            Point2D.of(1.5, 0.5),
+            Point2D.of(1.5, 2.5),
+            Point2D.of(2.5, 1.5),
+            Point2D.of(2.5, 2.5)
         });
         checkPoints(Region.Location.OUTSIDE, set, new Point2D[] {
-            new Point2D(-0.5, 0.5),
-            new Point2D( 0.5, 2.5),
-            new Point2D( 2.5, 0.5),
-            new Point2D( 1.5, 1.5),
-            new Point2D( 3.5, 2.5)
+            Point2D.of(-0.5, 0.5),
+            Point2D.of( 0.5, 2.5),
+            Point2D.of( 2.5, 0.5),
+            Point2D.of( 1.5, 1.5),
+            Point2D.of( 3.5, 2.5)
         });
         checkPoints(Region.Location.BOUNDARY, set, new Point2D[] {
-            new Point2D(1.0, 1.0),
-            new Point2D(2.0, 2.0),
-            new Point2D(1.5, 1.0),
-            new Point2D(2.0, 1.5),
-            new Point2D(0.0, 0.0),
-            new Point2D(0.5, 2.0),
-            new Point2D(2.0, 0.5),
-            new Point2D(2.5, 1.0),
-            new Point2D(3.0, 2.5)
+            Point2D.of(1.0, 1.0),
+            Point2D.of(2.0, 2.0),
+            Point2D.of(1.5, 1.0),
+            Point2D.of(2.0, 1.5),
+            Point2D.of(0.0, 0.0),
+            Point2D.of(0.5, 2.0),
+            Point2D.of(2.0, 0.5),
+            Point2D.of(2.5, 1.0),
+            Point2D.of(3.0, 2.5)
         });
     }
 
@@ -989,19 +989,19 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices1 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.0,  0.0),
-                new Point2D( 2.0,  0.0),
-                new Point2D( 2.0,  2.0),
-                new Point2D( 0.0,  2.0)
+                Point2D.of( 0.0,  0.0),
+                Point2D.of( 2.0,  0.0),
+                Point2D.of( 2.0,  2.0),
+                Point2D.of( 0.0,  2.0)
             }
         };
         PolygonsSet set1 = buildSet(vertices1);
         Point2D[][] vertices2 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 1.0,  1.0),
-                new Point2D( 3.0,  1.0),
-                new Point2D( 3.0,  3.0),
-                new Point2D( 1.0,  3.0)
+                Point2D.of( 1.0,  1.0),
+                Point2D.of( 3.0,  1.0),
+                Point2D.of( 3.0,  3.0),
+                Point2D.of( 1.0,  3.0)
             }
         };
         PolygonsSet set2 = buildSet(vertices2);
@@ -1015,41 +1015,41 @@ public class PolygonsSetTest {
         checkVertexLoopsEquivalent(vertices2, set2.getVertices());
         checkVertexLoopsEquivalent(new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.0,  0.0),
-                new Point2D( 2.0,  0.0),
-                new Point2D( 2.0,  1.0),
-                new Point2D( 1.0,  1.0),
-                new Point2D( 1.0,  2.0),
-                new Point2D( 0.0,  2.0)
+                Point2D.of( 0.0,  0.0),
+                Point2D.of( 2.0,  0.0),
+                Point2D.of( 2.0,  1.0),
+                Point2D.of( 1.0,  1.0),
+                Point2D.of( 1.0,  2.0),
+                Point2D.of( 0.0,  2.0)
             }
         }, set.getVertices());
 
         checkPoints(Region.Location.INSIDE, set, new Point2D[] {
-            new Point2D(0.5, 0.5),
-            new Point2D(0.5, 1.5),
-            new Point2D(1.5, 0.5)
+            Point2D.of(0.5, 0.5),
+            Point2D.of(0.5, 1.5),
+            Point2D.of(1.5, 0.5)
         });
         checkPoints(Region.Location.OUTSIDE, set, new Point2D[] {
-            new Point2D( 2.5, 2.5),
-            new Point2D(-0.5, 0.5),
-            new Point2D( 0.5, 2.5),
-            new Point2D( 2.5, 0.5),
-            new Point2D( 1.5, 1.5),
-            new Point2D( 3.5, 2.5),
-            new Point2D( 1.5, 2.5),
-            new Point2D( 2.5, 1.5),
-            new Point2D( 2.0, 1.5),
-            new Point2D( 2.0, 2.0),
-            new Point2D( 2.5, 1.0),
-            new Point2D( 2.5, 2.5),
-            new Point2D( 3.0, 2.5)
+            Point2D.of( 2.5, 2.5),
+            Point2D.of(-0.5, 0.5),
+            Point2D.of( 0.5, 2.5),
+            Point2D.of( 2.5, 0.5),
+            Point2D.of( 1.5, 1.5),
+            Point2D.of( 3.5, 2.5),
+            Point2D.of( 1.5, 2.5),
+            Point2D.of( 2.5, 1.5),
+            Point2D.of( 2.0, 1.5),
+            Point2D.of( 2.0, 2.0),
+            Point2D.of( 2.5, 1.0),
+            Point2D.of( 2.5, 2.5),
+            Point2D.of( 3.0, 2.5)
         });
         checkPoints(Region.Location.BOUNDARY, set, new Point2D[] {
-            new Point2D(1.0, 1.0),
-            new Point2D(1.5, 1.0),
-            new Point2D(0.0, 0.0),
-            new Point2D(0.5, 2.0),
-            new Point2D(2.0, 0.5)
+            Point2D.of(1.0, 1.0),
+            Point2D.of(1.5, 1.0),
+            Point2D.of(0.0, 0.0),
+            Point2D.of(0.5, 2.0),
+            Point2D.of(2.0, 0.5)
         });
     }
 
@@ -1058,19 +1058,19 @@ public class PolygonsSetTest {
         // arrange
         Point2D[][] vertices1 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.5, 3.5),
-                new Point2D( 0.5, 4.5),
-                new Point2D(-0.5, 4.5),
-                new Point2D(-0.5, 3.5)
+                Point2D.of( 0.5, 3.5),
+                Point2D.of( 0.5, 4.5),
+                Point2D.of(-0.5, 4.5),
+                Point2D.of(-0.5, 3.5)
             }
         };
         PolygonsSet set1 = buildSet(vertices1);
         Point2D[][] vertices2 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 1.0, 2.0),
-                new Point2D( 1.0, 8.0),
-                new Point2D(-1.0, 8.0),
-                new Point2D(-1.0, 2.0)
+                Point2D.of( 1.0, 2.0),
+                Point2D.of( 1.0, 8.0),
+                Point2D.of(-1.0, 8.0),
+                Point2D.of(-1.0, 2.0)
             }
         };
         PolygonsSet set2 = buildSet(vertices2);
@@ -1089,13 +1089,13 @@ public class PolygonsSetTest {
         double pi6   = Math.PI / 6.0;
         double sqrt3 = Math.sqrt(3.0);
         SubLine[] hyp = {
-            new Line(new Point2D(   0.0, 1.0),  5 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Point2D(-sqrt3, 1.0),  7 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Point2D(-sqrt3, 1.0),  9 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Point2D(-sqrt3, 0.0), 11 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Point2D(   0.0, 0.0), 13 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Point2D(   0.0, 1.0),  3 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(new Point2D(-5.0 * sqrt3 / 6.0, 0.0), 9 * pi6, TEST_TOLERANCE).wholeHyperplane()
+            new Line(Point2D.of(   0.0, 1.0),  5 * pi6, TEST_TOLERANCE).wholeHyperplane(),
+            new Line(Point2D.of(-sqrt3, 1.0),  7 * pi6, TEST_TOLERANCE).wholeHyperplane(),
+            new Line(Point2D.of(-sqrt3, 1.0),  9 * pi6, TEST_TOLERANCE).wholeHyperplane(),
+            new Line(Point2D.of(-sqrt3, 0.0), 11 * pi6, TEST_TOLERANCE).wholeHyperplane(),
+            new Line(Point2D.of(   0.0, 0.0), 13 * pi6, TEST_TOLERANCE).wholeHyperplane(),
+            new Line(Point2D.of(   0.0, 1.0),  3 * pi6, TEST_TOLERANCE).wholeHyperplane(),
+            new Line(Point2D.of(-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();
@@ -1109,7 +1109,7 @@ public class PolygonsSetTest {
         }
         PolygonsSet set = new PolygonsSet(tree, TEST_TOLERANCE);
         SubLine splitter =
-            new Line(new Point2D(-2.0 * sqrt3 / 3.0, 0.0), 9 * pi6, TEST_TOLERANCE).wholeHyperplane();
+            new Line(Point2D.of(-2.0 * sqrt3 / 3.0, 0.0), 9 * pi6, TEST_TOLERANCE).wholeHyperplane();
 
         // act
         PolygonsSet slice =
@@ -1120,7 +1120,7 @@ public class PolygonsSetTest {
 
         // assert
         Assert.assertEquals(Region.Location.OUTSIDE,
-                            slice.checkPoint(new Point2D(0.1, 0.5)));
+                            slice.checkPoint(Point2D.of(0.1, 0.5)));
         Assert.assertEquals(11.0 / 3.0, slice.getBoundarySize(), TEST_TOLERANCE);
     }
 
@@ -1130,25 +1130,25 @@ public class PolygonsSetTest {
         double h = Math.sqrt(3.0) / 2.0;
         Point2D[][] vertices1 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.00, 0.1 * h),
-                new Point2D( 0.05, 0.1 * h),
-                new Point2D( 0.10, 0.2 * h),
-                new Point2D( 0.05, 0.3 * h),
-                new Point2D(-0.05, 0.3 * h),
-                new Point2D(-0.10, 0.2 * h),
-                new Point2D(-0.05, 0.1 * h)
+                Point2D.of( 0.00, 0.1 * h),
+                Point2D.of( 0.05, 0.1 * h),
+                Point2D.of( 0.10, 0.2 * h),
+                Point2D.of( 0.05, 0.3 * h),
+                Point2D.of(-0.05, 0.3 * h),
+                Point2D.of(-0.10, 0.2 * h),
+                Point2D.of(-0.05, 0.1 * h)
             }
         };
         PolygonsSet set1 = buildSet(vertices1);
         Point2D[][] vertices2 = new Point2D[][] {
             new Point2D[] {
-                new Point2D( 0.00, 0.0 * h),
-                new Point2D( 0.10, 0.0 * h),
-                new Point2D( 0.20, 0.2 * h),
-                new Point2D( 0.10, 0.4 * h),
-                new Point2D(-0.10, 0.4 * h),
-                new Point2D(-0.20, 0.2 * h),
-                new Point2D(-0.10, 0.0 * h)
+                Point2D.of( 0.00, 0.0 * h),
+                Point2D.of( 0.10, 0.0 * h),
+                Point2D.of( 0.20, 0.2 * h),
+                Point2D.of( 0.10, 0.4 * h),
+                Point2D.of(-0.10, 0.4 * h),
+                Point2D.of(-0.20, 0.2 * h),
+                Point2D.of(-0.10, 0.0 * h)
             }
         };
         PolygonsSet set2 = buildSet(vertices2);
@@ -1161,86 +1161,86 @@ public class PolygonsSetTest {
     public void testBug20040520() {
         // arrange
         BSPTree<Point2D> a0 =
-            new BSPTree<>(buildSegment(new Point2D(0.85, -0.05),
-                                                  new Point2D(0.90, -0.10)),
+            new BSPTree<>(buildSegment(Point2D.of(0.85, -0.05),
+                                                  Point2D.of(0.90, -0.10)),
                                                   new BSPTree<Point2D>(Boolean.FALSE),
                                                   new BSPTree<Point2D>(Boolean.TRUE),
                                                   null);
         BSPTree<Point2D> a1 =
-            new BSPTree<>(buildSegment(new Point2D(0.85, -0.10),
-                                                  new Point2D(0.90, -0.10)),
+            new BSPTree<>(buildSegment(Point2D.of(0.85, -0.10),
+                                                  Point2D.of(0.90, -0.10)),
                                                   new BSPTree<Point2D>(Boolean.FALSE), a0, null);
         BSPTree<Point2D> a2 =
-            new BSPTree<>(buildSegment(new Point2D(0.90, -0.05),
-                                                  new Point2D(0.85, -0.05)),
+            new BSPTree<>(buildSegment(Point2D.of(0.90, -0.05),
+                                                  Point2D.of(0.85, -0.05)),
                                                   new BSPTree<Point2D>(Boolean.FALSE), a1, null);
         BSPTree<Point2D> a3 =
-            new BSPTree<>(buildSegment(new Point2D(0.82, -0.05),
-                                                  new Point2D(0.82, -0.08)),
+            new BSPTree<>(buildSegment(Point2D.of(0.82, -0.05),
+                                                  Point2D.of(0.82, -0.08)),
                                                   new BSPTree<Point2D>(Boolean.FALSE),
                                                   new BSPTree<Point2D>(Boolean.TRUE),
                                                   null);
         BSPTree<Point2D> a4 =
-            new BSPTree<>(buildHalfLine(new Point2D(0.85, -0.05),
-                                                   new Point2D(0.80, -0.05),
+            new BSPTree<>(buildHalfLine(Point2D.of(0.85, -0.05),
+                                                   Point2D.of(0.80, -0.05),
                                                    false),
                                                    new BSPTree<Point2D>(Boolean.FALSE), a3, null);
         BSPTree<Point2D> a5 =
-            new BSPTree<>(buildSegment(new Point2D(0.82, -0.08),
-                                                  new Point2D(0.82, -0.18)),
+            new BSPTree<>(buildSegment(Point2D.of(0.82, -0.08),
+                                                  Point2D.of(0.82, -0.18)),
                                                   new BSPTree<Point2D>(Boolean.FALSE),
                                                   new BSPTree<Point2D>(Boolean.TRUE),
                                                   null);
         BSPTree<Point2D> a6 =
-            new BSPTree<>(buildHalfLine(new Point2D(0.82, -0.18),
-                                                   new Point2D(0.85, -0.15),
+            new BSPTree<>(buildHalfLine(Point2D.of(0.82, -0.18),
+                                                   Point2D.of(0.85, -0.15),
                                                    true),
                                                    new BSPTree<Point2D>(Boolean.FALSE), a5, null);
         BSPTree<Point2D> a7 =
-            new BSPTree<>(buildHalfLine(new Point2D(0.85, -0.05),
-                                                   new Point2D(0.82, -0.08),
+            new BSPTree<>(buildHalfLine(Point2D.of(0.85, -0.05),
+                                                   Point2D.of(0.82, -0.08),
                                                    false),
                                                    a4, a6, null);
         BSPTree<Point2D> a8 =
-            new BSPTree<>(buildLine(new Point2D(0.85, -0.25),
-                                               new Point2D(0.85,  0.05)),
+            new BSPTree<>(buildLine(Point2D.of(0.85, -0.25),
+                                               Point2D.of(0.85,  0.05)),
                                                a2, a7, null);
         BSPTree<Point2D> a9 =
-            new BSPTree<>(buildLine(new Point2D(0.90,  0.05),
-                                               new Point2D(0.90, -0.50)),
+            new BSPTree<>(buildLine(Point2D.of(0.90,  0.05),
+                                               Point2D.of(0.90, -0.50)),
                                                a8, new BSPTree<Point2D>(Boolean.FALSE), null);
 
         BSPTree<Point2D> b0 =
-            new BSPTree<>(buildSegment(new Point2D(0.92, -0.12),
-                                                  new Point2D(0.92, -0.08)),
+            new BSPTree<>(buildSegment(Point2D.of(0.92, -0.12),
+                                                  Point2D.of(0.92, -0.08)),
                                                   new BSPTree<Point2D>(Boolean.FALSE), new BSPTree<Point2D>(Boolean.TRUE),
                                                   null);
         BSPTree<Point2D> b1 =
-            new BSPTree<>(buildHalfLine(new Point2D(0.92, -0.08),
-                                                   new Point2D(0.90, -0.10),
+            new BSPTree<>(buildHalfLine(Point2D.of(0.92, -0.08),
+                                                   Point2D.of(0.90, -0.10),
                                                    true),
                                                    new BSPTree<Point2D>(Boolean.FALSE), b0, null);
         BSPTree<Point2D> b2 =
-            new BSPTree<>(buildSegment(new Point2D(0.92, -0.18),
-                                                  new Point2D(0.92, -0.12)),
+            new BSPTree<>(buildSegment(Point2D.of(0.92, -0.18),
+                                                  Point2D.of(0.92, -0.12)),
                                                   new BSPTree<Point2D>(Boolean.FALSE), new BSPTree<Point2D>(Boolean.TRUE),
                                                   null);
         BSPTree<Point2D> b3 =
-            new BSPTree<>(buildSegment(new Point2D(0.85, -0.15),
-                                                  new Point2D(0.90, -0.20)),
+            new BSPTree<>(buildSegment(Point2D.of(0.85, -0.15),
+                                                  Point2D.of(0.90, -0.20)),
                                                   new BSPTree<Point2D>(Boolean.FALSE), b2, null);
         BSPTree<Point2D> b4 =
-            new BSPTree<>(buildSegment(new Point2D(0.95, -0.15),
-                                                  new Point2D(0.85, -0.05)),
+            new BSPTree<>(buildSegment(Point2D.of(0.95, -0.15),
+                                                  Point2D.of(0.85, -0.05)),
                                                   b1, b3, null);
         BSPTree<Point2D> b5 =
-            new BSPTree<>(buildHalfLine(new Point2D(0.85, -0.05),
-                                                   new Point2D(0.85, -0.25),
+            new BSPTree<>(buildHalfLine(Point2D.of(0.85, -0.05),
+                                                   Point2D.of(0.85, -0.25),
                                                    true),
                                                    new BSPTree<Point2D>(Boolean.FALSE), b4, null);
         BSPTree<Point2D> b6 =
-            new BSPTree<>(buildLine(new Point2D(0.0, -1.10),
-                                               new Point2D(1.0, -0.10)),
+            new BSPTree<>(buildLine(Point2D.of(0.0, -1.10),
+                                               Point2D.of(1.0, -0.10)),
                                                new BSPTree<Point2D>(Boolean.FALSE), b5, null);
 
         // act
@@ -1250,38 +1250,38 @@ public class PolygonsSetTest {
 
         // assert
         checkPoints(Region.Location.INSIDE, c, new Point2D[] {
-            new Point2D(0.83, -0.06),
-            new Point2D(0.83, -0.15),
-            new Point2D(0.88, -0.15),
-            new Point2D(0.88, -0.09),
-            new Point2D(0.88, -0.07),
-            new Point2D(0.91, -0.18),
-            new Point2D(0.91, -0.10)
+            Point2D.of(0.83, -0.06),
+            Point2D.of(0.83, -0.15),
+            Point2D.of(0.88, -0.15),
+            Point2D.of(0.88, -0.09),
+            Point2D.of(0.88, -0.07),
+            Point2D.of(0.91, -0.18),
+            Point2D.of(0.91, -0.10)
         });
 
         checkPoints(Region.Location.OUTSIDE, c, new Point2D[] {
-            new Point2D(0.80, -0.10),
-            new Point2D(0.83, -0.50),
-            new Point2D(0.83, -0.20),
-            new Point2D(0.83, -0.02),
-            new Point2D(0.87, -0.50),
-            new Point2D(0.87, -0.20),
-            new Point2D(0.87, -0.02),
-            new Point2D(0.91, -0.20),
-            new Point2D(0.91, -0.08),
-            new Point2D(0.93, -0.15)
+            Point2D.of(0.80, -0.10),
+            Point2D.of(0.83, -0.50),
+            Point2D.of(0.83, -0.20),
+            Point2D.of(0.83, -0.02),
+            Point2D.of(0.87, -0.50),
+            Point2D.of(0.87, -0.20),
+            Point2D.of(0.87, -0.02),
+            Point2D.of(0.91, -0.20),
+            Point2D.of(0.91, -0.08),
+            Point2D.of(0.93, -0.15)
         });
 
         checkVertexLoopsEquivalent(new Point2D[][] {
             new Point2D[] {
-                new Point2D(0.85, -0.15),
-                new Point2D(0.90, -0.20),
-                new Point2D(0.92, -0.18),
-                new Point2D(0.92, -0.08),
-                new Point2D(0.90, -0.10),
-                new Point2D(0.90, -0.05),
-                new Point2D(0.82, -0.05),
-                new Point2D(0.82, -0.18),
+                Point2D.of(0.85, -0.15),
+                Point2D.of(0.90, -0.20),
+                Point2D.of(0.92, -0.18),
+                Point2D.of(0.92, -0.08),
+                Point2D.of(0.90, -0.10),
+                Point2D.of(0.90, -0.05),
+                Point2D.of(0.82, -0.05),
+                Point2D.of(0.82, -0.18),
             }
         }, c.getVertices());
     }
@@ -1290,14 +1290,14 @@ public class PolygonsSetTest {
     public void testBug20041003() {
         // arrange
         Line[] l = {
-            new Line(new Point2D(0.0, 0.625000007541172),
-                     new Point2D(1.0, 0.625000007541172), TEST_TOLERANCE),
-            new Line(new Point2D(-0.19204433621902645, 0.0),
-                     new Point2D(-0.19204433621902645, 1.0), TEST_TOLERANCE),
-            new Line(new Point2D(-0.40303524786887,  0.4248364535319128),
-                     new Point2D(-1.12851149797877, -0.2634107480798909), TEST_TOLERANCE),
-            new Line(new Point2D(0.0, 2.0),
-                     new Point2D(1.0, 2.0), TEST_TOLERANCE)
+            new Line(Point2D.of(0.0, 0.625000007541172),
+                     Point2D.of(1.0, 0.625000007541172), TEST_TOLERANCE),
+            new Line(Point2D.of(-0.19204433621902645, 0.0),
+                     Point2D.of(-0.19204433621902645, 1.0), TEST_TOLERANCE),
+            new Line(Point2D.of(-0.40303524786887,  0.4248364535319128),
+                     Point2D.of(-1.12851149797877, -0.2634107480798909), TEST_TOLERANCE),
+            new Line(Point2D.of(0.0, 2.0),
+                     Point2D.of(1.0, 2.0), TEST_TOLERANCE)
         };
 
         BSPTree<Point2D> node1 =
@@ -1340,181 +1340,181 @@ public class PolygonsSetTest {
     public void testSqueezedHexa() {
         // act
         PolygonsSet set = new PolygonsSet(TEST_TOLERANCE,
-                                          new Point2D(-6, -4), new Point2D(-8, -8), new Point2D(  8, -8),
-                                          new Point2D( 6, -4), new Point2D(10,  4), new Point2D(-10,  4));
+                                          Point2D.of(-6, -4), Point2D.of(-8, -8), Point2D.of(  8, -8),
+                                          Point2D.of( 6, -4), Point2D.of(10,  4), Point2D.of(-10,  4));
 
         // assert
-        Assert.assertEquals(Location.OUTSIDE, set.checkPoint(new Point2D(0, 6)));
+        Assert.assertEquals(Location.OUTSIDE, set.checkPoint(Point2D.of(0, 6)));
     }
 
     @Test
     public void testIssue880Simplified() {
         // arrange
         Point2D[] vertices1 = new Point2D[] {
-            new Point2D( 90.13595870833188,  38.33604606376991),
-            new Point2D( 90.14047850603913,  38.34600084496253),
-            new Point2D( 90.11045289492762,  38.36801537312368),
-            new Point2D( 90.10871471476526,  38.36878044144294),
-            new Point2D( 90.10424901707671,  38.374300101757),
-            new Point2D( 90.0979455456843,   38.373578376172475),
-            new Point2D( 90.09081227075944,  38.37526295920463),
-            new Point2D( 90.09081378927135,  38.375193883266434)
+            Point2D.of( 90.13595870833188,  38.33604606376991),
+            Point2D.of( 90.14047850603913,  38.34600084496253),
+            Point2D.of( 90.11045289492762,  38.36801537312368),
+            Point2D.of( 90.10871471476526,  38.36878044144294),
+            Point2D.of( 90.10424901707671,  38.374300101757),
+            Point2D.of( 90.0979455456843,   38.373578376172475),
+            Point2D.of( 90.09081227075944,  38.37526295920463),
+            Point2D.of( 90.09081378927135,  38.375193883266434)
         };
 
         // act
         PolygonsSet set1 = new PolygonsSet(TEST_TOLERANCE, vertices1);
 
         // assert
-        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(new Point2D(90.12,  38.32)));
-        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(new Point2D(90.135, 38.355)));
+        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(Point2D.of(90.12,  38.32)));
+        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(Point2D.of(90.135, 38.355)));
 
     }
 
     @Test
     public void testIssue880Complete() {
         Point2D[] vertices1 = new Point2D[] {
-                new Point2D( 90.08714908223715,  38.370299337260235),
-                new Point2D( 90.08709517675004,  38.3702895991413),
-                new Point2D( 90.08401538704919,  38.368849330127944),
-                new Point2D( 90.08258210430711,  38.367634558585564),
-                new Point2D( 90.08251455106665,  38.36763409247078),
-                new Point2D( 90.08106599752608,  38.36761621664249),
-                new Point2D( 90.08249585300035,  38.36753627557965),
-                new Point2D( 90.09075743352184,  38.35914647644972),
-                new Point2D( 90.09099945896571,  38.35896264724079),
-                new Point2D( 90.09269383800086,  38.34595756121246),
-                new Point2D( 90.09638631543191,  38.3457988093121),
-                new Point2D( 90.09666417351019,  38.34523360999418),
-                new Point2D( 90.1297082145872,  38.337670454923625),
-                new Point2D( 90.12971687748956,  38.337669827794684),
-                new Point2D( 90.1240820219179,  38.34328502001131),
-                new Point2D( 90.13084259656404,  38.34017811765017),
-                new Point2D( 90.13378567942857,  38.33860579180606),
-                new Point2D( 90.13519557833206,  38.33621054663689),
-                new Point2D( 90.13545616732307,  38.33614965452864),
-                new Point2D( 90.13553111202748,  38.33613962818305),
-                new Point2D( 90.1356903436448,  38.33610227127048),
-                new Point2D( 90.13576283227428,  38.33609255422783),
-                new Point2D( 90.13595870833188,  38.33604606376991),
-                new Point2D( 90.1361556630693,  38.3360024198866),
-                new Point2D( 90.13622408795709,  38.335987048115726),
-                new Point2D( 90.13696189099994,  38.33581914328681),
-                new Point2D( 90.13746655304897,  38.33616706665265),
-                new Point2D( 90.13845973716064,  38.33650776167099),
-                new Point2D( 90.13950901827667,  38.3368469456463),
-                new Point2D( 90.14393814424852,  38.337591835857495),
-                new Point2D( 90.14483839716831,  38.337076122362475),
-                new Point2D( 90.14565474433601,  38.33769000964429),
-                new Point2D( 90.14569421179482,  38.3377117256905),
-                new Point2D( 90.14577067124333,  38.33770883625908),
-                new Point2D( 90.14600350631684,  38.337714326520995),
-                new Point2D( 90.14600355139731,  38.33771435193319),
-                new Point2D( 90.14600369112401,  38.33771443882085),
-                new Point2D( 90.14600382486884,  38.33771453466096),
-                new Point2D( 90.14600395205912,  38.33771463904344),
-                new Point2D( 90.14600407214999,  38.337714751520764),
-                new Point2D( 90.14600418462749,  38.337714871611695),
-                new Point2D( 90.14600422249327,  38.337714915811034),
-                new Point2D( 90.14867838361471,  38.34113888210675),
-                new Point2D( 90.14923750157374,  38.341582537502575),
-                new Point2D( 90.14877083250991,  38.34160685841391),
-                new Point2D( 90.14816667319519,  38.34244232585684),
-                new Point2D( 90.14797696744586,  38.34248455284745),
-                new Point2D( 90.14484318014337,  38.34385573215269),
-                new Point2D( 90.14477919958296,  38.3453797747614),
-                new Point2D( 90.14202393306448,  38.34464324839456),
-                new Point2D( 90.14198920640195,  38.344651155237216),
-                new Point2D( 90.14155207025175,  38.34486424263724),
-                new Point2D( 90.1415196143314,  38.344871730519),
-                new Point2D( 90.14128611910814,  38.34500196593859),
-                new Point2D( 90.14047850603913,  38.34600084496253),
-                new Point2D( 90.14045907000337,  38.34601860032171),
-                new Point2D( 90.14039496493928,  38.346223030432384),
-                new Point2D( 90.14037626063737,  38.346240203360026),
-                new Point2D( 90.14030005823724,  38.34646920000705),
-                new Point2D( 90.13799164754806,  38.34903093011013),
-                new Point2D( 90.11045289492762,  38.36801537312368),
-                new Point2D( 90.10871471476526,  38.36878044144294),
-                new Point2D( 90.10424901707671,  38.374300101757),
-                new Point2D( 90.10263482039932,  38.37310041316073),
-                new Point2D( 90.09834601753448,  38.373615053823414),
-                new Point2D( 90.0979455456843,  38.373578376172475),
-                new Point2D( 90.09086514328669,  38.37527884194668),
-                new Point2D( 90.09084931407364,  38.37590801712463),
-                new Point2D( 90.09081227075944,  38.37526295920463),
-                new Point2D( 90.09081378927135,  38.375193883266434)
+                Point2D.of( 90.08714908223715,  38.370299337260235),
+                Point2D.of( 90.08709517675004,  38.3702895991413),
+                Point2D.of( 90.08401538704919,  38.368849330127944),
+                Point2D.of( 90.08258210430711,  38.367634558585564),
+                Point2D.of( 90.08251455106665,  38.36763409247078),
+                Point2D.of( 90.08106599752608,  38.36761621664249),
+                Point2D.of( 90.08249585300035,  38.36753627557965),
+                Point2D.of( 90.09075743352184,  38.35914647644972),
+                Point2D.of( 90.09099945896571,  38.35896264724079),
+                Point2D.of( 90.09269383800086,  38.34595756121246),
+                Point2D.of( 90.09638631543191,  38.3457988093121),
+                Point2D.of( 90.09666417351019,  38.34523360999418),
+                Point2D.of( 90.1297082145872,  38.337670454923625),
+                Point2D.of( 90.12971687748956,  38.337669827794684),
+                Point2D.of( 90.1240820219179,  38.34328502001131),
+                Point2D.of( 90.13084259656404,  38.34017811765017),
+                Point2D.of( 90.13378567942857,  38.33860579180606),
+                Point2D.of( 90.13519557833206,  38.33621054663689),
+                Point2D.of( 90.13545616732307,  38.33614965452864),
+                Point2D.of( 90.13553111202748,  38.33613962818305),
+                Point2D.of( 90.1356903436448,  38.33610227127048),
+                Point2D.of( 90.13576283227428,  38.33609255422783),
+                Point2D.of( 90.13595870833188,  38.33604606376991),
+                Point2D.of( 90.1361556630693,  38.3360024198866),
+                Point2D.of( 90.13622408795709,  38.335987048115726),
+                Point2D.of( 90.13696189099994,  38.33581914328681),
+                Point2D.of( 90.13746655304897,  38.33616706665265),
+                Point2D.of( 90.13845973716064,  38.33650776167099),
+                Point2D.of( 90.13950901827667,  38.3368469456463),
+                Point2D.of( 90.14393814424852,  38.337591835857495),
+                Point2D.of( 90.14483839716831,  38.337076122362475),
+                Point2D.of( 90.14565474433601,  38.33769000964429),
+                Point2D.of( 90.14569421179482,  38.3377117256905),
+                Point2D.of( 90.14577067124333,  38.33770883625908),
+                Point2D.of( 90.14600350631684,  38.337714326520995),
+                Point2D.of( 90.14600355139731,  38.33771435193319),
+                Point2D.of( 90.14600369112401,  38.33771443882085),
+                Point2D.of( 90.14600382486884,  38.33771453466096),
+                Point2D.of( 90.14600395205912,  38.33771463904344),
+                Point2D.of( 90.14600407214999,  38.337714751520764),
+                Point2D.of( 90.14600418462749,  38.337714871611695),
+                Point2D.of( 90.14600422249327,  38.337714915811034),
+                Point2D.of( 90.14867838361471,  38.34113888210675),
+                Point2D.of( 90.14923750157374,  38.341582537502575),
+                Point2D.of( 90.14877083250991,  38.34160685841391),
+                Point2D.of( 90.14816667319519,  38.34244232585684),
+                Point2D.of( 90.14797696744586,  38.34248455284745),
+                Point2D.of( 90.14484318014337,  38.34385573215269),
+                Point2D.of( 90.14477919958296,  38.3453797747614),
+                Point2D.of( 90.14202393306448,  38.34464324839456),
+                Point2D.of( 90.14198920640195,  38.344651155237216),
+                Point2D.of( 90.14155207025175,  38.34486424263724),
+                Point2D.of( 90.1415196143314,  38.344871730519),
+                Point2D.of( 90.14128611910814,  38.34500196593859),
+                Point2D.of( 90.14047850603913,  38.34600084496253),
+                Point2D.of( 90.14045907000337,  38.34601860032171),
+                Point2D.of( 90.14039496493928,  38.346223030432384),
+                Point2D.of( 90.14037626063737,  38.346240203360026),
+                Point2D.of( 90.14030005823724,  38.34646920000705),
+                Point2D.of( 90.13799164754806,  38.34903093011013),
+                Point2D.of( 90.11045289492762,  38.36801537312368),
+                Point2D.of( 90.10871471476526,  38.36878044144294),
+                Point2D.of( 90.10424901707671,  38.374300101757),
+                Point2D.of( 90.10263482039932,  38.37310041316073),
+                Point2D.of( 90.09834601753448,  38.373615053823414),
+                Point2D.of( 90.0979455456843,  38.373578376172475),
+                Point2D.of( 90.09086514328669,  38.37527884194668),
+                Point2D.of( 90.09084931407364,  38.37590801712463),
+                Point2D.of( 90.09081227075944,  38.37526295920463),
+                Point2D.of( 90.09081378927135,  38.375193883266434)
         };
         PolygonsSet set1 = new PolygonsSet(1.0e-8, vertices1);
-        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(new Point2D(90.0905,  38.3755)));
-        Assert.assertEquals(Location.INSIDE,  set1.checkPoint(new Point2D(90.09084, 38.3755)));
-        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(new Point2D(90.0913,  38.3755)));
-        Assert.assertEquals(Location.INSIDE,  set1.checkPoint(new Point2D(90.1042,  38.3739)));
-        Assert.assertEquals(Location.INSIDE,  set1.checkPoint(new Point2D(90.1111,  38.3673)));
-        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(new Point2D(90.0959,  38.3457)));
+        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(Point2D.of(90.0905,  38.3755)));
+        Assert.assertEquals(Location.INSIDE,  set1.checkPoint(Point2D.of(90.09084, 38.3755)));
+        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(Point2D.of(90.0913,  38.3755)));
+        Assert.assertEquals(Location.INSIDE,  set1.checkPoint(Point2D.of(90.1042,  38.3739)));
+        Assert.assertEquals(Location.INSIDE,  set1.checkPoint(Point2D.of(90.1111,  38.3673)));
+        Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(Point2D.of(90.0959,  38.3457)));
 
         Point2D[] vertices2 = new Point2D[] {
-                new Point2D( 90.13067558880044,  38.36977255037573),
-                new Point2D( 90.12907570488,  38.36817308242706),
-                new Point2D( 90.1342774136516,  38.356886880294724),
-                new Point2D( 90.13090330629757,  38.34664392676211),
-                new Point2D( 90.13078571364593,  38.344904617518466),
-                new Point2D( 90.1315602208914,  38.3447185040846),
-                new Point2D( 90.1316336226821,  38.34470643148342),
-                new Point2D( 90.134020944832,  38.340936644972885),
-                new Point2D( 90.13912536387306,  38.335497255122334),
-                new Point2D( 90.1396178806582,  38.334878075552126),
-                new Point2D( 90.14083049696671,  38.33316530644106),
-                new Point2D( 90.14145252901329,  38.33152722916191),
-                new Point2D( 90.1404779335565,  38.32863516047786),
-                new Point2D( 90.14282712131586,  38.327504432532066),
-                new Point2D( 90.14616669875488,  38.3237354115015),
-                new Point2D( 90.14860976050608,  38.315714862457924),
-                new Point2D( 90.14999277782437,  38.3164932507504),
-                new Point2D( 90.15005207194997,  38.316534677663356),
-                new Point2D( 90.15508513859612,  38.31878731691609),
-                new Point2D( 90.15919938519221,  38.31852743183782),
-                new Point2D( 90.16093758658837,  38.31880662005153),
-                new Point2D( 90.16099420184912,  38.318825953291594),
-                new Point2D( 90.1665411125756,  38.31859497874757),
-                new Point2D( 90.16999653861313,  38.32505772048029),
-                new Point2D( 90.17475243391698,  38.32594398441148),
-                new Point2D( 90.17940844844992,  38.327427213761325),
-                new Point2D( 90.20951909541378,  38.330616833491774),
-                new Point2D( 90.2155400467941,  38.331746223670336),
-                new Point2D( 90.21559881391778,  38.33175551425302),
-                new Point2D( 90.21916646426041,  38.332584299620805),
-                new Point2D( 90.23863749852285,  38.34778978875795),
-                new Point2D( 90.25459855175802,  38.357790570608984),
-                new Point2D( 90.25964298227257,  38.356918010203174),
-                new Point2D( 90.26024593994703,  38.361692743151366),
-                new Point2D( 90.26146187570015,  38.36311080550837),
-                new Point2D( 90.26614159359622,  38.36510808579902),
-                new Point2D( 90.26621342936448,  38.36507942500333),
-                new Point2D( 90.26652190211962,  38.36494042196722),
-                new Point2D( 90.26621240678867,  38.365113172030874),
-                new Point2D( 90.26614057102057,  38.365141832826794),
-                new Point2D( 90.26380080055299,  38.3660381760273),
-                new Point2D( 90.26315345241,  38.36670658276421),
-                new Point2D( 90.26251574942881,  38.367490323488084),
-                new Point2D( 90.26247873448426,  38.36755266444749),
-                new Point2D( 90.26234628016698,  38.36787989125406),
-                new Point2D( 90.26214559424784,  38.36945909356126),
-                new Point2D( 90.25861728442555,  38.37200753430875),
-                new Point2D( 90.23905557537864,  38.375405314295904),
-                new Point2D( 90.22517251874075,  38.38984691662256),
-                new Point2D( 90.22549955153215,  38.3911564273979),
-                new Point2D( 90.22434386063355,  38.391476432092134),
-                new Point2D( 90.22147729457276,  38.39134652252034),
-                new Point2D( 90.22142070120117,  38.391349167741964),
-                new Point2D( 90.20665060751588,  38.39475580900313),
-                new Point2D( 90.20042268367109,  38.39842558622888),
-                new Point2D( 90.17423771242085,  38.402727751805344),
-                new Point2D( 90.16756796257476,  38.40913898597597),
-                new Point2D( 90.16728283954308,  38.411255399912875),
-                new Point2D( 90.16703538220418,  38.41136059866693),
-                new Point2D( 90.16725865657685,  38.41013618805954),
-                new Point2D( 90.16746107640665,  38.40902614307544),
-                new Point2D( 90.16122795307462,  38.39773101873203)
+                Point2D.of( 90.13067558880044,  38.36977255037573),
+                Point2D.of( 90.12907570488,  38.36817308242706),
+                Point2D.of( 90.1342774136516,  38.356886880294724),
+                Point2D.of( 90.13090330629757,  38.34664392676211),
+                Point2D.of( 90.13078571364593,  38.344904617518466),
+                Point2D.of( 90.1315602208914,  38.3447185040846),
+                Point2D.of( 90.1316336226821,  38.34470643148342),
+                Point2D.of( 90.134020944832,  38.340936644972885),
+                Point2D.of( 90.13912536387306,  38.335497255122334),
+                Point2D.of( 90.1396178806582,  38.334878075552126),
+                Point2D.of( 90.14083049696671,  38.33316530644106),
+                Point2D.of( 90.14145252901329,  38.33152722916191),
+                Point2D.of( 90.1404779335565,  38.32863516047786),
+                Point2D.of( 90.14282712131586,  38.327504432532066),
+                Point2D.of( 90.14616669875488,  38.3237354115015),
+                Point2D.of( 90.14860976050608,  38.315714862457924),
+                Point2D.of( 90.14999277782437,  38.3164932507504),
+                Point2D.of( 90.15005207194997,  38.316534677663356),
+                Point2D.of( 90.15508513859612,  38.31878731691609),
+                Point2D.of( 90.15919938519221,  38.31852743183782),
+                Point2D.of( 90.16093758658837,  38.31880662005153),
+                Point2D.of( 90.16099420184912,  38.318825953291594),
+                Point2D.of( 90.1665411125756,  38.31859497874757),
+                Point2D.of( 90.16999653861313,  38.32505772048029),
+                Point2D.of( 90.17475243391698,  38.32594398441148),
+                Point2D.of( 90.17940844844992,  38.327427213761325),
+                Point2D.of( 90.20951909541378,  38.330616833491774),
+                Point2D.of( 90.2155400467941,  38.331746223670336),
+                Point2D.of( 90.21559881391778,  38.33175551425302),
+                Point2D.of( 90.21916646426041,  38.332584299620805),
+                Point2D.of( 90.23863749852285,  38.34778978875795),
+                Point2D.of( 90.25459855175802,  38.357790570608984),
+                Point2D.of( 90.25964298227257,  38.356918010203174),
+                Point2D.of( 90.26024593994703,  38.361692743151366),
+                Point2D.of( 90.26146187570015,  38.36311080550837),
+                Point2D.of( 90.26614159359622,  38.36510808579902),
+                Point2D.of( 90.26621342936448,  38.36507942500333),
+                Point2D.of( 90.26652190211962,  38.36494042196722),
+                Point2D.of( 90.26621240678867,  38.365113172030874),
+                Point2D.of( 90.26614057102057,  38.365141832826794),
+                Point2D.of( 90.26380080055299,  38.3660381760273),
+                Point2D.of( 90.26315345241,  38.36670658276421),
+                Point2D.of( 90.26251574942881,  38.367490323488084),
+                Point2D.of( 90.26247873448426,  38.36755266444749),
+                Point2D.of( 90.26234628016698,  38.36787989125406),
+                Point2D.of( 90.26214559424784,  38.36945909356126),
+                Point2D.of( 90.25861728442555,  38.37200753430875),
+                Point2D.of( 90.23905557537864,  38.375405314295904),
+                Point2D.of( 90.22517251874075,  38.38984691662256),
+                Point2D.of( 90.22549955153215,  38.3911564273979),
+                Point2D.of( 90.22434386063355,  38.391476432092134),
+                Point2D.of( 90.22147729457276,  38.39134652252034),
+                Point2D.of( 90.22142070120117,  38.391349167741964),
+                Point2D.of( 90.20665060751588,  38.39475580900313),
+                Point2D.of( 90.20042268367109,  38.39842558622888),
+                Point2D.of( 90.17423771242085,  38.402727751805344),
+                Point2D.of( 90.16756796257476,  38.40913898597597),
+                Point2D.of( 90.16728283954308,  38.411255399912875),
+                Point2D.of( 90.16703538220418,  38.41136059866693),
+                Point2D.of( 90.16725865657685,  38.41013618805954),
+                Point2D.of( 90.16746107640665,  38.40902614307544),
+                Point2D.of( 90.16122795307462,  38.39773101873203)
         };
         PolygonsSet set2 = new PolygonsSet(1.0e-8, vertices2);
         PolygonsSet set  = (PolygonsSet) new
@@ -1553,17 +1553,17 @@ public class PolygonsSetTest {
     public void testIssue1162() {
         // arrange
         PolygonsSet p = new PolygonsSet(TEST_TOLERANCE,
-                                                new Point2D(4.267199999996532, -11.928637756014894),
-                                                new Point2D(4.267200000026445, -14.12360595809307),
-                                                new Point2D(9.144000000273694, -14.12360595809307),
-                                                new Point2D(9.144000000233383, -11.928637756020067));
+                                                Point2D.of(4.267199999996532, -11.928637756014894),
+                                                Point2D.of(4.267200000026445, -14.12360595809307),
+                                                Point2D.of(9.144000000273694, -14.12360595809307),
+                                                Point2D.of(9.144000000233383, -11.928637756020067));
 
         PolygonsSet w = new PolygonsSet(TEST_TOLERANCE,
-                                                new Point2D(2.56735636510452512E-9, -11.933116461089332),
-                                                new Point2D(2.56735636510452512E-9, -12.393225665247766),
-                                                new Point2D(2.56735636510452512E-9, -27.785625665247778),
-                                                new Point2D(4.267200000030211,      -27.785625665247778),
-                                                new Point2D(4.267200000030211,      -11.933116461089332));
+                                                Point2D.of(2.56735636510452512E-9, -11.933116461089332),
+                                                Point2D.of(2.56735636510452512E-9, -12.393225665247766),
+                                                Point2D.of(2.56735636510452512E-9, -27.785625665247778),
+                                                Point2D.of(4.267200000030211,      -27.785625665247778),
+                                                Point2D.of(4.267200000030211,      -11.933116461089332));
 
         // act/assert
         Assert.assertFalse(p.contains(w));
@@ -1575,10 +1575,10 @@ public class PolygonsSetTest {
 
         // arrange
         RegionFactory<Point2D> factory = new RegionFactory<>();
-        Point2D pA = new Point2D(0.0,        1.0);
-        Point2D pB = new Point2D(0.0,        0.0);
-        Point2D pC = new Point2D(1.0 / 64.0, 0.0);
-        Point2D pD = new Point2D(1.0 / 64.0, 1.0);
+        Point2D pA = Point2D.of(0.0,        1.0);
+        Point2D pB = Point2D.of(0.0,        0.0);
+        Point2D pC = Point2D.of(1.0 / 64.0, 0.0);
+        Point2D pD = Point2D.of(1.0 / 64.0, 1.0);
 
         // if tolerance is smaller than rectangle width, the rectangle is computed accurately
         Hyperplane<Point2D>[] h1 = new Line[] {
@@ -1605,10 +1605,10 @@ public class PolygonsSetTest {
 
         // arrange
         RegionFactory<Point2D> factory = new RegionFactory<>();
-        Point2D pA = new Point2D(0.0,        1.0);
-        Point2D pB = new Point2D(0.0,        0.0);
-        Point2D pC = new Point2D(1.0 / 64.0, 0.0);
-        Point2D pD = new Point2D(1.0 / 64.0, 1.0);
+        Point2D pA = Point2D.of(0.0,        1.0);
+        Point2D pB = Point2D.of(0.0,        0.0);
+        Point2D pC = Point2D.of(1.0 / 64.0, 0.0);
+        Point2D pD = Point2D.of(1.0 / 64.0, 1.0);
 
         Hyperplane<Point2D>[] h2 = new Line[] {
                 new Line(pA, pB, 1.0 / 16),
@@ -1629,18 +1629,18 @@ public class PolygonsSetTest {
     public void testInconsistentHyperplanes() {
         // act
         double tolerance = TEST_TOLERANCE;
-        new RegionFactory<Point2D>().buildConvex(new Line(new Point2D(0, 0), new Point2D(0, 1), tolerance),
-                                                     new Line(new Point2D(1, 1), new Point2D(1, 0), tolerance));
+        new RegionFactory<Point2D>().buildConvex(new Line(Point2D.of(0, 0), Point2D.of(0, 1), tolerance),
+                                                     new Line(Point2D.of(1, 1), Point2D.of(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 Point2D(0, 0),
-                                             new Point2D(1, 0),
-                                             new Point2D(1, 1),
-                                             new Point2D(0, 1));
+                                             Point2D.of(0, 0),
+                                             Point2D.of(1, 0),
+                                             Point2D.of(1, 1),
+                                             Point2D.of(0, 1));
         Point2D[][] squareBoundary = square.getVertices();
         Assert.assertEquals(1, squareBoundary.length);
         Assert.assertEquals(4, squareBoundary[0].length);
@@ -1651,7 +1651,7 @@ public class PolygonsSetTest {
 
         // splitting the square in two halves increases the BSP tree
         // with 3 more cuts and 3 more leaf nodes
-        SubLine cut = new Line(new Point2D(0.5, 0.5), 0.0, square.getTolerance()).wholeHyperplane();
+        SubLine cut = new Line(Point2D.of(0.5, 0.5), 0.0, square.getTolerance()).wholeHyperplane();
         PolygonsSet splitSquare = new PolygonsSet(square.getTree(false).split(cut),
                                                   square.getTolerance());
         Counter splitSquareCount = new Counter();
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java
index d5ca735..f9c71e2 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java
@@ -23,20 +23,20 @@ public class SegmentTest {
 
     @Test
     public void testDistance() {
-        Point2D start = new Point2D(2, 2);
-        Point2D end = new Point2D(-2, -2);
+        Point2D start = Point2D.of(2, 2);
+        Point2D end = Point2D.of(-2, -2);
         Segment segment = new Segment(start, end, new Line(start, end, 1.0e-10));
 
         // distance to center of segment
-        Assert.assertEquals(Math.sqrt(2), segment.distance(new Point2D(1, -1)), 1.0e-10);
+        Assert.assertEquals(Math.sqrt(2), segment.distance(Point2D.of(1, -1)), 1.0e-10);
 
         // distance a point on segment
-        Assert.assertEquals(Math.sin(Math.PI / 4.0), segment.distance(new Point2D(0, -1)), 1.0e-10);
+        Assert.assertEquals(Math.sin(Math.PI / 4.0), segment.distance(Point2D.of(0, -1)), 1.0e-10);
 
         // distance to end point
-        Assert.assertEquals(Math.sqrt(8), segment.distance(new Point2D(0, 4)), 1.0e-10);
+        Assert.assertEquals(Math.sqrt(8), segment.distance(Point2D.of(0, 4)), 1.0e-10);
 
         // distance to start point
-        Assert.assertEquals(Math.sqrt(8), segment.distance(new Point2D(0, -4)), 1.0e-10);
+        Assert.assertEquals(Math.sqrt(8), segment.distance(Point2D.of(0, -4)), 1.0e-10);
     }
 }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SubLineTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SubLineTest.java
index 246491a..94a282d 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SubLineTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SubLineTest.java
@@ -28,19 +28,19 @@ public class SubLineTest {
 
     @Test
     public void testEndPoints() {
-        Point2D p1 = new Point2D(-1, -7);
-        Point2D p2 = new Point2D(7, -1);
+        Point2D p1 = Point2D.of(-1, -7);
+        Point2D p2 = Point2D.of(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 Point2D(-1, -7).distance(segments.get(0).getStart()), 1.0e-10);
-        Assert.assertEquals(0.0, new Point2D( 7, -1).distance(segments.get(0).getEnd()), 1.0e-10);
+        Assert.assertEquals(0.0, Point2D.of(-1, -7).distance(segments.get(0).getStart()), 1.0e-10);
+        Assert.assertEquals(0.0, Point2D.of( 7, -1).distance(segments.get(0).getEnd()), 1.0e-10);
     }
 
     @Test
     public void testNoEndPoints() {
-        SubLine wholeLine = new Line(new Point2D(-1, 7), new Point2D(7, 1), 1.0e-10).wholeHyperplane();
+        SubLine wholeLine = new Line(Point2D.of(-1, 7), Point2D.of(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()) &&
@@ -55,7 +55,7 @@ public class SubLineTest {
 
     @Test
     public void testNoSegments() {
-        SubLine empty = new SubLine(new Line(new Point2D(-1, -7), new Point2D(7, -1), 1.0e-10),
+        SubLine empty = new SubLine(new Line(Point2D.of(-1, -7), Point2D.of(7, -1), 1.0e-10),
                                     new RegionFactory<Point1D>().getComplement(new IntervalsSet(1.0e-10)));
         List<Segment> segments = empty.getSegments();
         Assert.assertEquals(0, segments.size());
@@ -63,7 +63,7 @@ public class SubLineTest {
 
     @Test
     public void testSeveralSegments() {
-        SubLine twoSubs = new SubLine(new Line(new Point2D(-1, -7), new Point2D(7, -1), 1.0e-10),
+        SubLine twoSubs = new SubLine(new Line(Point2D.of(-1, -7), Point2D.of(7, -1), 1.0e-10),
                                     new RegionFactory<Point1D>().union(new IntervalsSet(1, 2, 1.0e-10),
                                                                            new IntervalsSet(3, 4, 1.0e-10)));
         List<Segment> segments = twoSubs.getSegments();
@@ -72,7 +72,7 @@ public class SubLineTest {
 
     @Test
     public void testHalfInfiniteNeg() {
-        SubLine empty = new SubLine(new Line(new Point2D(-1, -7), new Point2D(7, -1), 1.0e-10),
+        SubLine empty = new SubLine(new Line(Point2D.of(-1, -7), Point2D.of(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());
@@ -80,16 +80,16 @@ public class SubLineTest {
                           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 Point2D(3, -4).distance(segments.get(0).getEnd()), 1.0e-10);
+        Assert.assertEquals(0.0, Point2D.of(3, -4).distance(segments.get(0).getEnd()), 1.0e-10);
     }
 
     @Test
     public void testHalfInfinitePos() {
-        SubLine empty = new SubLine(new Line(new Point2D(-1, -7), new Point2D(7, -1), 1.0e-10),
+        SubLine empty = new SubLine(new Line(Point2D.of(-1, -7), Point2D.of(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 Point2D(3, -4).distance(segments.get(0).getStart()), 1.0e-10);
+        Assert.assertEquals(0.0, Point2D.of(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()) &&
@@ -98,56 +98,56 @@ public class SubLineTest {
 
     @Test
     public void testIntersectionInsideInside() {
-        SubLine sub1 = new SubLine(new Point2D(1, 1), new Point2D(3, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point2D(2, 0), new Point2D(2, 2), 1.0e-10);
-        Assert.assertEquals(0.0, new Point2D(2, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
-        Assert.assertEquals(0.0, new Point2D(2, 1).distance(sub1.intersection(sub2, false)), 1.0e-12);
+        SubLine sub1 = new SubLine(Point2D.of(1, 1), Point2D.of(3, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point2D.of(2, 0), Point2D.of(2, 2), 1.0e-10);
+        Assert.assertEquals(0.0, Point2D.of(2, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
+        Assert.assertEquals(0.0, Point2D.of(2, 1).distance(sub1.intersection(sub2, false)), 1.0e-12);
     }
 
     @Test
     public void testIntersectionInsideBoundary() {
-        SubLine sub1 = new SubLine(new Point2D(1, 1), new Point2D(3, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point2D(2, 0), new Point2D(2, 1), 1.0e-10);
-        Assert.assertEquals(0.0, new Point2D(2, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
+        SubLine sub1 = new SubLine(Point2D.of(1, 1), Point2D.of(3, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point2D.of(2, 0), Point2D.of(2, 1), 1.0e-10);
+        Assert.assertEquals(0.0, Point2D.of(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 Point2D(1, 1), new Point2D(3, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point2D(2, 0), new Point2D(2, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Point2D.of(1, 1), Point2D.of(3, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point2D.of(2, 0), Point2D.of(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 Point2D(1, 1), new Point2D(2, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point2D(2, 0), new Point2D(2, 1), 1.0e-10);
-        Assert.assertEquals(0.0, new Point2D(2, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
+        SubLine sub1 = new SubLine(Point2D.of(1, 1), Point2D.of(2, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point2D.of(2, 0), Point2D.of(2, 1), 1.0e-10);
+        Assert.assertEquals(0.0, Point2D.of(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 Point2D(1, 1), new Point2D(2, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point2D(2, 0), new Point2D(2, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Point2D.of(1, 1), Point2D.of(2, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point2D.of(2, 0), Point2D.of(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 Point2D(1, 1), new Point2D(1.5, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(new Point2D(2, 0), new Point2D(2, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Point2D.of(1, 1), Point2D.of(1.5, 1), 1.0e-10);
+        SubLine sub2 = new SubLine(Point2D.of(2, 0), Point2D.of(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 Point2D(0, 1), new Point2D(0, 2), 1.0e-10);
-        final SubLine sub2 = new SubLine(new Point2D(66, 3), new Point2D(66, 4), 1.0e-10);
+        final SubLine sub1 = new SubLine(Point2D.of(0, 1), Point2D.of(0, 2), 1.0e-10);
+        final SubLine sub2 = new SubLine(Point2D.of(66, 3), Point2D.of(66, 4), 1.0e-10);
         Assert.assertNull(sub1.intersection(sub2, true));
         Assert.assertNull(sub1.intersection(sub2, false));
     }
diff --git a/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java b/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java
index 1e7c0b9..00947b0 100644
--- a/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java
+++ b/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java
@@ -85,10 +85,10 @@ public abstract class ConvexHullGenerator2DAbstractTest {
     @Test
     public void testAllIdentical() {
         final Collection<Point2D> points = new ArrayList<>();
-        points.add(new Point2D(1, 1));
-        points.add(new Point2D(1, 1));
-        points.add(new Point2D(1, 1));
-        points.add(new Point2D(1, 1));
+        points.add(Point2D.of(1, 1));
+        points.add(Point2D.of(1, 1));
+        points.add(Point2D.of(1, 1));
+        points.add(Point2D.of(1, 1));
 
         final ConvexHull2D hull = generator.generate(points);
         Assert.assertTrue(hull.getVertices().length == 1);
@@ -110,11 +110,11 @@ public abstract class ConvexHullGenerator2DAbstractTest {
     @Test
     public void testCollinearPoints() {
         final Collection<Point2D> points = new ArrayList<>();
-        points.add(new Point2D(1, 1));
-        points.add(new Point2D(2, 2));
-        points.add(new Point2D(2, 4));
-        points.add(new Point2D(4, 1));
-        points.add(new Point2D(10, 1));
+        points.add(Point2D.of(1, 1));
+        points.add(Point2D.of(2, 2));
+        points.add(Point2D.of(2, 4));
+        points.add(Point2D.of(4, 1));
+        points.add(Point2D.of(10, 1));
 
         final ConvexHull2D hull = generator.generate(points);
         checkConvexHull(points, hull);
@@ -123,11 +123,11 @@ public abstract class ConvexHullGenerator2DAbstractTest {
     @Test
     public void testCollinearPointsReverse() {
         final Collection<Point2D> points = new ArrayList<>();
-        points.add(new Point2D(1, 1));
-        points.add(new Point2D(2, 2));
-        points.add(new Point2D(2, 4));
-        points.add(new Point2D(10, 1));
-        points.add(new Point2D(4, 1));
+        points.add(Point2D.of(1, 1));
+        points.add(Point2D.of(2, 2));
+        points.add(Point2D.of(2, 4));
+        points.add(Point2D.of(10, 1));
+        points.add(Point2D.of(4, 1));
 
         final ConvexHull2D hull = generator.generate(points);
         checkConvexHull(points, hull);
@@ -136,11 +136,11 @@ public abstract class ConvexHullGenerator2DAbstractTest {
     @Test
     public void testCollinearPointsIncluded() {
         final Collection<Point2D> points = new ArrayList<>();
-        points.add(new Point2D(1, 1));
-        points.add(new Point2D(2, 2));
-        points.add(new Point2D(2, 4));
-        points.add(new Point2D(4, 1));
-        points.add(new Point2D(10, 1));
+        points.add(Point2D.of(1, 1));
+        points.add(Point2D.of(2, 2));
+        points.add(Point2D.of(2, 4));
+        points.add(Point2D.of(4, 1));
+        points.add(Point2D.of(10, 1));
 
         final ConvexHull2D hull = createConvexHullGenerator(true).generate(points);
         checkConvexHull(points, hull, true);
@@ -149,11 +149,11 @@ public abstract class ConvexHullGenerator2DAbstractTest {
     @Test
     public void testCollinearPointsIncludedReverse() {
         final Collection<Point2D> points = new ArrayList<>();
-        points.add(new Point2D(1, 1));
-        points.add(new Point2D(2, 2));
-        points.add(new Point2D(2, 4));
-        points.add(new Point2D(10, 1));
-        points.add(new Point2D(4, 1));
+        points.add(Point2D.of(1, 1));
+        points.add(Point2D.of(2, 2));
+        points.add(Point2D.of(2, 4));
+        points.add(Point2D.of(10, 1));
+        points.add(Point2D.of(4, 1));
 
         final ConvexHull2D hull = createConvexHullGenerator(true).generate(points);
         checkConvexHull(points, hull, true);
@@ -162,11 +162,11 @@ public abstract class ConvexHullGenerator2DAbstractTest {
     @Test
     public void testIdenticalPoints() {
         final Collection<Point2D> points = new ArrayList<>();
-        points.add(new Point2D(1, 1));
-        points.add(new Point2D(2, 2));
-        points.add(new Point2D(2, 4));
-        points.add(new Point2D(4, 1));
-        points.add(new Point2D(1, 1));
+        points.add(Point2D.of(1, 1));
+        points.add(Point2D.of(2, 2));
+        points.add(Point2D.of(2, 4));
+        points.add(Point2D.of(4, 1));
+        points.add(Point2D.of(1, 1));
 
         final ConvexHull2D hull = generator.generate(points);
         checkConvexHull(points, hull);
@@ -175,11 +175,11 @@ public abstract class ConvexHullGenerator2DAbstractTest {
     @Test
     public void testIdenticalPoints2() {
         final Collection<Point2D> points = new ArrayList<>();
-        points.add(new Point2D(1, 1));
-        points.add(new Point2D(2, 2));
-        points.add(new Point2D(2, 4));
-        points.add(new Point2D(4, 1));
-        points.add(new Point2D(1, 1));
+        points.add(Point2D.of(1, 1));
+        points.add(Point2D.of(2, 2));
+        points.add(Point2D.of(2, 4));
+        points.add(Point2D.of(4, 1));
+        points.add(Point2D.of(1, 1));
 
         final ConvexHull2D hull = createConvexHullGenerator(true).generate(points);
         checkConvexHull(points, hull, true);
@@ -188,11 +188,11 @@ public abstract class ConvexHullGenerator2DAbstractTest {
     @Test
     public void testClosePoints() {
         final Collection<Point2D> points = new ArrayList<>();
-        points.add(new Point2D(1, 1));
-        points.add(new Point2D(2, 2));
-        points.add(new Point2D(2, 4));
-        points.add(new Point2D(4, 1));
-        points.add(new Point2D(1.00001, 1));
+        points.add(Point2D.of(1, 1));
+        points.add(Point2D.of(2, 2));
+        points.add(Point2D.of(2, 4));
+        points.add(Point2D.of(4, 1));
+        points.add(Point2D.of(1.00001, 1));
 
         final ConvexHull2D hull = generator.generate(points);
         checkConvexHull(points, hull);
@@ -203,16 +203,16 @@ public abstract class ConvexHullGenerator2DAbstractTest {
         // MATH-1135: check that collinear points on the hull are handled correctly
         //            when only a minimal hull shall be constructed
         final Collection<Point2D> points = new ArrayList<>();
-        points.add(new Point2D(7.3152, 34.7472));
-        points.add(new Point2D(6.400799999999997, 34.747199999999985));
-        points.add(new Point2D(5.486399999999997, 34.7472));
-        points.add(new Point2D(4.876799999999999, 34.7472));
-        points.add(new Point2D(4.876799999999999, 34.1376));
-        points.add(new Point2D(4.876799999999999, 30.48));
-        points.add(new Point2D(6.0959999999999965, 30.48));
-        points.add(new Point2D(6.0959999999999965, 34.1376));
-        points.add(new Point2D(7.315199999999996, 34.1376));
-        points.add(new Point2D(7.3152, 30.48));
+        points.add(Point2D.of(7.3152, 34.7472));
+        points.add(Point2D.of(6.400799999999997, 34.747199999999985));
+        points.add(Point2D.of(5.486399999999997, 34.7472));
+        points.add(Point2D.of(4.876799999999999, 34.7472));
+        points.add(Point2D.of(4.876799999999999, 34.1376));
+        points.add(Point2D.of(4.876799999999999, 30.48));
+        points.add(Point2D.of(6.0959999999999965, 30.48));
+        points.add(Point2D.of(6.0959999999999965, 34.1376));
+        points.add(Point2D.of(7.315199999999996, 34.1376));
+        points.add(Point2D.of(7.3152, 30.48));
 
         final ConvexHull2D hull = createConvexHullGenerator(false).generate(points);
         checkConvexHull(points, hull);
@@ -227,10 +227,10 @@ public abstract class ConvexHullGenerator2DAbstractTest {
         List<Point2D> points = new ArrayList<>();
 
         // first case: 3 points are collinear
-        points.add(new Point2D(16.078200000000184, -36.52519999989808));
-        points.add(new Point2D(19.164300000000186, -36.52519999989808));
-        points.add(new Point2D(19.1643, -25.28136477910407));
-        points.add(new Point2D(19.1643, -17.678400000004157));
+        points.add(Point2D.of(16.078200000000184, -36.52519999989808));
+        points.add(Point2D.of(19.164300000000186, -36.52519999989808));
+        points.add(Point2D.of(19.1643, -25.28136477910407));
+        points.add(Point2D.of(19.1643, -17.678400000004157));
 
         ConvexHull2D hull = createConvexHullGenerator(false).generate(points);
         checkConvexHull(points, hull);
@@ -241,15 +241,15 @@ public abstract class ConvexHullGenerator2DAbstractTest {
         points.clear();
 
         // second case: multiple points are collinear
-        points.add(new Point2D(0, -29.959696875));
-        points.add(new Point2D(0, -31.621809375));
-        points.add(new Point2D(0, -28.435696875));
-        points.add(new Point2D(0, -33.145809375));
-        points.add(new Point2D(3.048, -33.145809375));
-        points.add(new Point2D(3.048, -31.621809375));
-        points.add(new Point2D(3.048, -29.959696875));
-        points.add(new Point2D(4.572, -33.145809375));
-        points.add(new Point2D(4.572, -28.435696875));
+        points.add(Point2D.of(0, -29.959696875));
+        points.add(Point2D.of(0, -31.621809375));
+        points.add(Point2D.of(0, -28.435696875));
+        points.add(Point2D.of(0, -33.145809375));
+        points.add(Point2D.of(3.048, -33.145809375));
+        points.add(Point2D.of(3.048, -31.621809375));
+        points.add(Point2D.of(3.048, -29.959696875));
+        points.add(Point2D.of(4.572, -33.145809375));
+        points.add(Point2D.of(4.572, -28.435696875));
 
         hull = createConvexHullGenerator(false).generate(points);
         checkConvexHull(points, hull);
@@ -315,26 +315,26 @@ public abstract class ConvexHullGenerator2DAbstractTest {
                 { 11, -1 }, { 11, 0 }, { 11, 1 } };
 
         for (int[] line : data) {
-            points.add(new Point2D(line[0], line[1]));
+            points.add(Point2D.of(line[0], line[1]));
         }
 
         Point2D[] referenceHull = new Point2D[] {
-            new Point2D(-11.0, -1.0),
-            new Point2D(-10.0, -3.0),
-            new Point2D( -6.0, -7.0),
-            new Point2D( -3.0, -8.0),
-            new Point2D(  3.0, -8.0),
-            new Point2D(  6.0, -7.0),
-            new Point2D( 10.0, -3.0),
-            new Point2D( 11.0, -1.0),
-            new Point2D( 11.0,  1.0),
-            new Point2D( 10.0,  3.0),
-            new Point2D(  6.0,  7.0),
-            new Point2D(  3.0,  8.0),
-            new Point2D( -3.0,  8.0),
-            new Point2D( -6.0,  7.0),
-            new Point2D(-10.0,  3.0),
-            new Point2D(-11.0,  1.0),
+            Point2D.of(-11.0, -1.0),
+            Point2D.of(-10.0, -3.0),
+            Point2D.of( -6.0, -7.0),
+            Point2D.of( -3.0, -8.0),
+            Point2D.of(  3.0, -8.0),
+            Point2D.of(  6.0, -7.0),
+            Point2D.of( 10.0, -3.0),
+            Point2D.of( 11.0, -1.0),
+            Point2D.of( 11.0,  1.0),
+            Point2D.of( 10.0,  3.0),
+            Point2D.of(  6.0,  7.0),
+            Point2D.of(  3.0,  8.0),
+            Point2D.of( -3.0,  8.0),
+            Point2D.of( -6.0,  7.0),
+            Point2D.of(-10.0,  3.0),
+            Point2D.of(-11.0,  1.0),
         };
 
         ConvexHull2D convHull = generator.generate(points);
@@ -361,7 +361,7 @@ public abstract class ConvexHullGenerator2DAbstractTest {
         List<Point2D> points = new ArrayList<>(size);
         // fill the cloud with a random distribution of points
         for (int i = 0; i < size; i++) {
-            points.add(new Point2D(random.nextDouble() * 2.0 - 1.0, random.nextDouble() * 2.0 - 1.0));
+            points.add(Point2D.of(random.nextDouble() * 2.0 - 1.0, random.nextDouble() * 2.0 - 1.0));
         }
         return points;
     }
diff --git a/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChainTest.java b/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChainTest.java
index a19e99a..86f513d 100644
--- a/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChainTest.java
+++ b/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChainTest.java
@@ -38,14 +38,14 @@ public class MonotoneChainTest extends ConvexHullGenerator2DAbstractTest {
     public void testConvergenceException() {
         final Collection<Point2D> points = new ArrayList<>();
 
-        points.add(new Point2D(1, 1));
-        points.add(new Point2D(1, 5));
-        points.add(new Point2D(0, 7));
-        points.add(new Point2D(1, 10));
-        points.add(new Point2D(1, 20));
-        points.add(new Point2D(20, 20));
-        points.add(new Point2D(20, 40));
-        points.add(new Point2D(40, 1));
+        points.add(Point2D.of(1, 1));
+        points.add(Point2D.of(1, 5));
+        points.add(Point2D.of(0, 7));
+        points.add(Point2D.of(1, 10));
+        points.add(Point2D.of(1, 20));
+        points.add(Point2D.of(20, 20));
+        points.add(Point2D.of(20, 40));
+        points.add(Point2D.of(40, 1));
 
         @SuppressWarnings("unused")
         final ConvexHull2D hull = new MonotoneChain(true, 2).generate(points);
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/SphericalCoordinates.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/SphericalCoordinates.java
index d8dc614..d9d959f 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/SphericalCoordinates.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/SphericalCoordinates.java
@@ -110,7 +110,7 @@ public class SphericalCoordinates implements Serializable {
         this.phi   = phi;
 
         // Cartesian coordinates
-        this.v  = new Vector3D(r * cosTheta * sinPhi,
+        this.v  = Vector3D.of(r * cosTheta * sinPhi,
                                r * sinTheta * sinPhi,
                                r * cosPhi);
 
@@ -386,7 +386,7 @@ public class SphericalCoordinates implements Serializable {
          * @return replacement {@link SphericalCoordinates}
          */
         private Object readResolve() {
-            return new SphericalCoordinates(new Vector3D(x, y, z));
+            return new SphericalCoordinates(Vector3D.of(x, y, z));
         }
 
     }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
index da4f85c..8f7b19c 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
@@ -46,7 +46,7 @@ public class S1Point implements Point<S1Point> {
      */
     public S1Point(final double alpha) {
         this(PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(alpha),
-             new Vector2D(Math.cos(alpha), Math.sin(alpha)));
+             Vector2D.of(Math.cos(alpha), Math.sin(alpha)));
     }
 
     /** Build a point from its internal components.
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
index 4542e26..567e666 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
@@ -118,7 +118,7 @@ public class S2Point implements Point<S2Point> {
         final double cosPhi   = Math.cos(phi);
         final double sinPhi   = Math.sin(phi);
 
-        return new Vector3D(cosTheta * sinPhi, sinTheta * sinPhi, cosPhi);
+        return Vector3D.of(cosTheta * sinPhi, sinTheta * sinPhi, cosPhi);
 
     }
 
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalCoordinatesTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalCoordinatesTest.java
index 892814b..db3b76e 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalCoordinatesTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalCoordinatesTest.java
@@ -28,43 +28,43 @@ public class SphericalCoordinatesTest {
     public void testCoordinatesStoC() {
         double piO2 = 0.5 * Math.PI;
         SphericalCoordinates sc1 = new SphericalCoordinates(2.0, 0, piO2);
-        Assert.assertEquals(0, sc1.getCartesian().distance(new Vector3D(2, 0, 0)), 1.0e-10);
+        Assert.assertEquals(0, sc1.getCartesian().distance(Vector3D.of(2, 0, 0)), 1.0e-10);
         SphericalCoordinates sc2 = new SphericalCoordinates(2.0, piO2, piO2);
-        Assert.assertEquals(0, sc2.getCartesian().distance(new Vector3D(0, 2, 0)), 1.0e-10);
+        Assert.assertEquals(0, sc2.getCartesian().distance(Vector3D.of(0, 2, 0)), 1.0e-10);
         SphericalCoordinates sc3 = new SphericalCoordinates(2.0, Math.PI, piO2);
-        Assert.assertEquals(0, sc3.getCartesian().distance(new Vector3D(-2, 0, 0)), 1.0e-10);
+        Assert.assertEquals(0, sc3.getCartesian().distance(Vector3D.of(-2, 0, 0)), 1.0e-10);
         SphericalCoordinates sc4 = new SphericalCoordinates(2.0, -piO2, piO2);
-        Assert.assertEquals(0, sc4.getCartesian().distance(new Vector3D(0, -2, 0)), 1.0e-10);
+        Assert.assertEquals(0, sc4.getCartesian().distance(Vector3D.of(0, -2, 0)), 1.0e-10);
         SphericalCoordinates sc5 = new SphericalCoordinates(2.0, 1.23456, 0);
-        Assert.assertEquals(0, sc5.getCartesian().distance(new Vector3D(0, 0, 2)), 1.0e-10);
+        Assert.assertEquals(0, sc5.getCartesian().distance(Vector3D.of(0, 0, 2)), 1.0e-10);
         SphericalCoordinates sc6 = new SphericalCoordinates(2.0, 6.54321, Math.PI);
-        Assert.assertEquals(0, sc6.getCartesian().distance(new Vector3D(0, 0, -2)), 1.0e-10);
+        Assert.assertEquals(0, sc6.getCartesian().distance(Vector3D.of(0, 0, -2)), 1.0e-10);
     }
 
     @Test
     public void testCoordinatesCtoS() {
         double piO2 = 0.5 * Math.PI;
-        SphericalCoordinates sc1 = new SphericalCoordinates(new Vector3D(2, 0, 0));
+        SphericalCoordinates sc1 = new SphericalCoordinates(Vector3D.of(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 Vector3D(0, 2, 0));
+        SphericalCoordinates sc2 = new SphericalCoordinates(Vector3D.of(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 Vector3D(-2, 0, 0));
+        SphericalCoordinates sc3 = new SphericalCoordinates(Vector3D.of(-2, 0, 0));
         Assert.assertEquals(2,           sc3.getR(),     1.0e-10);
         Assert.assertEquals(Math.PI, sc3.getTheta(), 1.0e-10);
         Assert.assertEquals(piO2,        sc3.getPhi(),   1.0e-10);
-        SphericalCoordinates sc4 = new SphericalCoordinates(new Vector3D(0, -2, 0));
+        SphericalCoordinates sc4 = new SphericalCoordinates(Vector3D.of(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 Vector3D(0, 0, 2));
+        SphericalCoordinates sc5 = new SphericalCoordinates(Vector3D.of(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 Vector3D(0, 0, -2));
+        SphericalCoordinates sc6 = new SphericalCoordinates(Vector3D.of(0, 0, -2));
         Assert.assertEquals(2,           sc6.getR(),     1.0e-10);
         //  don't check theta on poles, as it is singular
         Assert.assertEquals(Math.PI, sc6.getPhi(),   1.0e-10);
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java
index 313e455..b5a1211 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java
@@ -110,7 +110,7 @@ public class SphericalTestUtils {
             @Override
             public Circle parseHyperplane()
                 throws IOException, ParseException {
-                return new Circle(new Vector3D(getNumber(), getNumber(), getNumber()), getNumber());
+                return new Circle(Vector3D.of(getNumber(), getNumber(), getNumber()), getNumber());
             }
 
         };
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java
index 7458ee9..a958dcf 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java
@@ -36,7 +36,7 @@ public class CircleTest {
 
     @Test
     public void testEquator() {
-        Circle circle = new Circle(new Vector3D(0, 0, 1000), 1.0e-10).copySelf();
+        Circle circle = new Circle(Vector3D.of(0, 0, 1000), 1.0e-10).copySelf();
         Assert.assertEquals(Vector3D.PLUS_Z, circle.getPole());
         Assert.assertEquals(1.0e-10, circle.getTolerance(), 1.0e-20);
         circle.revertSelf();
@@ -83,7 +83,7 @@ public class CircleTest {
     @Test
     public void testPhase() {
         Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10);
-        Vector3D p = new Vector3D(1, 2, -4);
+        Vector3D p = Vector3D.of(1, 2, -4);
         Vector3D samePhase = circle.getPointAt(circle.getPhase(p));
         Assert.assertEquals(0.0,
                             Vector3D.angle(Vector3D.crossProduct(circle.getPole(), p),
@@ -101,7 +101,7 @@ public class CircleTest {
         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 * Math.PI, circle.toSubSpace(new S2Point(circle.getYAxis())).getAlpha(), 1.0e-10);
-        Vector3D p = new Vector3D(1, 2, -4);
+        Vector3D p = Vector3D.of(1, 2, -4);
         Assert.assertEquals(circle.getPhase(p), circle.toSubSpace(new S2Point(p)).getAlpha(), 1.0e-10);
     }
 
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java
index 0152188..0f52671 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java
@@ -156,7 +156,7 @@ public class SphericalPolygonsSetTest {
         Assert.assertEquals(3, count);
 
         Assert.assertEquals(0.0,
-                            octant.getBarycenter().distance(new S2Point(new Vector3D(1, 1, 1))),
+                            octant.getBarycenter().distance(new S2Point(Vector3D.of(1, 1, 1))),
                             1.0e-10);
         Assert.assertEquals(0.5 * Math.PI, octant.getSize(), 1.0e-10);
 
@@ -166,7 +166,7 @@ public class SphericalPolygonsSetTest {
 
         EnclosingBall<S2Point> reversedCap =
                 ((SphericalPolygonsSet) factory.getComplement(octant)).getEnclosingCap();
-        Assert.assertEquals(0, reversedCap.getCenter().distance(new S2Point(new Vector3D(-1, -1, -1))), 1.0e-10);
+        Assert.assertEquals(0, reversedCap.getCenter().distance(new S2Point(Vector3D.of(-1, -1, -1))), 1.0e-10);
         Assert.assertEquals(Math.PI - Math.asin(1.0 / Math.sqrt(3)), reversedCap.getRadius(), 1.0e-10);
 
     }
@@ -274,14 +274,14 @@ public class SphericalPolygonsSetTest {
         boundary.add(create(Vector3D.PLUS_Z,  Vector3D.MINUS_Y, Vector3D.PLUS_X,  tol, 0.0, 0.5 * Math.PI));
         SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, tol);
 
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D( 1,  1,  1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(new Vector3D(-1,  1,  1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(new Vector3D(-1, -1,  1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(new Vector3D( 1, -1,  1).normalize())));
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D( 1,  1, -1).normalize())));
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D(-1,  1, -1).normalize())));
-        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(new Vector3D(-1, -1, -1).normalize())));
-        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D( 1, -1, -1).normalize())));
+        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of( 1,  1,  1).normalize())));
+        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(Vector3D.of(-1,  1,  1).normalize())));
+        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(Vector3D.of(-1, -1,  1).normalize())));
+        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(Vector3D.of( 1, -1,  1).normalize())));
+        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of( 1,  1, -1).normalize())));
+        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of(-1,  1, -1).normalize())));
+        Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(new S2Point(Vector3D.of(-1, -1, -1).normalize())));
+        Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of( 1, -1, -1).normalize())));
 
         Assert.assertEquals(Geometry.TWO_PI, polygon.getSize(), 1.0e-10);
         Assert.assertEquals(3 * Math.PI, polygon.getBoundarySize(), 1.0e-10);
@@ -366,7 +366,7 @@ public class SphericalPolygonsSetTest {
     public void testPartWithHole() {
         double tol = 0.01;
         double alpha = 0.7;
-        S2Point center = new S2Point(new Vector3D(1, 1, 1));
+        S2Point center = new S2Point(Vector3D.of(1, 1, 1));
         SphericalPolygonsSet hexa = new SphericalPolygonsSet(center.getVector(), Vector3D.PLUS_Z, alpha, 6, tol);
         SphericalPolygonsSet hole  = new SphericalPolygonsSet(tol,
                                                               new S2Point(Math.PI / 6, Math.PI / 3),
@@ -395,7 +395,7 @@ public class SphericalPolygonsSetTest {
     @Test
     public void testConcentricSubParts() {
         double tol = 0.001;
-        Vector3D center = new Vector3D(1, 1, 1);
+        Vector3D center = Vector3D.of(1, 1, 1);
         SphericalPolygonsSet hexaOut   = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.9,  6, tol);
         SphericalPolygonsSet hexaIn    = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.8,  6, tol);
         SphericalPolygonsSet pentaOut  = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.7,  5, tol);
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SubCircleTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SubCircleTest.java
index 6cd5618..69a3950 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SubCircleTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SubCircleTest.java
@@ -110,9 +110,9 @@ public class SubCircleTest {
     public void testSideSplitConsistency() {
 
         double tolerance = 1.0e-6;
-        Circle hyperplane = new Circle(new Vector3D(9.738804529764676E-5, -0.6772824575010357, -0.7357230887208355),
+        Circle hyperplane = new Circle(Vector3D.of(9.738804529764676E-5, -0.6772824575010357, -0.7357230887208355),
                                        tolerance);
-        SubCircle sub = new SubCircle(new Circle(new Vector3D(2.1793884139073498E-4, 0.9790647032675541, -0.20354915700704285),
+        SubCircle sub = new SubCircle(new Circle(Vector3D.of(2.1793884139073498E-4, 0.9790647032675541, -0.20354915700704285),
                                                  tolerance),
                                       new ArcsSet(4.7121441684170700, 4.7125386635004760, tolerance));
         SplitSubHyperplane<S2Point> split = sub.split(hyperplane);


[commons-geometry] 04/08: GEOMETRY-2: removing Serializable from top-level interface and placing at concrete class level, per issue comments

Posted by er...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 519a17ab35760edc45acd24798d0a5270598c04d
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Sat Jun 2 23:16:46 2018 -0400

    GEOMETRY-2: removing Serializable from top-level interface and placing at concrete class level, per issue comments
---
 .../src/main/java/org/apache/commons/geometry/core/Spatial.java       | 4 +---
 .../java/org/apache/commons/geometry/euclidean/oned/Cartesian1D.java  | 4 +++-
 .../org/apache/commons/geometry/euclidean/threed/Cartesian3D.java     | 4 +++-
 .../java/org/apache/commons/geometry/euclidean/twod/Cartesian2D.java  | 4 +++-
 .../main/java/org/apache/commons/geometry/spherical/oned/S1Point.java | 4 +++-
 .../main/java/org/apache/commons/geometry/spherical/twod/S2Point.java | 4 +++-
 6 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Spatial.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Spatial.java
index ad72eb7..c6f76c1 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Spatial.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Spatial.java
@@ -16,11 +16,9 @@
  */
 package org.apache.commons.geometry.core;
 
-import java.io.Serializable;
-
 /** Interface representing a generic element in a mathematical space.
  */
-public interface Spatial extends Serializable {
+public interface Spatial {
 
     /** Returns the number of dimensions in the space that this element
      * belongs to.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Cartesian1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Cartesian1D.java
index 53e2879..8d9b800 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Cartesian1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Cartesian1D.java
@@ -16,12 +16,14 @@
  */
 package org.apache.commons.geometry.euclidean.oned;
 
+import java.io.Serializable;
+
 import org.apache.commons.geometry.core.Spatial;
 
 /** This class represents a Cartesian coordinate value in
  * one-dimensional Euclidean space.
  */
-public abstract class Cartesian1D implements Spatial {
+public abstract class Cartesian1D implements Spatial, Serializable {
 
     /** Serializable UID. */
     private static final long serialVersionUID = -1178039568877797126L;
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Cartesian3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Cartesian3D.java
index 4640b23..6b619ac 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Cartesian3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Cartesian3D.java
@@ -17,12 +17,14 @@
 
 package org.apache.commons.geometry.euclidean.threed;
 
+import java.io.Serializable;
+
 import org.apache.commons.geometry.core.Spatial;
 
 /** This class represents a Cartesian coordinate value in
  * three-dimensional Euclidean space.
  */
-public abstract class Cartesian3D implements Spatial {
+public abstract class Cartesian3D implements Spatial, Serializable {
 
     /** Serializable UID. */
     private static final long serialVersionUID = 6249091865814886817L;
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Cartesian2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Cartesian2D.java
index ba3b462..d4c69b6 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Cartesian2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Cartesian2D.java
@@ -17,12 +17,14 @@
 
 package org.apache.commons.geometry.euclidean.twod;
 
+import java.io.Serializable;
+
 import org.apache.commons.geometry.core.Spatial;
 
 /** This class represents a set of Cartesian coordinates in
  * two-dimensional Euclidean space.
  */
-public abstract class Cartesian2D implements Spatial {
+public abstract class Cartesian2D implements Spatial, Serializable {
 
     /** Serializable UID */
     private static final long serialVersionUID = 2918583078965478552L;
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
index c2f6d86..7cced20 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.geometry.spherical.oned;
 
+import java.io.Serializable;
+
 import org.apache.commons.geometry.core.Point;
 import org.apache.commons.geometry.core.util.Coordinates;
 import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
@@ -25,7 +27,7 @@ import org.apache.commons.numbers.angle.PlaneAngleRadians;
 /** This class represents a point on the 1-sphere.
  * <p>Instances of this class are guaranteed to be immutable.</p>
  */
-public final class S1Point implements Point<S1Point> {
+public final class S1Point implements Point<S1Point>, Serializable {
 
    // CHECKSTYLE: stop ConstantName
     /** A vector with all coordinates set to NaN. */
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
index a0c7499..f8d3f4e 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.geometry.spherical.twod;
 
+import java.io.Serializable;
+
 import org.apache.commons.geometry.core.Point;
 import org.apache.commons.geometry.core.util.Coordinates;
 import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
@@ -31,7 +33,7 @@ import org.apache.commons.geometry.euclidean.threed.Vector3D;
  * </p>
  * <p>Instances of this class are guaranteed to be immutable.</p>
  */
-public final class S2Point implements Point<S2Point> {
+public final class S2Point implements Point<S2Point>, Serializable {
 
     /** +I (coordinates: \( \theta = 0, \varphi = \pi/2 \)). */
     public static final S2Point PLUS_I = new S2Point(0, 0.5 * Math.PI, Vector3D.PLUS_X);


[commons-geometry] 02/08: GEOMETRY-3: adding generic coordinate format and parsing classes

Posted by er...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit f255ccce7c5736f2eb88c91ef57a4483adede29c
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Sat Jun 2 00:54:34 2018 -0400

    GEOMETRY-3: adding generic coordinate format and parsing classes
---
 .../core/util/AbstractCoordinateParser.java        | 239 +++++++++++
 .../commons/geometry/core/util/Coordinates.java    |  65 +++
 .../geometry/core/util/SimpleCoordinateFormat.java | 177 ++++++++
 .../core/util/SimpleCoordinateFormatTest.java      | 453 +++++++++++++++++++++
 4 files changed, 934 insertions(+)

diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java
new file mode 100644
index 0000000..ec906bc
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.util;
+
+import java.text.ParsePosition;
+
+/** Abstract class providing basic parsing functionality for reading coordinate tuples
+ * from strings.
+ */
+public abstract class AbstractCoordinateParser {
+
+    /** String separating coordinate values */
+    private final String separator;
+
+    /** String used to signal the start of a coordinate tuple; may be null */
+    private final String prefix;
+
+    /** String used to signal the end of a coordinate tuple; may be null */
+    private final String suffix;
+
+    /** Simple constructor
+     * @param separator String used to separate coordinate values; must not be null.
+     * @param prefix String used to signal the start of a coordinate tuple; if null, no
+     *      string is expected at the start of the tuple
+     * @param suffix String used to signal the end of a coordinate tuple; if null, no
+     *      string is expected at the end of the tuple
+     */
+    protected AbstractCoordinateParser(String separator, String prefix, String suffix) {
+        this.separator = separator;
+        this.prefix = prefix;
+        this.suffix = suffix;
+    }
+
+    /** Returns the string used to separate coordinate values.
+     * @return the coordinate value separator string
+     */
+    public String getSeparator() {
+        return separator;
+    }
+
+    /** Returns the string used to signal the start of a coordinate tuple. This value may be null.
+     * @return the string used to begin each coordinate tuple or null
+     */
+    public String getPrefix() {
+        return prefix;
+    }
+
+    /** Returns the string used to signal the end of a coordinate tuple. This value may be null.
+     * @return the string used to end each coordinate tuple or null
+     */
+    public String getSuffix() {
+        return suffix;
+    }
+
+    /** Reads the configured prefix from the current position in the given string, ignoring any preceding
+     * whitespace, and advances the parsing position past the prefix sequence. An exception is thrown if the
+     * prefix is not found. Does nothing if the prefix is null.
+     * @param str the string being parsed
+     * @param pos the current parsing position
+     * @throws IllegalArgumentException if the configured prefix is not null and is not found at the current
+     *      parsing position, ignoring preceding whitespace
+     */
+    protected void readPrefix(String str, ParsePosition pos) throws IllegalArgumentException {
+        if (prefix != null) {
+            consumeWhitespace(str, pos);
+            readSequence(str, prefix, pos);
+        }
+    }
+
+    /** Reads and returns a coordinate value from the current position in the given string. An exception is thrown if a
+     * valid number is not found. The parsing position is advanced past the parsed number and any trailing separator.
+     * @param str the string being parsed
+     * @param pos the current parsing position
+     * @return the coordinate value
+     * @throws IllegalArgumentException if the configured prefix is not null and is not found at the current
+     *      parsing position, ignoring preceding whitespace
+     */
+    protected double readCoordinateValue(String str, ParsePosition pos) throws IllegalArgumentException {
+        final int startIdx = pos.getIndex();
+
+        int endIdx = str.indexOf(separator, startIdx);
+        if (endIdx < 0) {
+            if (suffix != null) {
+                endIdx = str.indexOf(suffix, startIdx);
+            }
+
+            if (endIdx < 0) {
+                endIdx = str.length();
+            }
+        }
+
+        String substr = str.substring(startIdx, endIdx);
+        try {
+            double value = Double.parseDouble(substr);
+
+            // advance the position and move past any terminating separator
+            pos.setIndex(endIdx);
+            matchSequence(str, separator, pos);
+
+            return value;
+        }
+        catch (NumberFormatException exc) {
+            throw new CoordinateParseException("Failed to parse number from string at index " + startIdx + ": " + substr, exc);
+        }
+    }
+
+    /** Reads the configured suffix from the current position in the given string, ignoring any preceding
+     * whitespace, and advances the parsing position past the suffix sequence. An exception is thrown if the
+     * suffix is not found. Does nothing if the suffix is null.
+     * @param str the string being parsed
+     * @param pos the current parsing position
+     * @throws IllegalArgumentException if the configured suffix is not null and is not found at the current
+     *      parsing position, ignoring preceding whitespace
+     */
+    protected void readSuffix(String str, ParsePosition pos) throws IllegalArgumentException {
+        if (suffix != null) {
+            consumeWhitespace(str, pos);
+            readSequence(str, suffix, pos);
+        }
+    }
+
+    /** Ends a parse operation by ensuring that all non-whitespace characters in the string have been parsed. An exception
+     * is thrown if extra content is found.
+     * @param str the string being parsed
+     * @param pos the current parsing position
+     * @throws IllegalArgumentException if extra non-whitespace content is found past the current parsing position
+     */
+    protected void endParse(String str, ParsePosition pos) throws IllegalArgumentException {
+        consumeWhitespace(str, pos);
+        if (pos.getIndex() != str.length()) {
+            throw new CoordinateParseException("Failed to parse string: unexpected content at index " + pos.getIndex());
+        }
+    }
+
+    /** Advances {@code pos} past any whitespace characters in {@code str},
+     * starting at the current parse position index.
+     * @param str the input string
+     * @param pos the current parse position
+     */
+    protected void consumeWhitespace(String str, ParsePosition pos) {
+        int idx = pos.getIndex();
+        final int len = str.length();
+
+        for (; idx<len; ++idx) {
+            if (!Character.isWhitespace(str.codePointAt(idx))) {
+                break;
+            }
+        }
+
+        pos.setIndex(idx);
+    }
+
+    /** Returns a boolean indicating whether or not the input string {@code str}
+     * contains the string {@code seq} at the given parse index. If the match succeeds,
+     * the index of {@code pos} is moved to the first character after the match. If
+     * the match does not succeed, the parse position is left unchanged.
+     * @param str the string to match against
+     * @param seq the sequence to look for in {@code str}
+     * @param pos the parse position indicating the index in {@code str}
+     *      to attempt the match
+     * @return true if {@code str} contains exactly the same characters as {@code seq}
+     *      at {@code pos}; otherwise, false
+     */
+    protected boolean matchSequence(String str, String seq, ParsePosition pos) {
+        final int idx = pos.getIndex();
+        final int inputLength = str.length();
+        final int seqLength = seq.length();
+
+        int i = idx;
+        int s = 0;
+        for (; i<inputLength && s<seqLength; ++i, ++s) {
+            if (str.codePointAt(i) != seq.codePointAt(s)) {
+                break;
+            }
+        }
+
+        if (i <= inputLength && s == seqLength) {
+            pos.setIndex(idx + seqLength);
+            return true;
+        }
+        return false;
+    }
+
+    /** Reads the string given by {@code seq} from the given position in {@code str}.
+     * Throws an IllegalArgumentException if the sequence is not found at that position.
+     * @param str the string to match against
+     * @param seq the sequence to look for in {@code str}
+     * @param pos the parse position indicating the index in {@code str}
+     *      to attempt the match
+     * @throws IllegalArgumentException if {@code str} does not contain the characters from
+     *      {@code seq} at position {@code pos}
+     */
+    protected void readSequence(String str, String seq, ParsePosition pos) throws IllegalArgumentException {
+        if (!matchSequence(str, seq, pos)) {
+            final int idx = pos.getIndex();
+            final String actualSeq = str.substring(idx, Math.min(str.length(), idx + seq.length()));
+
+            throw new CoordinateParseException("Failed to parse string: expected \"" + seq +
+                    "\" but found \"" + actualSeq + "\" at index " + idx);
+        }
+    }
+
+    /** Exception class for errors occurring during coordinate parsing.
+     */
+    private static class CoordinateParseException extends IllegalArgumentException {
+
+        /** Serializable version identifier */
+        private static final long serialVersionUID = 1494716029613981959L;
+
+        /** Simple constructor.
+         * @param msg the exception message.
+         */
+        public CoordinateParseException(String msg) {
+            super(msg);
+        }
+
+        /** Simple constructor with cause.
+         * @param msg the exception message
+         * @param cause the exception root cause
+         */
+        public CoordinateParseException(String msg, Throwable cause) {
+            super(msg, cause);
+        }
+    }
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java
new file mode 100644
index 0000000..fcafd4f
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.util;
+
+/** Utility class for working with coordinate tuples.
+ */
+public class Coordinates {
+
+    /** Interface for classes that create new instances of a type from a single coordinate value.
+     * @param <T> The type created by this factory.
+     */
+    public static interface Factory1D<T> {
+
+        /** Creates a new instance of type T from the given coordinate value.
+         * @param v the first coordinate value
+         * @return a new instance of type T
+         */
+        T create(double v);
+    }
+
+    /** Interface for classes that create new instances of a type from two coordinate values.
+     * @param <T> The type created by this factory.
+     */
+    public static interface Factory2D<T> {
+
+        /** Creates a new instance of type T from the given coordinate values.
+         * @param v1 the first coordinate value
+         * @param v2 the second coordinate value
+         * @return a new instance of type T
+         */
+        T create(double v1, double v2);
+    }
+
+    /** Interface for classes that create new instances of a type from three coordinate values.
+     * @param <T> The type created by this factory.
+     */
+    public static interface Factory3D<T> {
+
+        /** Creates a new instance of type T from the given coordinate values.
+         * @param v1 the first coordinate value
+         * @param v2 the second coordinate value
+         * @param v3 the third coordinate value
+         * @return a new instance of type T
+         */
+        T create(double v1, double v2, double v3);
+    }
+
+    /** Private constructor. */
+    private Coordinates() {
+    }
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java
new file mode 100644
index 0000000..fd66e45
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.util;
+
+import java.text.ParsePosition;
+
+/** Class for performing simple formatting and parsing of coordinate tuples in common dimensions.
+ */
+public class SimpleCoordinateFormat extends AbstractCoordinateParser {
+
+    /** Default coordinate separator value */
+    private static final String DEFAULT_SEPARATOR = ",";
+
+    /** Space character */
+    private static final String SPACE = " ";
+
+    /** Creates a new format instance with the default separator value and the given
+     * tuple prefix and suffix.
+     * @param prefix coordinate tuple prefix; may be null
+     * @param suffix coordinate tuple suffix; may be null
+     */
+    public SimpleCoordinateFormat(String prefix, String suffix) {
+        this(DEFAULT_SEPARATOR, prefix, suffix);
+    }
+
+    /** Creates a new format instance with the given separator, prefix, and suffix.
+     * @param separator string separating coordinate values
+     * @param prefix coordinate tuple prefix; may be null
+     * @param suffix coordinate tuple suffix; may be null
+     */
+    public SimpleCoordinateFormat(String separator, String prefix, String suffix) {
+        super(separator, prefix, suffix);
+    }
+
+    /** Returns a 1D coordinate tuple string with the given value.
+     * @param v coordinate value
+     * @return 1D coordinate tuple string
+     */
+    public String format1D(double v) {
+        StringBuilder sb = new StringBuilder();
+
+        if (getPrefix() != null) {
+            sb.append(getPrefix());
+        }
+
+        sb.append(v);
+
+        if (getSuffix() != null) {
+            sb.append(getSuffix());
+        }
+
+        return sb.toString();
+    }
+
+    /** Returns a 2D coordinate tuple string with the given values.
+     * @param v1 first coordinate value
+     * @param v2 second coordinate value
+     * @return 2D coordinate tuple string
+     */
+    public String format2D(double v1, double v2) {
+        StringBuilder sb = new StringBuilder();
+
+        if (getPrefix() != null) {
+            sb.append(getPrefix());
+        }
+
+        sb.append(v1);
+        sb.append(getSeparator());
+        sb.append(SPACE);
+        sb.append(v2);
+
+        if (getSuffix() != null) {
+            sb.append(getSuffix());
+        }
+
+        return sb.toString();
+    }
+
+    /** Returns a 3D coordinate tuple string with the given values.
+     * @param v1 first coordinate value
+     * @param v2 second coordinate value
+     * @param v3 third coordinate value
+     * @return 3D coordinate tuple string
+     */
+    public String format3D(double v1, double v2, double v3) {
+        StringBuilder sb = new StringBuilder();
+
+        if (getPrefix() != null) {
+            sb.append(getPrefix());
+        }
+
+        sb.append(v1);
+        sb.append(getSeparator());
+        sb.append(SPACE);
+        sb.append(v2);
+        sb.append(getSeparator());
+        sb.append(SPACE);
+        sb.append(v3);
+
+        if (getSuffix() != null) {
+            sb.append(getSuffix());
+        }
+
+        return sb.toString();
+    }
+
+    /** Parses the given string as a 1D coordinate tuple and passes the coordinate value to the
+     * given factory. The object created by the factory is returned.
+     * @param str the string to be parsed
+     * @param factory object that will be passed the parsed coordinate value
+     * @return object created by {@code factory}
+     * @throws IllegalArgumentException if the input string format is invalid
+     */
+    public <T> T parse1D(String str, Coordinates.Factory1D<T> factory) throws IllegalArgumentException {
+        final ParsePosition pos = new ParsePosition(0);
+
+        readPrefix(str, pos);
+        final double v = readCoordinateValue(str, pos);
+        readSuffix(str, pos);
+        endParse(str, pos);
+
+        return factory.create(v);
+    }
+
+    /** Parses the given string as a 2D coordinate tuple and passes the coordinate values to the
+     * given factory. The object created by the factory is returned.
+     * @param str the string to be parsed
+     * @param factory object that will be passed the parsed coordinate values
+     * @return object created by {@code factory}
+     * @throws IllegalArgumentException if the input string format is invalid
+     */
+    public <T> T parse2D(String str, Coordinates.Factory2D<T> factory) throws IllegalArgumentException {
+        final ParsePosition pos = new ParsePosition(0);
+
+        readPrefix(str, pos);
+        final double v1 = readCoordinateValue(str, pos);
+        final double v2 = readCoordinateValue(str, pos);
+        readSuffix(str, pos);
+        endParse(str, pos);
+
+        return factory.create(v1, v2);
+    }
+
+    /** Parses the given string as a 3D coordinate tuple and passes the coordinate values to the
+     * given factory. The object created by the factory is returned.
+     * @param str the string to be parsed
+     * @param factory object that will be passed the parsed coordinate values
+     * @return object created by {@code factory}
+     * @throws IllegalArgumentException if the input string format is invalid
+     */
+    public <T> T parse3D(String str, Coordinates.Factory3D<T> factory) throws IllegalArgumentException {
+        ParsePosition pos = new ParsePosition(0);
+
+        readPrefix(str, pos);
+        final double v1 = readCoordinateValue(str, pos);
+        final double v2 = readCoordinateValue(str, pos);
+        final double v3 = readCoordinateValue(str, pos);
+        readSuffix(str, pos);
+        endParse(str, pos);
+
+        return factory.create(v1, v2, v3);
+    }
+}
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java
new file mode 100644
index 0000000..820d3f6
--- /dev/null
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java
@@ -0,0 +1,453 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SimpleCoordinateFormatTest {
+
+    private static final double EPS = 1e-10;
+
+    private static final String COMMA = ",";
+    private static final String OPEN_PAREN = "(";
+    private static final String CLOSE_PAREN = ")";
+
+    private static Coordinates.Factory1D<Stub1D> FACTORY_1D = new Coordinates.Factory1D<Stub1D>() {
+
+        @Override
+        public Stub1D create(double v) {
+            Stub1D result = new Stub1D();
+            result.v = v;
+
+            return result;
+        }
+    };
+
+    private static Coordinates.Factory2D<Stub2D> FACTORY_2D = new Coordinates.Factory2D<Stub2D>() {
+
+        @Override
+        public Stub2D create(double v1, double v2) {
+            Stub2D result = new Stub2D();
+            result.v1 = v1;
+            result.v2 = v2;
+
+            return result;
+        }
+    };
+
+    private static Coordinates.Factory3D<Stub3D> FACTORY_3D = new Coordinates.Factory3D<Stub3D>() {
+
+        @Override
+        public Stub3D create(double v1, double v2, double v3) {
+            Stub3D result = new Stub3D();
+            result.v1 = v1;
+            result.v2 = v2;
+            result.v3 = v3;
+
+            return result;
+        }
+    };
+
+    @Test
+    public void testConstructor() {
+        // act
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("|", "{", "}");
+
+        // assert
+        Assert.assertEquals("|", formatter.getSeparator());
+        Assert.assertEquals("{", formatter.getPrefix());
+        Assert.assertEquals("}", formatter.getSuffix());
+    }
+
+    @Test
+    public void testConstructor_defaultSeparator() {
+        // act
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("{", "}");
+
+        // assert
+        Assert.assertEquals(COMMA, formatter.getSeparator());
+        Assert.assertEquals("{", formatter.getPrefix());
+        Assert.assertEquals("}", formatter.getSuffix());
+    }
+
+    @Test
+    public void testFormat1D() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+
+        // act/assert
+        Assert.assertEquals("(1.0)", formatter.format1D(1.0));
+        Assert.assertEquals("(-1.0)", formatter.format1D(-1.0));
+        Assert.assertEquals("(NaN)", formatter.format1D(Double.NaN));
+        Assert.assertEquals("(-Infinity)", formatter.format1D(Double.NEGATIVE_INFINITY));
+        Assert.assertEquals("(Infinity)", formatter.format1D(Double.POSITIVE_INFINITY));
+    }
+
+    @Test
+    public void testFormat1D_noPrefixSuffix() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+
+        // act/assert
+        Assert.assertEquals("1.0", formatter.format1D(1.0));
+        Assert.assertEquals("-1.0", formatter.format1D(-1.0));
+        Assert.assertEquals("NaN", formatter.format1D(Double.NaN));
+        Assert.assertEquals("-Infinity", formatter.format1D(Double.NEGATIVE_INFINITY));
+        Assert.assertEquals("Infinity", formatter.format1D(Double.POSITIVE_INFINITY));
+    }
+
+    @Test
+    public void testFormat2D() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+
+        // act/assert
+        Assert.assertEquals("(1.0, -1.0)", formatter.format2D(1.0, -1.0));
+        Assert.assertEquals("(-1.0, 1.0)", formatter.format2D(-1.0, 1.0));
+        Assert.assertEquals("(NaN, -Infinity)", formatter.format2D(Double.NaN, Double.NEGATIVE_INFINITY));
+        Assert.assertEquals("(-Infinity, Infinity)", formatter.format2D(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+    }
+
+    @Test
+    public void testFormat2D_noPrefixSuffix() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+
+        // act/assert
+        Assert.assertEquals("1.0, -1.0", formatter.format2D(1.0, -1.0));
+        Assert.assertEquals("-1.0, 1.0", formatter.format2D(-1.0, 1.0));
+        Assert.assertEquals("NaN, -Infinity", formatter.format2D(Double.NaN, Double.NEGATIVE_INFINITY));
+        Assert.assertEquals("-Infinity, Infinity", formatter.format2D(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+    }
+
+    @Test
+    public void testFormat3D() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+
+        // act/assert
+        Assert.assertEquals("(1.0, 0.0, -1.0)", formatter.format3D(1.0, 0.0, -1.0));
+        Assert.assertEquals("(-1.0, 1.0, 0.0)", formatter.format3D(-1.0, 1.0, 0.0));
+        Assert.assertEquals("(NaN, -Infinity, Infinity)", formatter.format3D(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+    }
+
+    @Test
+    public void testFormat3D_noPrefixSuffix() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+
+        // act/assert
+        Assert.assertEquals("1.0, 0.0, -1.0", formatter.format3D(1.0, 0.0, -1.0));
+        Assert.assertEquals("-1.0, 1.0, 0.0", formatter.format3D(-1.0, 1.0, 0.0));
+        Assert.assertEquals("NaN, -Infinity, Infinity", formatter.format3D(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+    }
+
+    @Test
+    public void testFormat_longTokens() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("||", "<<", ">>");
+
+        // act/assert
+        Assert.assertEquals("<<1.0>>", formatter.format1D(1.0));
+        Assert.assertEquals("<<1.0|| 2.0>>", formatter.format2D(1.0, 2.0));
+        Assert.assertEquals("<<1.0|| 2.0|| 3.0>>", formatter.format3D(1.0, 2.0, 3.0));
+    }
+
+    @Test
+    public void testParse1D() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+
+        // act/assert
+        checkParse1D(formatter, "(1)", 1.0);
+        checkParse1D(formatter, "(-1)", -1.0);
+
+        checkParse1D(formatter, "(0.01)", 0.01);
+        checkParse1D(formatter, "(-1e-2)", -0.01);
+
+        checkParse1D(formatter, "(100)", 100);
+        checkParse1D(formatter, "(-1e2)", -100);
+
+        checkParse1D(formatter, " (\n 1 \t) ", 1);
+        checkParse1D(formatter, "\n ( -1 \t)\r\n", -1);
+
+        checkParse1D(formatter, "(1, )", 1.0);
+        checkParse1D(formatter, "(-1, )", -1.0);
+
+        checkParse1D(formatter, "(NaN)", Double.NaN);
+        checkParse1D(formatter, "(-Infinity)", Double.NEGATIVE_INFINITY);
+        checkParse1D(formatter, "(Infinity)", Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testParse1D_noPrefixSuffix() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+
+        // act/assert
+        checkParse1D(formatter, "1", 1.0);
+        checkParse1D(formatter, "-1", -1.0);
+
+        checkParse1D(formatter, "0.01", 0.01);
+        checkParse1D(formatter, "-1e-2", -0.01);
+
+        checkParse1D(formatter, "100", 100);
+        checkParse1D(formatter, "-1e2", -100);
+
+        checkParse1D(formatter, " \n 1 \t ", 1);
+        checkParse1D(formatter, "\n  -1 \t\r\n", -1);
+
+        checkParse1D(formatter, "1, ", 1.0);
+        checkParse1D(formatter, "-1, ", -1.0);
+
+        checkParse1D(formatter, "NaN", Double.NaN);
+        checkParse1D(formatter, "-Infinity", Double.NEGATIVE_INFINITY);
+        checkParse1D(formatter, "Infinity", Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testParse1D_failure() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+
+        // act/assert
+        checkParse1DFailure(formatter, "", "expected \"(\" but found \"\" at index 0");
+        checkParse1DFailure(formatter, "(1 ", "expected \")\" but found \"\" at index 3");
+
+        checkParse1DFailure(formatter, "(abc)", "Failed to parse number from string at index 1: abc");
+
+        checkParse1DFailure(formatter, "(1) 1", "unexpected content at index 4");
+    }
+
+    @Test
+    public void testParse2D() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+
+        // act/assert
+        checkParse2D(formatter, "(1,-2)", 1.0, -2.0);
+        checkParse2D(formatter, "(2,-1)", 2.0, -1.0);
+
+        checkParse2D(formatter, "(0.01, -0.02)", 0.01, -0.02);
+        checkParse2D(formatter, "(-1e-2,2e-2)", -0.01, 0.02);
+
+        checkParse2D(formatter, "(100,  -1e2)", 100, -100);
+
+        checkParse2D(formatter, " (\n 1 , 2 \t) ", 1, 2);
+        checkParse2D(formatter, "\n ( -1 , -2 \t)\r\n", -1, -2);
+
+        checkParse2D(formatter, "(1, 2, )", 1.0, 2.0);
+        checkParse2D(formatter, "(-1, -2,)", -1.0, -2.0);
+
+        checkParse2D(formatter, "(NaN, -Infinity)", Double.NaN, Double.NEGATIVE_INFINITY);
+        checkParse2D(formatter, "(-Infinity, Infinity)", Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testParse2D_noPrefixSuffix() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+
+        // act/assert
+        checkParse2D(formatter, "1,-2", 1.0, -2.0);
+        checkParse2D(formatter, "2,-1", 2.0, -1.0);
+
+        checkParse2D(formatter, "0.01, -0.02", 0.01, -0.02);
+        checkParse2D(formatter, "-1e-2,2e-2", -0.01, 0.02);
+
+        checkParse2D(formatter, "100,  -1e2", 100, -100);
+
+        checkParse2D(formatter, " \n 1 , 2 \t ", 1, 2);
+        checkParse2D(formatter, "\n  -1 , -2 \t\r\n", -1, -2);
+
+        checkParse2D(formatter, "1, 2, ", 1.0, 2.0);
+        checkParse2D(formatter, "-1, -2,", -1.0, -2.0);
+
+        checkParse2D(formatter, "NaN, -Infinity", Double.NaN, Double.NEGATIVE_INFINITY);
+        checkParse2D(formatter, "-Infinity, Infinity", Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testParse2D_failure() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+
+        // act/assert
+        checkParse2DFailure(formatter, "", "expected \"(\" but found \"\" at index 0");
+        checkParse2DFailure(formatter, "(1, 2 ", "expected \")\" but found \"\" at index 6");
+
+        checkParse2DFailure(formatter, "(0,abc)", "Failed to parse number from string at index 3: abc");
+
+        checkParse2DFailure(formatter, "(1, 2) 1", "unexpected content at index 7");
+    }
+
+    @Test
+    public void testParse3D() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+
+        // act/assert
+        checkParse3D(formatter, "(1,-2,3)", 1.0, -2.0, 3.0);
+        checkParse3D(formatter, "(2,-1,3)", 2.0, -1.0, 3.0);
+
+        checkParse3D(formatter, "(0.01, -0.02, 0.3)", 0.01, -0.02, 0.3);
+        checkParse3D(formatter, "(-1e-2,2e-2,-3E-1)", -0.01, 0.02, -0.3);
+
+        checkParse3D(formatter, "(100,  -1e2,2E10)", 100, -100, 2e10);
+
+        checkParse3D(formatter, " (\n 1 , 2 , 3 \t) ", 1, 2, 3);
+        checkParse3D(formatter, "\n ( -1 , -2 ,  -3 \t)\r\n", -1, -2, -3);
+
+        checkParse3D(formatter, "(1, 2, 3, )", 1.0, 2.0, 3.0);
+        checkParse3D(formatter, "(-1, -2, -3,)", -1.0, -2.0, -3.0);
+
+        checkParse3D(formatter, "(NaN, -Infinity, Infinity)", Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testParse3D_noPrefixSuffix() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null);
+
+        // act/assert
+        checkParse3D(formatter, "1,-2,3", 1.0, -2.0, 3.0);
+        checkParse3D(formatter, "2,-1,3", 2.0, -1.0, 3.0);
+
+        checkParse3D(formatter, "0.01, -0.02, 0.3", 0.01, -0.02, 0.3);
+        checkParse3D(formatter, "-1e-2,2e-2,-3E-1", -0.01, 0.02, -0.3);
+
+        checkParse3D(formatter, "100,  -1e2,2E10", 100, -100, 2e10);
+
+        checkParse3D(formatter, " \n 1 , 2 , 3 \t ", 1, 2, 3);
+        checkParse3D(formatter, "\n  -1 , -2 ,  -3 \t\r\n", -1, -2, -3);
+
+        checkParse3D(formatter, "1, 2, 3, ", 1.0, 2.0, 3.0);
+        checkParse3D(formatter, "-1, -2, -3,", -1.0, -2.0, -3.0);
+
+        checkParse3D(formatter, "NaN, -Infinity, Infinity", Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testParse3D_failure() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN);
+
+        // act/assert
+        checkParse3DFailure(formatter, "", "expected \"(\" but found \"\" at index 0");
+        checkParse3DFailure(formatter, "(1, 2, 3", "expected \")\" but found \"\" at index 8");
+
+        checkParse3DFailure(formatter, "(0,0,abc)", "Failed to parse number from string at index 5: abc");
+
+        checkParse3DFailure(formatter, "(1, 2, 3) 1", "unexpected content at index 10");
+    }
+
+    @Test
+    public void testParse_longTokens() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("||", "<<", ">>");
+
+        // act/assert
+        checkParse1D(formatter, "<<1.0>>", 1.0);
+        checkParse2D(formatter, "<<1.0|| 2.0>>", 1.0, 2.0);
+        checkParse3D(formatter, "<<1.0|| 2.0|| 3.0>>", 1.0, 2.0, 3.0);
+    }
+
+    @Test
+    public void testParse_longTokens_failure() {
+        // arrange
+        SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("||", "<<", ">>");
+
+        // act/assert
+        checkParse1DFailure(formatter, "<", "expected \"<<\" but found \"<\" at index 0");
+        checkParse1DFailure(formatter, "<1.0>>", "expected \"<<\" but found \"<1\" at index 0");
+        checkParse2DFailure(formatter, "<<1.0| 2.0>>", "Failed to parse number from string at index 2: 1.0| 2.0");
+        checkParse3DFailure(formatter, "<<1.0|| 2.0|| 3.0>", "Failed to parse number from string at index 13:  3.0>");
+    }
+
+    private void checkParse1D(SimpleCoordinateFormat formatter, String str, double v) {
+        Stub1D result = formatter.parse1D(str, FACTORY_1D);
+
+        Assert.assertEquals(v, result.v, EPS);
+    }
+
+    private void checkParse1DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) {
+        try {
+            formatter.parse1D(str, FACTORY_1D);
+            Assert.fail("Operation should have failed");
+        }
+        catch (IllegalArgumentException exc) {
+            String excMsg = exc.getMessage();
+            Assert.assertTrue("Expected message to contain [" + msgSubstr + "] but was [" + excMsg + "]",
+                    excMsg.contains(msgSubstr));
+        }
+    }
+
+    private void checkParse2D(SimpleCoordinateFormat formatter, String str, double v1, double v2) {
+        Stub2D result = formatter.parse2D(str, FACTORY_2D);
+
+        Assert.assertEquals(v1, result.v1, EPS);
+        Assert.assertEquals(v2, result.v2, EPS);
+    }
+
+    private void checkParse2DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) {
+        try {
+            formatter.parse2D(str, FACTORY_2D);
+            Assert.fail("Operation should have failed");
+        }
+        catch (IllegalArgumentException exc) {
+            String excMsg = exc.getMessage();
+            Assert.assertTrue("Expected message to contain [" + msgSubstr + "] but was [" + excMsg + "]",
+                    excMsg.contains(msgSubstr));
+        }
+    }
+
+    private void checkParse3D(SimpleCoordinateFormat formatter, String str, double v1, double v2, double v3) {
+        Stub3D result = formatter.parse3D(str, FACTORY_3D);
+
+        Assert.assertEquals(v1, result.v1, EPS);
+        Assert.assertEquals(v2, result.v2, EPS);
+        Assert.assertEquals(v3, result.v3, EPS);
+    }
+
+    private void checkParse3DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) {
+        try {
+            formatter.parse3D(str, FACTORY_3D);
+            Assert.fail("Operation should have failed");
+        }
+        catch (IllegalArgumentException exc) {
+            String excMsg = exc.getMessage();
+            Assert.assertTrue("Expected message to contain [" + msgSubstr + "] but was [" + excMsg + "]",
+                    excMsg.contains(msgSubstr));
+        }
+    }
+
+    private static class Stub1D {
+        public double v;
+    }
+
+    private static class Stub2D {
+        public double v1;
+        public double v2;
+    }
+
+    private static class Stub3D {
+        public double v1;
+        public double v2;
+        public double v3;
+    }
+}


[commons-geometry] 06/08: GEOMETRY-3: replacing class internal use of factory method with calls to constructor

Posted by er...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 9cdec0393b650ad54d1be9d3c198da76c7b924c7
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Wed Jun 6 21:10:33 2018 -0400

    GEOMETRY-3: replacing class internal use of factory method with calls to constructor
---
 .../commons/geometry/euclidean/oned/Point1D.java   | 12 +++----
 .../commons/geometry/euclidean/oned/Vector1D.java  | 22 ++++++------
 .../commons/geometry/euclidean/threed/Point3D.java | 10 +++---
 .../geometry/euclidean/threed/Vector3D.java        | 40 +++++++++++-----------
 .../commons/geometry/euclidean/twod/Point2D.java   | 10 +++---
 .../commons/geometry/euclidean/twod/Vector2D.java  | 28 +++++++--------
 6 files changed, 61 insertions(+), 61 deletions(-)

diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
index c6e6910..3715c69 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
@@ -27,23 +27,23 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D, Vector1D> {
 
     /** Origin (coordinates: 0). */
-    public static final Point1D ZERO = Point1D.of(0.0);
+    public static final Point1D ZERO = new Point1D(0.0);
 
     /** Unit (coordinates: 1). */
-    public static final Point1D ONE  = Point1D.of(1.0);
+    public static final Point1D ONE  = new Point1D(1.0);
 
     // CHECKSTYLE: stop ConstantName
     /** A vector with all coordinates set to NaN. */
-    public static final Point1D NaN = Point1D.of(Double.NaN);
+    public static final Point1D NaN = new Point1D(Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A point with all coordinates set to positive infinity. */
     public static final Point1D POSITIVE_INFINITY =
-        Point1D.of(Double.POSITIVE_INFINITY);
+        new Point1D(Double.POSITIVE_INFINITY);
 
     /** A point with all coordinates set to negative infinity. */
     public static final Point1D NEGATIVE_INFINITY =
-        Point1D.of(Double.NEGATIVE_INFINITY);
+        new Point1D(Double.NEGATIVE_INFINITY);
 
     /** Serializable UID. */
     private static final long serialVersionUID = 7556674948671647925L;
@@ -92,7 +92,7 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D
     /** {@inheritDoc} */
     @Override
     public Point1D add(Vector1D v) {
-        return Point1D.of(getX() + v.getX());
+        return new Point1D(getX() + v.getX());
     }
 
     /**
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
index 5d79379..0aab089 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
@@ -27,23 +27,23 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public final class Vector1D extends Cartesian1D implements EuclideanVector<Point1D, Vector1D> {
 
     /** Zero vector (coordinates: 0). */
-    public static final Vector1D ZERO = Vector1D.of(0.0);
+    public static final Vector1D ZERO = new Vector1D(0.0);
 
     /** Unit vector (coordinates: 1). */
-    public static final Vector1D ONE  = Vector1D.of(1.0);
+    public static final Vector1D ONE  = new Vector1D(1.0);
 
     // CHECKSTYLE: stop ConstantName
     /** A vector with all coordinates set to NaN. */
-    public static final Vector1D NaN = Vector1D.of(Double.NaN);
+    public static final Vector1D NaN = new Vector1D(Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A vector with all coordinates set to positive infinity. */
     public static final Vector1D POSITIVE_INFINITY =
-        Vector1D.of(Double.POSITIVE_INFINITY);
+        new Vector1D(Double.POSITIVE_INFINITY);
 
     /** A vector with all coordinates set to negative infinity. */
     public static final Vector1D NEGATIVE_INFINITY =
-        Vector1D.of(Double.NEGATIVE_INFINITY);
+        new Vector1D(Double.NEGATIVE_INFINITY);
 
     /** Serializable UID. */
     private static final long serialVersionUID = 1582116020164328846L;
@@ -104,31 +104,31 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector1D add(Vector1D v) {
-        return Vector1D.of(getX() + v.getX());
+        return new Vector1D(getX() + v.getX());
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector1D add(double factor, Vector1D v) {
-        return Vector1D.of(getX() + (factor * v.getX()));
+        return new Vector1D(getX() + (factor * v.getX()));
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector1D subtract(Vector1D v) {
-        return Vector1D.of(getX() - v.getX());
+        return new Vector1D(getX() - v.getX());
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector1D subtract(double factor, Vector1D v) {
-        return Vector1D.of(getX() - (factor * v.getX()));
+        return new Vector1D(getX() - (factor * v.getX()));
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector1D negate() {
-        return Vector1D.of(-getX());
+        return new Vector1D(-getX());
     }
 
     /** {@inheritDoc} */
@@ -144,7 +144,7 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector1D scalarMultiply(double a) {
-        return Vector1D.of(a * getX());
+        return new Vector1D(a * getX());
     }
 
     /** {@inheritDoc} */
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
index 2093292..f257425 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
@@ -28,20 +28,20 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D, Vector3D> {
 
     /** Zero point (coordinates: 0, 0, 0). */
-    public static final Point3D ZERO   = Point3D.of(0, 0, 0);
+    public static final Point3D ZERO   = new Point3D(0, 0, 0);
 
     // CHECKSTYLE: stop ConstantName
     /** A point with all coordinates set to NaN. */
-    public static final Point3D NaN = Point3D.of(Double.NaN, Double.NaN, Double.NaN);
+    public static final Point3D NaN = new Point3D(Double.NaN, Double.NaN, Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A point with all coordinates set to positive infinity. */
     public static final Point3D POSITIVE_INFINITY =
-        Point3D.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+        new Point3D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
 
     /** A point with all coordinates set to negative infinity. */
     public static final Point3D NEGATIVE_INFINITY =
-        Point3D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+        new Point3D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
 
     /** Serializable version identifier. */
     private static final long serialVersionUID = 1313493323784566947L;
@@ -97,7 +97,7 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
     /** {@inheritDoc} */
     @Override
     public Point3D add(Vector3D v) {
-        return Point3D.of(
+        return new Point3D(
                     getX() + v.getX(),
                     getY() + v.getY(),
                     getZ() + v.getZ()
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
index 85246ab..9d1f258 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
@@ -27,38 +27,38 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public final class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Vector3D> {
 
     /** Zero (null) vector (coordinates: 0, 0, 0). */
-    public static final Vector3D ZERO   = Vector3D.of(0, 0, 0);
+    public static final Vector3D ZERO   = new Vector3D(0, 0, 0);
 
     /** First canonical vector (coordinates: 1, 0, 0). */
-    public static final Vector3D PLUS_X = Vector3D.of(1, 0, 0);
+    public static final Vector3D PLUS_X = new Vector3D(1, 0, 0);
 
     /** Opposite of the first canonical vector (coordinates: -1, 0, 0). */
-    public static final Vector3D MINUS_X = Vector3D.of(-1, 0, 0);
+    public static final Vector3D MINUS_X = new Vector3D(-1, 0, 0);
 
     /** Second canonical vector (coordinates: 0, 1, 0). */
-    public static final Vector3D PLUS_Y = Vector3D.of(0, 1, 0);
+    public static final Vector3D PLUS_Y = new Vector3D(0, 1, 0);
 
     /** Opposite of the second canonical vector (coordinates: 0, -1, 0). */
-    public static final Vector3D MINUS_Y = Vector3D.of(0, -1, 0);
+    public static final Vector3D MINUS_Y = new Vector3D(0, -1, 0);
 
     /** Third canonical vector (coordinates: 0, 0, 1). */
-    public static final Vector3D PLUS_Z = Vector3D.of(0, 0, 1);
+    public static final Vector3D PLUS_Z = new Vector3D(0, 0, 1);
 
     /** Opposite of the third canonical vector (coordinates: 0, 0, -1).  */
-    public static final Vector3D MINUS_Z = Vector3D.of(0, 0, -1);
+    public static final Vector3D MINUS_Z = new Vector3D(0, 0, -1);
 
  // CHECKSTYLE: stop ConstantName
     /** A vector with all coordinates set to NaN. */
-    public static final Vector3D NaN = Vector3D.of(Double.NaN, Double.NaN, Double.NaN);
+    public static final Vector3D NaN = new Vector3D(Double.NaN, Double.NaN, Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A vector with all coordinates set to positive infinity. */
     public static final Vector3D POSITIVE_INFINITY =
-        Vector3D.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+        new Vector3D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
 
     /** A vector with all coordinates set to negative infinity. */
     public static final Vector3D NEGATIVE_INFINITY =
-        Vector3D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+        new Vector3D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
 
     /** Serializable UID */
     private static final long serialVersionUID = 3695385854431542858L;
@@ -147,7 +147,7 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector3D add(Vector3D v) {
-        return Vector3D.of(
+        return new Vector3D(
                     getX() + v.getX(),
                     getY() + v.getY(),
                     getZ() + v.getZ()
@@ -157,7 +157,7 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector3D add(double factor, Vector3D v) {
-        return Vector3D.of(
+        return new Vector3D(
                     getX() + (factor * v.getX()),
                     getY() + (factor * v.getY()),
                     getZ() + (factor * v.getZ())
@@ -167,7 +167,7 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector3D subtract(Vector3D v) {
-        return Vector3D.of(
+        return new Vector3D(
                     getX() - v.getX(),
                     getY() - v.getY(),
                     getZ() - v.getZ()
@@ -177,7 +177,7 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector3D subtract(double factor, Vector3D v) {
-        return Vector3D.of(
+        return new Vector3D(
                     getX() - (factor * v.getX()),
                     getY() - (factor * v.getY()),
                     getZ() - (factor * v.getZ())
@@ -187,7 +187,7 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector3D negate() {
-        return Vector3D.of(-getX(), -getY(), -getZ());
+        return new Vector3D(-getX(), -getY(), -getZ());
     }
 
     /** {@inheritDoc} */
@@ -227,13 +227,13 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
 
         if (Math.abs(x) <= threshold) {
             double inverse  = 1 / Math.sqrt(y * y + z * z);
-            return Vector3D.of(0, inverse * z, -inverse * y);
+            return new Vector3D(0, inverse * z, -inverse * y);
         } else if (Math.abs(y) <= threshold) {
             double inverse  = 1 / Math.sqrt(x * x + z * z);
-            return Vector3D.of(-inverse * z, 0, inverse * x);
+            return new Vector3D(-inverse * z, 0, inverse * x);
         }
         double inverse  = 1 / Math.sqrt(x * x + y * y);
-        return Vector3D.of(inverse * y, -inverse * x, 0);
+        return new Vector3D(inverse * y, -inverse * x, 0);
     }
 
     /** Compute the angular separation between two vectors.
@@ -272,7 +272,7 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
      * @return the cross product this ^ v as a new Cartesian3D
      */
     public Vector3D crossProduct(final Vector3D v) {
-        return Vector3D.of(LinearCombination.value(getY(), v.getZ(), -getZ(), v.getY()),
+        return new Vector3D(LinearCombination.value(getY(), v.getZ(), -getZ(), v.getY()),
                             LinearCombination.value(getZ(), v.getX(), -getX(), v.getZ()),
                             LinearCombination.value(getX(), v.getY(), -getY(), v.getX()));
     }
@@ -280,7 +280,7 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector3D scalarMultiply(double a) {
-        return Vector3D.of(a * getX(), a * getY(), a * getZ());
+        return new Vector3D(a * getX(), a * getY(), a * getZ());
     }
 
     /** {@inheritDoc} */
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
index 4175d11..c32777a 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
@@ -27,20 +27,20 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D, Vector2D> {
 
     /** Origin (coordinates: 0, 0). */
-    public static final Point2D ZERO   = Point2D.of(0, 0);
+    public static final Point2D ZERO   = new Point2D(0, 0);
 
  // CHECKSTYLE: stop ConstantName
     /** A point with all coordinates set to NaN. */
-    public static final Point2D NaN = Point2D.of(Double.NaN, Double.NaN);
+    public static final Point2D NaN = new Point2D(Double.NaN, Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A point with all coordinates set to positive infinity. */
     public static final Point2D POSITIVE_INFINITY =
-        Point2D.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+        new Point2D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
 
     /** A point with all coordinates set to negative infinity. */
     public static final Point2D NEGATIVE_INFINITY =
-        Point2D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+        new Point2D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
 
     /** Serializable UID. */
     private static final long serialVersionUID = 266938651998679754L;
@@ -91,7 +91,7 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D
     /** {@inheritDoc} */
     @Override
     public Point2D add(Vector2D v) {
-        return Point2D.of(getX() + v.getX(), getY() + v.getY());
+        return new Point2D(getX() + v.getX(), getY() + v.getY());
     }
 
     /**
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
index e6285b1..ac8e380 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
@@ -27,32 +27,32 @@ import org.apache.commons.numbers.arrays.LinearCombination;
 public final class Vector2D extends Cartesian2D implements EuclideanVector<Point2D, Vector2D> {
 
     /** Zero vector (coordinates: 0, 0). */
-    public static final Vector2D ZERO   = Vector2D.of(0, 0);
+    public static final Vector2D ZERO   = new Vector2D(0, 0);
 
     /** Unit vector pointing in the direction of the positive x-axis. */
-    public static final Vector2D PLUS_X = Vector2D.of(1, 0);
+    public static final Vector2D PLUS_X = new Vector2D(1, 0);
 
     /** Unit vector pointing in the direction of the negative x-axis. */
-    public static final Vector2D MINUS_X = Vector2D.of(-1, 0);
+    public static final Vector2D MINUS_X = new Vector2D(-1, 0);
 
     /** Unit vector pointing in the direction of the positive y-axis. */
-    public static final Vector2D PLUS_Y = Vector2D.of(0, 1);
+    public static final Vector2D PLUS_Y = new Vector2D(0, 1);
 
     /** Unit vector pointing in the direction of the negative y-axis. */
-    public static final Vector2D MINUS_Y = Vector2D.of(0, -1);
+    public static final Vector2D MINUS_Y = new Vector2D(0, -1);
 
     // CHECKSTYLE: stop ConstantName
     /** A vector with all coordinates set to NaN. */
-    public static final Vector2D NaN = Vector2D.of(Double.NaN, Double.NaN);
+    public static final Vector2D NaN = new Vector2D(Double.NaN, Double.NaN);
     // CHECKSTYLE: resume ConstantName
 
     /** A vector with all coordinates set to positive infinity. */
     public static final Vector2D POSITIVE_INFINITY =
-        Vector2D.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+        new Vector2D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
 
     /** A vector with all coordinates set to negative infinity. */
     public static final Vector2D NEGATIVE_INFINITY =
-        Vector2D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+        new Vector2D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
 
     /** Serializable UID */
     private static final long serialVersionUID = 1746839897232305304L;
@@ -129,31 +129,31 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector2D add(Vector2D v) {
-        return Vector2D.of(getX() + v.getX(), getY() + v.getY());
+        return new Vector2D(getX() + v.getX(), getY() + v.getY());
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector2D add(double factor, Vector2D v) {
-        return Vector2D.of(getX() + (factor * v.getX()), getY() + (factor * v.getY()));
+        return new Vector2D(getX() + (factor * v.getX()), getY() + (factor * v.getY()));
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector2D subtract(Vector2D v) {
-        return Vector2D.of(getX() - v.getX(), getY() - v.getY());
+        return new Vector2D(getX() - v.getX(), getY() - v.getY());
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector2D subtract(double factor, Vector2D v) {
-        return Vector2D.of(getX() - (factor * v.getX()), getY() - (factor * v.getY()));
+        return new Vector2D(getX() - (factor * v.getX()), getY() - (factor * v.getY()));
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector2D negate() {
-        return Vector2D.of(-getX(), -getY());
+        return new Vector2D(-getX(), -getY());
     }
 
     /** {@inheritDoc} */
@@ -169,7 +169,7 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector2D scalarMultiply(double a) {
-        return Vector2D.of(a * getX(), a * getY());
+        return new Vector2D(a * getX(), a * getY());
     }
 
     /** {@inheritDoc} */