You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by js...@apache.org on 2026/10/08 10:01:31 UTC

(sis) 02/02: feat(Geometry): reorganize GeometryFactory to allow futur configuration parameters

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

asf-gitbox-commits pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit c2a9ff0285ee5f31b0549758376e4a9c3d90cce6
Author: jsorel <jo...@geomatys.com>
AuthorDate: Thu Oct 8 12:01:10 2026 +0200

    feat(Geometry): reorganize GeometryFactory to allow futur configuration parameters
---
 .../main/org/apache/sis/geometries/Curve.java      |   6 +-
 .../org/apache/sis/geometries/GeometryFactory.java | 366 +++++++++++++--------
 .../org/apache/sis/geometries/GeometryType.java    |   4 +
 .../main/org/apache/sis/geometries/HyperPlane.java |   2 +-
 .../main/org/apache/sis/geometries/Plane.java      |   2 +-
 .../main/org/apache/sis/geometries/Point.java      |   2 +-
 .../main/org/apache/sis/geometries/Ray.java        |   2 +-
 .../apache/sis/geometries/adapter/JTSAdapter.java  |  18 +-
 .../org/apache/sis/geometries/adapter/SIS.java     |  46 +--
 .../sis/geometries/adapter/ShapeAdapter.java       |   6 +-
 .../sis/geometries/adapter/ShapeConverter.java     |  14 +-
 .../geometries/adapter/WellKnownBinaryParser.java  |  66 ++--
 .../geometries/adapter/WellKnownTextParser.java    |  76 ++---
 .../org/apache/sis/geometries/adapter/Wrapper.java |  34 +-
 .../internal/shared/DefaultGeometryCollection.java |   2 +-
 .../internal/shared/DefaultMultiPoint.java         |   2 +-
 .../geometries/internal/shared/DefaultPolygon.java |   2 +-
 .../apache/sis/geometries/mesh/MeshPrimitive.java  |   8 +-
 .../sis/geometries/mesh/MeshPrimitiveVisitor.java  |   4 +-
 .../sis/geometries/operation/Intersection.java     |   4 +-
 .../org/apache/sis/geometries/operation/To3D.java  |   4 +-
 .../apache/sis/geometries/operation/Transform.java |   6 +-
 .../simplify/greedyinsert/TINBuilder.java          |   6 +-
 .../operation/simplify/greedyinsert/WTriangle.java |   2 +-
 .../triangulate/delaunay/OrientedTriangle.java     |   2 +-
 .../org/apache/sis/geometries/solid/Capsule.java   |   2 +-
 .../org/apache/sis/geometries/solid/Cylinder.java  |   2 +-
 .../org/apache/sis/geometries/solid/Ellipsoid.java | 364 ++++++++++++++++++++
 .../org/apache/sis/geometries/solid/Sphere.java    |  72 +++-
 .../solid/polyhedron/AbstractPolyhedron.java       |   4 +-
 .../geometries/surface/ParametricCurveSurface.java |   2 +
 .../main/org/apache/sis/gml/GML2Reader.java        |  16 +-
 .../main/org/apache/sis/gml/GML3Reader.java        |  62 ++--
 .../org/apache/sis/gml/PositionListBuilder.java    |   4 +-
 .../sis/geometries/adapter/ShapeAdapterTest.java   |  26 +-
 .../geometries/adapter/WellKnownBinaryTest.java    |  22 +-
 .../sis/geometries/adapter/WellKnownTextTest.java  |  12 +-
 .../sis/geometries/operation/AbstractD9IMTest.java |  14 +-
 .../sis/geometries/operation/DistanceTest.java     |  14 +-
 .../apache/sis/geometries/operation/To3DTest.java  |   2 +-
 .../sis/geometries/operation/ToPrimitiveTest.java  |  36 +-
 .../sis/geometries/surface/TriangleTest.java       |   6 +-
 .../test/org/apache/sis/gml/GML2ReaderTest.java    |  40 +--
 .../test/org/apache/sis/gml/GML2WriterTest.java    |  44 +--
 .../test/org/apache/sis/gml/GML3ReaderTest.java    |  48 +--
 .../test/org/apache/sis/gml/GML3WriterTest.java    |  60 ++--
 .../test/org/apache/sis/gml/GMLWriterTest.java     |   4 +-
 .../apache/sis/gml/JAXBGeometryAdapterTest.java    |   8 +-
 .../storage/dggs/DiscreteGlobalGridSystems.java    |   4 +-
 49 files changed, 1019 insertions(+), 535 deletions(-)

diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Curve.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Curve.java
index 4c41dca8a0..ffbeb07625 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Curve.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Curve.java
@@ -220,9 +220,9 @@ public sealed interface Curve extends Orientable
     @Override
     default Geometry getBoundary() {
         if (isEmpty() || isClosed()) {
-            return GeometryFactory.createEmpty(getCoordinateReferenceSystem());
+            return GeometryFactory.DEFAULT.createEmpty(getCoordinateReferenceSystem());
         }
-        return GeometryFactory.createMultiPoint(getStartPoint(), getEndPoint());
+        return GeometryFactory.DEFAULT.createMultiPoint(getStartPoint(), getEndPoint());
     }
 
     /**
@@ -454,7 +454,7 @@ public sealed interface Curve extends Orientable
          * not a geometry. `DefaultReversedCurve` returns this curve back from its own `getReverse()`,
          * so wrapping never nests.
          */
-        return GeometryFactory.createReversed(this);
+        return GeometryFactory.DEFAULT.createReversed(this);
     }
 
     /**
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryFactory.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryFactory.java
index 7326b09e72..86b3eb3a41 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryFactory.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryFactory.java
@@ -99,8 +99,10 @@ import org.apache.sis.geometries.internal.shared.DefaultSpiral;
 import org.apache.sis.geometries.internal.shared.DefaultTriangle;
 import org.apache.sis.geometries.internal.shared.DefaultTriangulatedSurface;
 import org.apache.sis.geometries.point.MultiPoint;
+import org.apache.sis.geometries.solid.Ellipsoid;
 import org.apache.sis.geometries.solid.MultiPolyhedron;
 import org.apache.sis.geometries.solid.Polyhedron;
+import org.apache.sis.geometries.solid.Sphere;
 import org.apache.sis.geometries.solid.BSplineSolid;
 import org.apache.sis.geometries.surface.BSplineSurface;
 import org.apache.sis.geometries.surface.BSplineSurfaceForm;
@@ -115,6 +117,7 @@ import org.apache.sis.geometries.surface.TIN;
 import org.apache.sis.geometries.surface.Triangle;
 import org.apache.sis.maths.Array;
 import org.apache.sis.maths.DataType;
+import org.apache.sis.maths.NDArrays;
 import org.apache.sis.maths.SampleSystem;
 import org.apache.sis.maths.Vector;
 import org.apache.sis.measure.NumberRange;
@@ -122,143 +125,156 @@ import org.apache.sis.measure.Range;
 
 
 /**
+ * Factory for SIS Geometry.
  *
  * @author Johann Sorel (Geomatys)
  */
 public final class GeometryFactory {
 
-    public static GeometryFactory INSTANCE = new GeometryFactory();
+    public static GeometryFactory DEFAULT = new GeometryFactory();
 
     private GeometryFactory(){
     }
 
-    public static Empty createEmpty(CoordinateReferenceSystem crs) {
-        final DataPointsType.Template attType = new DataPointsType.Template();
-        attType.addOrReplaceAttribute(DataPointsType.ATT_POSITION, SampleSystem.of(crs), DataType.DOUBLE);
-        return new DefaultEmpty(attType);
-    }
+    // ////////////////////////////////////////////////////////////////////////
+    // DataPoints /////////////////////////////////////////////////////////////
+    // ////////////////////////////////////////////////////////////////////////
 
-    public static Empty createEmpty(DataPointsType attType) {
-        return new DefaultEmpty(attType);
+    /**
+     * Create a new DataPoints from a 2D array of coordinates.
+     *
+     * @param positions in 2D
+     * @return created DataPoints
+     */
+    public DataPoints createDataPoints(double ... positions) {
+        return createDataPoints(2, positions);
     }
 
-    public static Point createPoint(CoordinateReferenceSystem crs) {
-        return new DefaultPoint(crs);
+    public DataPoints createDataPoints(int dimension, double ... positions) {
+        return createDataPoints(Geometries.getUndefinedCRS(dimension), positions);
     }
 
-    public static Point createPoint(CoordinateReferenceSystem crs, double ... position) {
-        return new DefaultPoint(crs, position);
+    public DataPoints createDataPoints(CoordinateReferenceSystem crs, double ... positions) {
+        final Array array = NDArrays.of(crs, positions);
+        return createDataPoints(array);
     }
 
-    public static Point createPoint(SampleSystem ss, double ... position) {
-        return new DefaultPoint(ss, position);
+    /**
+     * Create a new DataPoints from a 2D array of coordinates.
+     *
+     * @param positions in 2D
+     * @return created DataPoints
+     */
+    public DataPoints createDataPoints(float ... positions) {
+        return createDataPoints(2, positions);
     }
 
-    public static Point createPoint(DataPoints sequence) {
-        return new DefaultPoint(sequence);
+    public DataPoints createDataPoints(int dimension, float ... positions) {
+        return createDataPoints(Geometries.getUndefinedCRS(dimension), positions);
     }
 
-    public static LineString createLineString(DataPoints sequence) {
-        return new DefaultLineString(sequence);
+    public DataPoints createDataPoints(CoordinateReferenceSystem crs, float ... positions) {
+        final Array array = NDArrays.of(crs, positions);
+        return createDataPoints(array);
     }
 
-    public static Geodesic createGeodesic(DataPoints sequence) {
-        return new DefaultGeodesic(sequence);
+    public DataPoints createDataPoints(Array positions) {
+        return GeometryFactory.this.createDataPoints(Collections.singletonMap(DataPointsType.ATT_POSITION, positions));
     }
 
-    public static Rhumb createRhumb(DataPoints sequence) {
-        return new DefaultRhumb(sequence);
+    public DataPoints createDataPoints(Map<String, Array> attributes) {
+        return new ArrayDataPoints(attributes);
     }
 
-    public static LinearRing createLinearRing(DataPoints sequence) {
-        return new DefaultLinearRing(sequence);
+    /**
+     * Returns a copy of the given DataPoints.
+     */
+    public DataPoints createDataPoints(final DataPoints source) {
+        final Map<String,Array> attributes = new LinkedHashMap<>();
+        for (final String name : source.getType().getAttributeNames()) {
+            attributes.put(name, source.getAttributeArray(name));
+        }
+        return createDataPoints(attributes);
     }
 
-    public static Polygon createPolygon(LinearRing exterior, List<LinearRing> interiors) {
-        return new DefaultPolygon(exterior, interiors);
-    }
+    // ////////////////////////////////////////////////////////////////////////
+    // Empty //////////////////////////////////////////////////////////////////
+    // ////////////////////////////////////////////////////////////////////////
 
-    public static Triangle createTriangle(LinearRing exterior) {
-        return new DefaultTriangle(exterior);
+    public Empty createEmpty(CoordinateReferenceSystem crs) {
+        final DataPointsType.Template attType = new DataPointsType.Template();
+        attType.addOrReplaceAttribute(DataPointsType.ATT_POSITION, SampleSystem.of(crs), DataType.DOUBLE);
+        return createEmpty(attType);
     }
 
-    public static MultiPoint createMultiPoint(DataPoints sequence) {
-        return new DefaultMultiPoint(sequence);
+    public Empty createEmpty(DataPointsType attType) {
+        return new DefaultEmpty(attType);
     }
 
-    public static MultiPoint createMultiPoint(Point ... geometries) {
-        return new DefaultRawMultiPoint(geometries);
-    }
+    // ////////////////////////////////////////////////////////////////////////
+    // Points /////////////////////////////////////////////////////////////////
+    // ////////////////////////////////////////////////////////////////////////
 
-    public static MultiLineString createMultiLineString(LineString ... geometries) {
-        return new DefaultMultiLineString(geometries);
+    public Point createPoint(CoordinateReferenceSystem crs) {
+        return new DefaultPoint(crs);
     }
 
-    public static <T extends Curve> MultiCurve<T> createMultiCurve(T ... geometries) {
-        return new DefaultMultiCurve<>(geometries);
+    public Point createPoint(CoordinateReferenceSystem crs, double ... position) {
+        return new DefaultPoint(crs, position);
     }
 
-    public static MultiPolygon createMultiPolygon(Polygon ... geometries) {
-        return new DefaultMultiPolygon(geometries);
+    public Point createPoint(SampleSystem ss, double ... position) {
+        return new DefaultPoint(ss, position);
     }
 
-    public static <T extends Surface> MultiSurface<T> createMultiSurface(T ... geometries) {
-        return new DefaultMultiSurface<>(geometries);
+    public Point createPoint(DataPoints sequence) {
+        return new DefaultPoint(sequence);
     }
 
-    public static <T extends Geometry> GeometryCollection<T> createGeometryCollection(T ... geometries) {
-        return new DefaultGeometryCollection<>(geometries);
+    public MultiPoint createMultiPoint(DataPoints sequence) {
+        return new DefaultMultiPoint(sequence);
     }
 
-    /*
-     * Variants taking an explicit coordinate reference system, used when the collection may be
-     * empty. An aggregate normally reports the CRS of its first element; with no element there is
-     * nothing to report, so the CRS has to be supplied by the caller.
-     */
+    public MultiPoint createMultiPoint(Point ... geometries) {
+        return new DefaultRawMultiPoint(geometries);
+    }
 
-    public static MultiPoint createMultiPoint(CoordinateReferenceSystem crs, Point ... geometries) {
+    public MultiPoint createMultiPoint(CoordinateReferenceSystem crs, Point ... geometries) {
         return new DefaultRawMultiPoint(crs, geometries);
     }
 
-    public static MultiLineString createMultiLineString(CoordinateReferenceSystem crs, LineString ... geometries) {
-        return new DefaultMultiLineString(crs, geometries);
-    }
+    // ////////////////////////////////////////////////////////////////////////
+    // Curves /////////////////////////////////////////////////////////////////
+    // ////////////////////////////////////////////////////////////////////////
 
-    public static <T extends Curve> MultiCurve<T> createMultiCurve(CoordinateReferenceSystem crs, T ... geometries) {
-        return new DefaultMultiCurve<>(crs, geometries);
+    public LineString createLineString(DataPoints sequence) {
+        return new DefaultLineString(sequence);
     }
 
-    public static MultiPolygon createMultiPolygon(CoordinateReferenceSystem crs, Polygon ... geometries) {
-        return new DefaultMultiPolygon(crs, geometries);
+    public LinearRing createLinearRing(DataPoints sequence) {
+        return new DefaultLinearRing(sequence);
     }
 
-    public static <T extends Surface> MultiSurface<T> createMultiSurface(CoordinateReferenceSystem crs, T ... geometries) {
-        return new DefaultMultiSurface<>(crs, geometries);
+    public Geodesic createGeodesic(DataPoints sequence) {
+        return new DefaultGeodesic(sequence);
     }
 
-    public static <T extends Geometry> GeometryCollection<T> createGeometryCollection(CoordinateReferenceSystem crs, T ... geometries) {
-        return new DefaultGeometryCollection<>(crs, geometries);
+    public Rhumb createRhumb(DataPoints sequence) {
+        return new DefaultRhumb(sequence);
     }
 
-    /*
-     * Curves and surfaces beyond the linear ones, and solids. These are what the GML 3 constructs
-     * `gml:Curve`, `gml:CompositeCurve`, `gml:Ring`, `gml:ArcString`, `gml:Surface`,
-     * `gml:CompositeSurface`, `gml:Solid`, `gml:CompositeSolid` and the two `gml:Orientable*`
-     * elements map onto.
-     */
+    public CircularString createCircularString(DataPoints sequence) {
+        return new DefaultCircularString(sequence);
+    }
 
-    public static CompoundCurve createCompoundCurve(Curve ... curves) {
+    public CompoundCurve createCompoundCurve(Curve ... curves) {
         return new DefaultCompoundCurve(curves);
     }
 
-    public static CompoundCurve createCompoundCurve(CoordinateReferenceSystem crs, Curve ... curves) {
+    public CompoundCurve createCompoundCurve(CoordinateReferenceSystem crs, Curve ... curves) {
         return new DefaultCompoundCurve(crs, curves);
     }
 
-    public static CircularString createCircularString(DataPoints sequence) {
-        return new DefaultCircularString(sequence);
-    }
-
     /**
      * Creates a circular arc from the centre of its circle, that circle's radius expressed in the
      * given unit, and the bearings at which the arc starts and ends.
@@ -269,7 +285,7 @@ public final class GeometryFactory {
      * @param  startAngle  bearing at which the arc starts, in decimal degrees.
      * @param  endAngle    bearing at which the arc ends, in decimal degrees.
      */
-    public static ArcByCenterPoint createArcByCenterPoint(Point center, double radius, Unit<?> radiusUnit,
+    public ArcByCenterPoint createArcByCenterPoint(Point center, double radius, Unit<?> radiusUnit,
             double startAngle, double endAngle)
     {
         return new DefaultArcByCenterPoint(center, radius, radiusUnit, startAngle, endAngle);
@@ -283,16 +299,10 @@ public final class GeometryFactory {
      * @param  bulge   distance from the midpoint of the chord to the arc, along {@code normal}.
      * @param  normal  direction the arc bulges towards, perpendicular to the chord.
      */
-    public static ArcByBulge createArcByBulge(DataPoints points, double bulge, Vector<?> normal) {
+    public ArcByBulge createArcByBulge(DataPoints points, double bulge, Vector<?> normal) {
         return new DefaultArcByBulge(points, bulge, normal);
     }
 
-    /*
-     * Conics, spirals and splines. These are the curves whose interpolation is neither linear nor
-     * a simple chain of circular arcs, and which ISO 19107 defines by a mathematical construction
-     * rather than by a list of positions alone.
-     */
-
     /**
      * Creates a chain of conic section arcs, each of them determined by five data points.
      *
@@ -302,7 +312,7 @@ public final class GeometryFactory {
      *                        one per arc, or {@code null} if none.
      * @param  cycle          whether the conic closes on itself.
      */
-    public static Conic createConic(DataPoints points, Array controlPoints, boolean cycle) {
+    public Conic createConic(DataPoints points, Array controlPoints, boolean cycle) {
         return new DefaultConic(points, controlPoints, cycle);
     }
 
@@ -317,7 +327,7 @@ public final class GeometryFactory {
      *                        possibly empty.
      * @param  cycle          whether the chain closes on itself.
      */
-    public static Arc createArc(DataPoints points, Array controlPoints, List<Vector> radius, boolean cycle) {
+    public Arc createArc(DataPoints points, Array controlPoints, List<Vector> radius, boolean cycle) {
         return new DefaultArc(points, controlPoints, radius, cycle);
     }
 
@@ -331,7 +341,7 @@ public final class GeometryFactory {
      *                        must stay below a full turn, at least two of them are needed.
      * @param  radius         radius vectors of the arcs, possibly empty.
      */
-    public static Circle createCircle(DataPoints points, Array controlPoints, List<Vector> radius) {
+    public Circle createCircle(DataPoints points, Array controlPoints, List<Vector> radius) {
         return new DefaultCircle(points, controlPoints, radius);
     }
 
@@ -343,7 +353,7 @@ public final class GeometryFactory {
      * @param  controlPoints  centres of the ellipses of the arcs, or {@code null} if none.
      * @param  cycle          whether the arc closes on itself, making it a complete ellipse.
      */
-    public static EllipticArc createEllipticArc(DataPoints points, Array controlPoints, boolean cycle) {
+    public EllipticArc createEllipticArc(DataPoints points, Array controlPoints, boolean cycle) {
         return new DefaultEllipticArc(points, controlPoints, cycle);
     }
 
@@ -356,7 +366,7 @@ public final class GeometryFactory {
      * @param  startFrame  two or three mutually orthogonal unit vectors forming a right-handed frame
      *                     at the start point.
      */
-    public static Spiral createSpiral(DataPoints points, RealFunction curvature,
+    public Spiral createSpiral(DataPoints points, RealFunction curvature,
             RealFunction torsion, List<Vector> startFrame)
     {
         return new DefaultSpiral(points, curvature, torsion, startFrame);
@@ -372,7 +382,7 @@ public final class GeometryFactory {
      * @param  startFrame  two mutually orthogonal unit vectors forming a right-handed frame at the
      *                     start point, a clothoid being planar.
      */
-    public static Clothoid createClothoid(DataPoints points, RealFunction curvature, List<Vector> startFrame) {
+    public Clothoid createClothoid(DataPoints points, RealFunction curvature, List<Vector> startFrame) {
         return new DefaultClothoid(points, curvature, startFrame);
     }
 
@@ -390,7 +400,7 @@ public final class GeometryFactory {
      * @param  derivativeInterior  number of continuous derivatives at the interior knots,
      *                             at most {@code degree} − 1.
      */
-    public static PolynomialSpline createPolynomialSpline(DataPoints points, Array controlPoints,
+    public PolynomialSpline createPolynomialSpline(DataPoints points, Array controlPoints,
             double[] knots, int degree, SplineCurveForm curveForm, KnotType knotSpec,
             Vector derivativeAtStart, Vector derivativeAtEnd, int derivativeInterior)
     {
@@ -409,7 +419,7 @@ public final class GeometryFactory {
      * @param  derivativeAtStart  tangent imposed at the start point, or {@code null} if none.
      * @param  derivativeAtEnd    tangent imposed at the end point, or {@code null} if none.
      */
-    public static CubicSpline createCubicSpline(DataPoints points, Array controlPoints, double[] knots,
+    public CubicSpline createCubicSpline(DataPoints points, Array controlPoints, double[] knots,
             SplineCurveForm curveForm, KnotType knotSpec, Vector derivativeAtStart, Vector derivativeAtEnd)
     {
         return new DefaultCubicSpline(points, controlPoints, knots, curveForm, knotSpec,
@@ -429,7 +439,7 @@ public final class GeometryFactory {
      * @param  derivativeAtStart  derivative imposed at the start point, or {@code null} if none.
      * @param  derivativeAtEnd    derivative imposed at the end point, or {@code null} if none.
      */
-    public static Bezier createBezier(DataPoints points, Array controlPoints, double[] knots, int degree,
+    public Bezier createBezier(DataPoints points, Array controlPoints, double[] knots, int degree,
             SplineCurveForm curveForm, KnotType knotSpec, Vector derivativeAtStart, Vector derivativeAtEnd)
     {
         return new DefaultBezier(points, controlPoints, knots, degree, curveForm, knotSpec,
@@ -450,7 +460,7 @@ public final class GeometryFactory {
      * @param  knotSpec       distribution of the knots, or {@code null} if unspecified.
      * @param  rational       whether the control points are expressed in homogeneous coordinates.
      */
-    public static BSplineCurve createBSplineCurve(DataPoints points, Array controlPoints, double[] knots,
+    public BSplineCurve createBSplineCurve(DataPoints points, Array controlPoints, double[] knots,
             int degree, SplineCurveForm curveForm, KnotType knotSpec, boolean rational)
     {
         return new DefaultBSplineCurve(points, controlPoints, knots, degree, curveForm, knotSpec, rational);
@@ -465,7 +475,7 @@ public final class GeometryFactory {
      * @param  knots    knot values, whose multiplicities make the curve clamped or periodic.
      * @param  degree   degree of the basis functions.
      */
-    public static NurbCurve createNurbCurve(DataPoints points, double[] weights, double[] knots, int degree) {
+    public NurbCurve createNurbCurve(DataPoints points, double[] weights, double[] knots, int degree) {
         return new DefaultNurbCurve(points, weights, knots, degree);
     }
 
@@ -480,7 +490,7 @@ public final class GeometryFactory {
      * @param  refDirection  reference direction of the offset in a 3-dimensional coordinate system,
      *                       or {@code null} if the spatial dimension is 2.
      */
-    public static OffsetCurve createOffsetCurve(Curve baseCurve, Quantity<?> distance, Bearing refDirection) {
+    public OffsetCurve createOffsetCurve(Curve baseCurve, Quantity<?> distance, Bearing refDirection) {
         return new DefaultOffsetCurve(baseCurve, distance, refDirection);
     }
 
@@ -493,48 +503,67 @@ public final class GeometryFactory {
      *                         They are disjoint and together cover the whole coordinate system.
      * @param  elements        projections of the curve, one per projection of the coordinate system.
      */
-    public static ProductCurve createProductCurve(Range<?> parameterRange,
+    public ProductCurve createProductCurve(Range<?> parameterRange,
             List<Projection> projections, Curve ... elements)
     {
         return new DefaultProductCurve(parameterRange, projections, elements);
     }
 
-    public static CurvePolygon createCurvePolygon(Curve exterior, List<Curve> interiors) {
-        return new DefaultCurvePolygon(exterior, interiors);
+    /**
+     * Returns a curve traversed in the opposite direction to the given one.
+     * This is what a GML {@code gml:OrientableCurve} with {@code orientation="-"} describes.
+     */
+    public Curve createReversed(Curve base) {
+        return new DefaultReversedCurve(base);
     }
 
-    public static <T extends Polygon> PolyhedralSurface<T> createPolyhedralSurface(T ... patches) {
-        return new DefaultPolyhedralSurface<>(null, patches);
+    public MultiLineString createMultiLineString(LineString ... geometries) {
+        return new DefaultMultiLineString(geometries);
     }
 
-    public static <T extends Polygon> PolyhedralSurface<T> createPolyhedralSurface(CoordinateReferenceSystem crs, T[] patches) {
-        return new DefaultPolyhedralSurface<>(crs, patches);
+    public MultiLineString createMultiLineString(CoordinateReferenceSystem crs, LineString ... geometries) {
+        return new DefaultMultiLineString(crs, geometries);
     }
 
-    public static TIN createTIN(Triangle ... patches) {
-        return new DefaultTriangulatedSurface(patches);
+    public <T extends Curve> MultiCurve<T> createMultiCurve(T ... geometries) {
+        return new DefaultMultiCurve<>(geometries);
     }
 
-    public static TIN createTIN(CoordinateReferenceSystem crs, Triangle[] patches) {
-        return new DefaultTriangulatedSurface(crs, patches);
+    public <T extends Curve> MultiCurve<T> createMultiCurve(CoordinateReferenceSystem crs, T ... geometries) {
+        return new DefaultMultiCurve<>(crs, geometries);
     }
 
-    public static Polyhedron createPolyhedron(MultiPolygon exteriorShell, List<MultiPolygon> interiorShells) {
-        return new DefaultPolyhedron(exteriorShell, interiorShells);
+    // ////////////////////////////////////////////////////////////////////////
+    // Surfaces ///////////////////////////////////////////////////////////////
+    // ////////////////////////////////////////////////////////////////////////
+
+    public Polygon createPolygon(LinearRing exterior, List<LinearRing> interiors) {
+        return new DefaultPolygon(exterior, interiors);
     }
 
-    public static MultiPolyhedron createMultiPolyhedron(Polyhedron ... solids) {
-        return new DefaultMultiPolyhedron(solids);
+    public Triangle createTriangle(LinearRing exterior) {
+        return new DefaultTriangle(exterior);
     }
 
-    public static MultiPolyhedron createMultiPolyhedron(CoordinateReferenceSystem crs, Polyhedron ... solids) {
-        return new DefaultMultiPolyhedron(crs, solids);
+    public CurvePolygon createCurvePolygon(Curve exterior, List<Curve> interiors) {
+        return new DefaultCurvePolygon(exterior, interiors);
     }
 
-    /*
-     * Surfaces and solids defined over a rectangular parameter space, in which fixing all the
-     * parameters but one yields a family of section curves.
-     */
+    public <T extends Polygon> PolyhedralSurface<T> createPolyhedralSurface(T ... patches) {
+        return new DefaultPolyhedralSurface<>(null, patches);
+    }
+
+    public <T extends Polygon> PolyhedralSurface<T> createPolyhedralSurface(CoordinateReferenceSystem crs, T[] patches) {
+        return new DefaultPolyhedralSurface<>(crs, patches);
+    }
+
+    public TIN createTIN(Triangle ... patches) {
+        return new DefaultTriangulatedSurface(patches);
+    }
+
+    public TIN createTIN(CoordinateReferenceSystem crs, Triangle[] patches) {
+        return new DefaultTriangulatedSurface(crs, patches);
+    }
 
     /**
      * Creates a parametric curve surface using polylines as both horizontal and vertical curves,
@@ -548,7 +577,7 @@ public final class GeometryFactory {
      * @param  columns        number of columns in the parameter grid.
      * @param  knots          knot values, one sequence per surface parameter, or {@code null} if none.
      */
-    public static BilinearGrid createBilinearGrid(DataPoints points, List<DirectPosition> controlPoints,
+    public BilinearGrid createBilinearGrid(DataPoints points, List<DirectPosition> controlPoints,
             int rows, int columns, List<double[]> knots)
     {
         return new DefaultBilinearGrid(points, controlPoints, rows, columns, knots);
@@ -572,7 +601,7 @@ public final class GeometryFactory {
      * @param  polynomial     {@code true} if the surface is polynomial, {@code false} if the control
      *                        points are expressed in homogeneous coordinates, making it rational.
      */
-    public static BSplineSurface createBSplineSurface(DataPoints points, List<DirectPosition> controlPoints,
+    public BSplineSurface createBSplineSurface(DataPoints points, List<DirectPosition> controlPoints,
             int rows, int columns, List<double[]> knots, int degree, KnotType knotSpec,
             BSplineSurfaceForm surfaceForm, boolean polynomial)
     {
@@ -591,12 +620,74 @@ public final class GeometryFactory {
      * @param  knotsV         knot values along the <var>v</var> parameter.
      * @param  degree         degree of the basis functions.
      */
-    public static NurbSurface createNurbSurface(Vector<?>[][] controlPoints, double[][] weights,
+    public NurbSurface createNurbSurface(Vector<?>[][] controlPoints, double[][] weights,
             double[] knotsU, double[] knotsV, int degree)
     {
         return new DefaultNurbSurface(controlPoints, weights, knotsU, knotsV, degree);
     }
 
+    /**
+     * Creates a sphere of the given radius centered on the single position of the given sequence.
+     * The sequence is taken as-is, so the caller may give the sphere the attributes carried by it.
+     *
+     * @param  points  the center of the sphere, as a sequence of exactly one position.
+     * @param  radius  radius of the sphere, must be positive.
+     * @return the sphere of the given center and radius.
+     * @throws IllegalArgumentException if the given sequence does not hold exactly one position.
+     */
+    public Sphere createSphere(DataPoints points, double radius) {
+        return new Sphere(points, radius);
+    }
+
+    /**
+     * Creates an ellipsoid of the given semi-axes centered on the single position of the given
+     * sequence. The sequence is taken as-is, so the caller may give the ellipsoid the attributes
+     * carried by it. An ellipsoid whose semi-axes are all equal is a {@linkplain #createSphere
+     * sphere} of that radius.
+     *
+     * @param  points    the center of the ellipsoid, as a sequence of exactly one position.
+     * @param  semiAxes  length of the semi-axis along each axis of the coordinate system,
+     *                   one value per dimension. Each of them must be positive.
+     * @return the ellipsoid of the given center and semi-axes.
+     * @throws IllegalArgumentException if the given sequence does not hold exactly one position,
+     *         or if the number of semi-axes is not the number of dimensions.
+     */
+    public Ellipsoid createEllipsoid(DataPoints points, double... semiAxes) {
+        return new Ellipsoid(points, semiAxes);
+    }
+
+    /**
+     * Returns a surface whose up-normal points the opposite way to the given one's.
+     * This is what a GML {@code gml:OrientableSurface} with {@code orientation="-"} describes.
+     */
+    public Surface createReversed(Surface base) {
+        return new DefaultReversedSurface(base);
+    }
+
+    public MultiPolygon createMultiPolygon(Polygon ... geometries) {
+        return new DefaultMultiPolygon(geometries);
+    }
+
+    public MultiPolygon createMultiPolygon(CoordinateReferenceSystem crs, Polygon ... geometries) {
+        return new DefaultMultiPolygon(crs, geometries);
+    }
+
+    public <T extends Surface> MultiSurface<T> createMultiSurface(T ... geometries) {
+        return new DefaultMultiSurface<>(geometries);
+    }
+
+    public <T extends Surface> MultiSurface<T> createMultiSurface(CoordinateReferenceSystem crs, T ... geometries) {
+        return new DefaultMultiSurface<>(crs, geometries);
+    }
+
+    // ////////////////////////////////////////////////////////////////////////
+    // Solids /////////////////////////////////////////////////////////////////
+    // ////////////////////////////////////////////////////////////////////////
+
+    public Polyhedron createPolyhedron(MultiPolygon exteriorShell, List<MultiPolygon> interiorShells) {
+        return new DefaultPolyhedron(exteriorShell, interiorShells);
+    }
+
     /**
      * Creates a parametric curve solid whose three families of curves are b-splines.
      *
@@ -607,7 +698,7 @@ public final class GeometryFactory {
      * @param  columns        number of vertical columns in the parameter grid.
      * @param  files          number of depth files in the parameter grid.
      */
-    public static BSplineSolid createBSolidSpline(DataPoints points, List<DirectPosition> controlPoints,
+    public BSplineSolid createBSolidSpline(DataPoints points, List<DirectPosition> controlPoints,
             int rows, int columns, int files)
     {
         return new DefaultBSplineSolid(points, controlPoints, rows, columns, files);
@@ -620,42 +711,27 @@ public final class GeometryFactory {
      * @param  extrusionRange  lower and upper limits of the extrusion.
      * @param  extrusionCrs    coordinate reference system of the extrusion range.
      */
-    public static Prism createPrism(Geometry base, NumberRange<?> extrusionRange, SingleCRS extrusionCrs) {
+    public Prism createPrism(Geometry base, NumberRange<?> extrusionRange, SingleCRS extrusionCrs) {
         return new DefaultPrism(base, extrusionRange, extrusionCrs);
     }
 
-    /**
-     * Returns a curve traversed in the opposite direction to the given one.
-     * This is what a GML {@code gml:OrientableCurve} with {@code orientation="-"} describes.
-     */
-    public static Curve createReversed(Curve base) {
-        return new DefaultReversedCurve(base);
+    public MultiPolyhedron createMultiPolyhedron(Polyhedron ... solids) {
+        return new DefaultMultiPolyhedron(solids);
     }
 
-    /**
-     * Returns a surface whose up-normal points the opposite way to the given one's.
-     * This is what a GML {@code gml:OrientableSurface} with {@code orientation="-"} describes.
-     */
-    public static Surface createReversed(Surface base) {
-        return new DefaultReversedSurface(base);
+    public MultiPolyhedron createMultiPolyhedron(CoordinateReferenceSystem crs, Polyhedron ... solids) {
+        return new DefaultMultiPolyhedron(crs, solids);
     }
 
-    public static DataPoints createSequence(Array positions) {
-        return createSequence(Collections.singletonMap(DataPointsType.ATT_POSITION, positions));
-    }
+    // ////////////////////////////////////////////////////////////////////////
+    // Heterogeneous collections //////////////////////////////////////////////
+    // ////////////////////////////////////////////////////////////////////////
 
-    public static DataPoints createSequence(Map<String, Array> attributes) {
-        return new ArrayDataPoints(attributes);
+    public <T extends Geometry> GeometryCollection<T> createGeometryCollection(T ... geometries) {
+        return new DefaultGeometryCollection<>(geometries);
     }
 
-    /**
-     * Returns a copy of the given DataPoints.
-     */
-    public static DataPoints copy(final DataPoints source) {
-        final Map<String,Array> attributes = new LinkedHashMap<>();
-        for (final String name : source.getType().getAttributeNames()) {
-            attributes.put(name, source.getAttributeArray(name));
-        }
-        return GeometryFactory.createSequence(attributes);
+    public <T extends Geometry> GeometryCollection<T> createGeometryCollection(CoordinateReferenceSystem crs, T ... geometries) {
+        return new DefaultGeometryCollection<>(crs, geometries);
     }
 }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryType.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryType.java
index 75a6625c37..9a5a86d1bf 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryType.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryType.java
@@ -242,6 +242,10 @@ public enum GeometryType {
      * A solid bounded by the positions at a constant distance from a center point.
      */
     SPHERE,
+    /**
+     * A {@linkplain #SPHERE} scaled by a distinct factor along each axis of the coordinate system.
+     */
+    ELLIPSOID,
     /**
      * A solid bounded by a lateral surface and two parallel bases.
      */
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java
index 946d5006ef..22fc0dcca4 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java
@@ -50,7 +50,7 @@ public final class HyperPlane extends AbstractGeometry{
      * @param  normal    the direction the hyperplane is perpendicular to, not null.
      */
     public HyperPlane(Tuple<?> position, Vector<?> normal) {
-        points = GeometryFactory.createSequence(NDArrays.of(position.getSampleSystem(), position.getDataType(), 1));
+        points = GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(position.getSampleSystem(), position.getDataType(), 1));
         points.setPosition(0, position);
         this.normal = normal;
     }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java
index b5aa4c7aa2..3983aa7e7b 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java
@@ -62,7 +62,7 @@ public final class Plane extends AbstractGeometry{
      * @param  normal    the direction the plane is perpendicular to, not null.
      */
     public Plane(Tuple<?> position, Vector<?> normal) {
-        points = GeometryFactory.createSequence(NDArrays.of(position.getSampleSystem(), position.getDataType(), 1));
+        points = GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(position.getSampleSystem(), position.getDataType(), 1));
         points.setPosition(0, position);
         this.normal = normal;
     }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Point.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Point.java
index a7a4f19444..4e779165fb 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Point.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Point.java
@@ -224,7 +224,7 @@ public sealed interface Point extends Primitive
     @UML(identifier="boundary", specification=ISO_19107)
     @Override
     default Geometry getBoundary() {
-        return GeometryFactory.createEmpty(getCoordinateReferenceSystem());
+        return GeometryFactory.DEFAULT.createEmpty(getCoordinateReferenceSystem());
     }
 
     /**
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Ray.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Ray.java
index 2254ebb854..b57303daa4 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Ray.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Ray.java
@@ -47,7 +47,7 @@ public final class Ray extends AbstractGeometry{
      * @param  direction  the direction the ray extends toward, not null.
      */
     public Ray(Tuple<?> position, Vector<?> direction) {
-        points = GeometryFactory.createSequence(NDArrays.of(position.getSampleSystem(), position.getDataType(), 1));
+        points = GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(position.getSampleSystem(), position.getDataType(), 1));
         points.setPosition(0, position);
         this.direction = direction;
     }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/JTSAdapter.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/JTSAdapter.java
index 409ca14d08..a844709d0c 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/JTSAdapter.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/JTSAdapter.java
@@ -76,47 +76,47 @@ public final class JTSAdapter {
         if (jts == null) {
             return null;
         } else if (jts.isEmpty()) {
-            return GeometryFactory.createEmpty(crs);
+            return GeometryFactory.DEFAULT.createEmpty(crs);
 
         } else if (jts instanceof org.locationtech.jts.geom.Point cdt) {
-            return GeometryFactory.createPoint(toDataPoints(cdt.getCoordinateSequence(), crs, copy));
+            return GeometryFactory.DEFAULT.createPoint(toDataPoints(cdt.getCoordinateSequence(), crs, copy));
 
         } else if (jts instanceof org.locationtech.jts.geom.MultiPoint cdt) {
-            return GeometryFactory.createMultiPoint(toDataPoints(jts.getFactory().getCoordinateSequenceFactory().create(cdt.getCoordinates()), crs, copy));
+            return GeometryFactory.DEFAULT.createMultiPoint(toDataPoints(jts.getFactory().getCoordinateSequenceFactory().create(cdt.getCoordinates()), crs, copy));
 
         } else if (jts instanceof org.locationtech.jts.geom.LinearRing cdt) {
-            return GeometryFactory.createLinearRing(toDataPoints(cdt.getCoordinateSequence(), crs, copy));
+            return GeometryFactory.DEFAULT.createLinearRing(toDataPoints(cdt.getCoordinateSequence(), crs, copy));
 
         } else if (jts instanceof org.locationtech.jts.geom.LineString cdt) {
-            return GeometryFactory.createLineString(toDataPoints(cdt.getCoordinateSequence(), crs, copy));
+            return GeometryFactory.DEFAULT.createLineString(toDataPoints(cdt.getCoordinateSequence(), crs, copy));
 
         } else if (jts instanceof org.locationtech.jts.geom.MultiLineString cdt) {
             final LineString[] strings = new LineString[cdt.getNumGeometries()];
             for (int i = 0; i < strings.length; i++) {
                 strings[i] = (LineString) fromJTS(cdt.getGeometryN(i), crs, copy);
             }
-            return GeometryFactory.createMultiLineString(strings);
+            return GeometryFactory.DEFAULT.createMultiLineString(strings);
         } else if (jts instanceof org.locationtech.jts.geom.Polygon cdt) {
             final LinearRing exterior = (LinearRing) fromJTS(cdt.getExteriorRing(), crs, copy);
             final List<LinearRing> interiors = new ArrayList<>(cdt.getNumInteriorRing());
             for (int i = 0, n = cdt.getNumInteriorRing(); i < n; i++) {
                 interiors.add((LinearRing) fromJTS(cdt.getInteriorRingN(i), crs, copy));
             }
-            return GeometryFactory.createPolygon(exterior, interiors);
+            return GeometryFactory.DEFAULT.createPolygon(exterior, interiors);
 
         } else if (jts instanceof org.locationtech.jts.geom.MultiPolygon cdt) {
             final Polygon[] geoms = new Polygon[cdt.getNumGeometries()];
             for (int i = 0; i < geoms.length; i++) {
                 geoms[i] = (Polygon) fromJTS(cdt.getGeometryN(i), crs, copy);
             }
-            return GeometryFactory.createMultiPolygon(geoms);
+            return GeometryFactory.DEFAULT.createMultiPolygon(geoms);
 
         } else if (jts instanceof org.locationtech.jts.geom.GeometryCollection cdt) {
             final Geometry[] geoms = new Geometry[cdt.getNumGeometries()];
             for (int i = 0; i < geoms.length; i++) {
                 geoms[i] = fromJTS(cdt.getGeometryN(i), crs, copy);
             }
-            return GeometryFactory.createGeometryCollection(geoms);
+            return GeometryFactory.DEFAULT.createGeometryCollection(geoms);
 
         } else {
             throw new IllegalArgumentException("Unknown JTS geometry type");
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/SIS.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/SIS.java
index ba3e0ffb41..fcf8db2d88 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/SIS.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/SIS.java
@@ -288,7 +288,7 @@ public final class SIS extends org.apache.sis.geometry.wrapper.Geometries<Geomet
     @Override
     public MultiPoint<?> createMultiPoint(final boolean isFloat, final Dimensions dimensions, final DoubleBuffer coordinates) {
         final int count = coordinates.remaining() / dimensions.count;
-        return GeometryFactory.createMultiPoint(readDataPoints(isFloat, dimensions, count, coordinates));
+        return GeometryFactory.DEFAULT.createMultiPoint(readDataPoints(isFloat, dimensions, count, coordinates));
     }
 
     /**
@@ -327,12 +327,12 @@ public final class SIS extends org.apache.sis.geometry.wrapper.Geometries<Geomet
         }
         addPath(paths, path, polygon, isFloat, dimensions, spatial);
         switch (paths.size()) {
-            case 0:  return GeometryFactory.createEmpty(undefinedCRS(spatial));
+            case 0:  return GeometryFactory.DEFAULT.createEmpty(undefinedCRS(spatial));
             case 1:  return paths.get(0);
             default: {
                 // An ArrayStoreException here would be a bug in our use of the `polygon` flag.
-                return polygon ? GeometryFactory.createMultiPolygon(paths.toArray(Polygon[]::new))
-                               : GeometryFactory.createMultiLineString(paths.toArray(LineString[]::new));
+                return polygon ? GeometryFactory.DEFAULT.createMultiPolygon(paths.toArray(Polygon[]::new))
+                               : GeometryFactory.DEFAULT.createMultiLineString(paths.toArray(LineString[]::new));
             }
         }
     }
@@ -359,8 +359,8 @@ public final class SIS extends org.apache.sis.geometry.wrapper.Geometries<Geomet
                 throw new IllegalArgumentException("Coordinates of a polygon shall make a closed ring.");
             }
             final DataPoints points = toDataPoints(path, isFloat, dimensions, spatial);
-            addTo.add(polygon ? GeometryFactory.createPolygon(GeometryFactory.createLinearRing(points), List.of())
-                              : GeometryFactory.createLineString(points));
+            addTo.add(polygon ? GeometryFactory.DEFAULT.createPolygon(GeometryFactory.DEFAULT.createLinearRing(points), List.of())
+                              : GeometryFactory.DEFAULT.createLineString(points));
         }
         path.clear();
     }
@@ -381,13 +381,13 @@ public final class SIS extends org.apache.sis.geometry.wrapper.Geometries<Geomet
             if (component instanceof Polygon polygon) {
                 polygons[i] = polygon;
             } else if (component instanceof LineString line) {
-                polygons[i] = GeometryFactory.createPolygon(toRing(line), List.of());
+                polygons[i] = GeometryFactory.DEFAULT.createPolygon(toRing(line), List.of());
             } else {
                 throw new ClassCastException(Errors.format(Errors.Keys.IllegalArgumentClass_3,
                         Strings.bracket("geometries", i), Polygon.class, Classes.getClass(component)));
             }
         }
-        return new Wrapper(GeometryFactory.createMultiPolygon(polygons));
+        return new Wrapper(GeometryFactory.DEFAULT.createMultiPolygon(polygons));
     }
 
     /**
@@ -415,12 +415,12 @@ public final class SIS extends org.apache.sis.geometry.wrapper.Geometries<Geomet
         switch (type) {
             case POINT: {
                 final DataPoints points = toDataPoints(components);
-                geometry = (points.size() == 1) ? GeometryFactory.createPoint(points)
-                                                : GeometryFactory.createMultiPoint(points).getCentroid();
+                geometry = (points.size() == 1) ? GeometryFactory.DEFAULT.createPoint(points)
+                                                : GeometryFactory.DEFAULT.createMultiPoint(points).getCentroid();
                 break;
             }
             case LINESTRING: {
-                geometry = GeometryFactory.createLineString(toDataPoints(components));
+                geometry = GeometryFactory.DEFAULT.createLineString(toDataPoints(components));
                 break;
             }
             case POLYGON: {
@@ -436,29 +436,29 @@ public final class SIS extends org.apache.sis.geometry.wrapper.Geometries<Geomet
                         if (i == 0) shell = ring;
                         else holes.add(ring);
                     }
-                    geometry = GeometryFactory.createPolygon(shell, holes);
+                    geometry = GeometryFactory.DEFAULT.createPolygon(shell, holes);
                 } else {
-                    geometry = GeometryFactory.createPolygon(
-                            GeometryFactory.createLinearRing(toDataPoints(components)), List.of());
+                    geometry = GeometryFactory.DEFAULT.createPolygon(
+                            GeometryFactory.DEFAULT.createLinearRing(toDataPoints(components)), List.of());
                 }
                 break;
             }
             case MULTIPOINT: {
                 geometry = (components instanceof Point[] points)
-                        ? GeometryFactory.createMultiPoint(points)
-                        : GeometryFactory.createMultiPoint(toDataPoints(components));
+                        ? GeometryFactory.DEFAULT.createMultiPoint(points)
+                        : GeometryFactory.DEFAULT.createMultiPoint(toDataPoints(components));
                 break;
             }
             case MULTILINESTRING: {
-                geometry = GeometryFactory.createMultiLineString((LineString[]) components);
+                geometry = GeometryFactory.DEFAULT.createMultiLineString((LineString[]) components);
                 break;
             }
             case MULTIPOLYGON: {
-                geometry = GeometryFactory.createMultiPolygon((Polygon[]) components);
+                geometry = GeometryFactory.DEFAULT.createMultiPolygon((Polygon[]) components);
                 break;
             }
             case GEOMETRYCOLLECTION: {
-                geometry = GeometryFactory.createGeometryCollection((Geometry[]) components);
+                geometry = GeometryFactory.DEFAULT.createGeometryCollection((Geometry[]) components);
                 break;
             }
             case GEOMETRY: {
@@ -606,7 +606,7 @@ public final class SIS extends org.apache.sis.geometry.wrapper.Geometries<Geomet
             return points;
         }
         if (components instanceof Array positions) {
-            return GeometryFactory.createSequence(positions);
+            return GeometryFactory.DEFAULT.createDataPoints(positions);
         }
         // The ClassCastException that may happen here is part of method contract.
         final Collection<?> source = (components instanceof Collection<?> c) ? c : Arrays.asList((Object[]) components);
@@ -622,10 +622,10 @@ public final class SIS extends org.apache.sis.geometry.wrapper.Geometries<Geomet
              * so the two-dimensional case is assumed, as everywhere else in the absence of
              * a coordinate reference system.
              */
-            return GeometryFactory.createSequence(NDArrays.of(undefinedSystem(BIDIMENSIONAL), DataType.DOUBLE, 0));
+            return GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(undefinedSystem(BIDIMENSIONAL), DataType.DOUBLE, 0));
         }
         final Tuple<?> first = tuples.get(0);
-        return GeometryFactory.createSequence(NDArrays.of(tuples, first.getSampleSystem(), first.getDataType()));
+        return GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(tuples, first.getSampleSystem(), first.getDataType()));
     }
 
     /**
@@ -633,6 +633,6 @@ public final class SIS extends org.apache.sis.geometry.wrapper.Geometries<Geomet
      * The ring shares the positions of the given curve, no copy is performed.
      */
     private static LinearRing toRing(final LineString line) {
-        return (line instanceof LinearRing ring) ? ring : GeometryFactory.createLinearRing(line.getDataPoints());
+        return (line instanceof LinearRing ring) ? ring : GeometryFactory.DEFAULT.createLinearRing(line.getDataPoints());
     }
 }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeAdapter.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeAdapter.java
index 7734d4a71a..0b15937a6e 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeAdapter.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeAdapter.java
@@ -107,7 +107,7 @@ public final class ShapeAdapter extends AbstractShape {
      */
     @Override
     public boolean contains(final double x, final double y) {
-        return geometry.contains(GeometryFactory.createPoint(SampleSystem.ofSize(2), x, y));
+        return geometry.contains(GeometryFactory.DEFAULT.createPoint(SampleSystem.ofSize(2), x, y));
     }
 
     /**
@@ -155,8 +155,8 @@ public final class ShapeAdapter extends AbstractShape {
             xmin, ymin
         });
         final DataPoints ps = new ArrayDataPoints(positions);
-        final LinearRing ring = GeometryFactory.createLinearRing(ps);
-        return GeometryFactory.createPolygon(ring, null);
+        final LinearRing ring = GeometryFactory.DEFAULT.createLinearRing(ps);
+        return GeometryFactory.DEFAULT.createPolygon(ring, null);
     }
 
     /**
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeConverter.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeConverter.java
index 1bb7135d8e..0d7f198fe3 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeConverter.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeConverter.java
@@ -270,10 +270,10 @@ public abstract class ShapeConverter {
         }
 
         switch (geometryType) {
-            case 0:          return GeometryFactory.INSTANCE.createEmpty(Geometries.getUndefinedCRS(DIMENSION));
-            default:         return GeometryFactory.INSTANCE.createGeometryCollection(geometries.toArray(Geometry[]::new));
-            case POINT:      return GeometryFactory.INSTANCE.createMultiPoint(geometries.toArray(Point[]::new));
-            case LINESTRING: return GeometryFactory.INSTANCE.createMultiLineString(geometries.toArray(LineString[]::new));
+            case 0:          return GeometryFactory.DEFAULT.createEmpty(Geometries.getUndefinedCRS(DIMENSION));
+            default:         return GeometryFactory.DEFAULT.createGeometryCollection(geometries.toArray(Geometry[]::new));
+            case POINT:      return GeometryFactory.DEFAULT.createMultiPoint(geometries.toArray(Point[]::new));
+            case LINESTRING: return GeometryFactory.DEFAULT.createMultiLineString(geometries.toArray(LineString[]::new));
             case POLYGON:    break;
         }
         /*
@@ -313,14 +313,14 @@ public abstract class ShapeConverter {
         if (length != 0) {
             Geometry geometry;
             if (length == DIMENSION) {
-                geometry = GeometryFactory.INSTANCE.createPoint(toSequence(false));
+                geometry = GeometryFactory.DEFAULT.createPoint(toSequence(false));
                 geometryType |= POINT;
             } else {
                 if (isRing) {
-                    geometry = GeometryFactory.INSTANCE.createPolygon(GeometryFactory.INSTANCE.createLinearRing(toSequence(true)), null);
+                    geometry = GeometryFactory.DEFAULT.createPolygon(GeometryFactory.DEFAULT.createLinearRing(toSequence(true)), null);
                     geometryType |= POLYGON;
                 } else {
-                    geometry = GeometryFactory.INSTANCE.createLineString(toSequence(false));
+                    geometry = GeometryFactory.DEFAULT.createLineString(toSequence(false));
                     geometryType |= LINESTRING;
                 }
             }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/WellKnownBinaryParser.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/WellKnownBinaryParser.java
index 6a1f868545..1b78b959ab 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/WellKnownBinaryParser.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/WellKnownBinaryParser.java
@@ -212,8 +212,8 @@ final class WellKnownBinaryParser {
         }
         switch (code % 1000) {
             case WellKnownBinary.Codes.POINT:               return parsePoint();
-            case WellKnownBinary.Codes.LINESTRING:          return GeometryFactory.createLineString(readPointList());
-            case WellKnownBinary.Codes.CIRCULARSTRING:      return GeometryFactory.createCircularString(readPointList());
+            case WellKnownBinary.Codes.LINESTRING:          return GeometryFactory.DEFAULT.createLineString(readPointList());
+            case WellKnownBinary.Codes.CIRCULARSTRING:      return GeometryFactory.DEFAULT.createCircularString(readPointList());
             case WellKnownBinary.Codes.COMPOUNDCURVE:       return parseCompoundCurve();
             case WellKnownBinary.Codes.POLYGON:             return readPolygonBody();
             case WellKnownBinary.Codes.TRIANGLE:            return readTriangleBody();
@@ -263,10 +263,10 @@ final class WellKnownBinaryParser {
             if (!Double.isNaN(ordinate)) {
                 final Coordinates c = new Coordinates();
                 c.add(tuple);
-                return GeometryFactory.createPoint(c.build());
+                return GeometryFactory.DEFAULT.createPoint(c.build());
             }
         }
-        return GeometryFactory.createEmpty(crs());
+        return GeometryFactory.DEFAULT.createEmpty(crs());
     }
 
     /**
@@ -275,13 +275,13 @@ final class WellKnownBinaryParser {
     private CompoundCurve parseCompoundCurve() {
         final int n = readCount();
         if (n == 0) {
-            return GeometryFactory.createCompoundCurve(crs());
+            return GeometryFactory.DEFAULT.createCompoundCurve(crs());
         }
         final Curve[] curves = new Curve[n];
         for (int i = 0; i < n; i++) {
             curves[i] = readMember(Curve.class, CompoundCurve.TYPE);
         }
-        return GeometryFactory.createCompoundCurve(curves);
+        return GeometryFactory.DEFAULT.createCompoundCurve(curves);
     }
 
     /**
@@ -291,14 +291,14 @@ final class WellKnownBinaryParser {
     private CurvePolygon parseCurvePolygon() {
         final int n = readCount();
         if (n == 0) {
-            return GeometryFactory.createCurvePolygon(emptyRing(), List.of());
+            return GeometryFactory.DEFAULT.createCurvePolygon(emptyRing(), List.of());
         }
         final Curve exterior = readMember(Curve.class, CurvePolygon.TYPE);
         final List<Curve> interiors = new ArrayList<>(n - 1);
         for (int i = 1; i < n; i++) {
             interiors.add(readMember(Curve.class, CurvePolygon.TYPE));
         }
-        return GeometryFactory.createCurvePolygon(exterior, interiors);
+        return GeometryFactory.DEFAULT.createCurvePolygon(exterior, interiors);
     }
 
     /**
@@ -307,13 +307,13 @@ final class WellKnownBinaryParser {
     private PolyhedralSurface<Polygon> parsePolyhedralSurface() {
         final int n = readCount();
         if (n == 0) {
-            return GeometryFactory.createPolyhedralSurface(crs(), new Polygon[0]);
+            return GeometryFactory.DEFAULT.createPolyhedralSurface(crs(), new Polygon[0]);
         }
         final Polygon[] patches = new Polygon[n];
         for (int i = 0; i < n; i++) {
             patches[i] = readMember(Polygon.class, PolyhedralSurface.TYPE);
         }
-        return GeometryFactory.createPolyhedralSurface(patches);
+        return GeometryFactory.DEFAULT.createPolyhedralSurface(patches);
     }
 
     /**
@@ -322,13 +322,13 @@ final class WellKnownBinaryParser {
     private TIN parseTIN() {
         final int n = readCount();
         if (n == 0) {
-            return GeometryFactory.createTIN(crs(), new Triangle[0]);
+            return GeometryFactory.DEFAULT.createTIN(crs(), new Triangle[0]);
         }
         final Triangle[] patches = new Triangle[n];
         for (int i = 0; i < n; i++) {
             patches[i] = readMember(Triangle.class, TIN.TYPE);
         }
-        return GeometryFactory.createTIN(patches);
+        return GeometryFactory.DEFAULT.createTIN(patches);
     }
 
     /**
@@ -337,14 +337,14 @@ final class WellKnownBinaryParser {
     private MultiPoint<?> parseMultiPoint() {
         final int n = readCount();
         if (n == 0) {
-            return GeometryFactory.createMultiPoint(crs());
+            return GeometryFactory.DEFAULT.createMultiPoint(crs());
         }
         final Point[] members = new Point[n];
         for (int i = 0; i < n; i++) {
             // See parsePoint(): an empty point decodes to Empty, which is not a Point.
             members[i] = readMember(Point.class, MultiPoint.TYPE);
         }
-        return GeometryFactory.createMultiPoint(members);
+        return GeometryFactory.DEFAULT.createMultiPoint(members);
     }
 
     /**
@@ -353,13 +353,13 @@ final class WellKnownBinaryParser {
     private MultiLineString parseMultiLineString() {
         final int n = readCount();
         if (n == 0) {
-            return GeometryFactory.createMultiLineString(crs());
+            return GeometryFactory.DEFAULT.createMultiLineString(crs());
         }
         final LineString[] members = new LineString[n];
         for (int i = 0; i < n; i++) {
             members[i] = readMember(LineString.class, MultiLineString.TYPE);
         }
-        return GeometryFactory.createMultiLineString(members);
+        return GeometryFactory.DEFAULT.createMultiLineString(members);
     }
 
     /**
@@ -368,13 +368,13 @@ final class WellKnownBinaryParser {
     private MultiPolygon parseMultiPolygon() {
         final int n = readCount();
         if (n == 0) {
-            return GeometryFactory.createMultiPolygon(crs());
+            return GeometryFactory.DEFAULT.createMultiPolygon(crs());
         }
         final Polygon[] members = new Polygon[n];
         for (int i = 0; i < n; i++) {
             members[i] = readMember(Polygon.class, MultiPolygon.TYPE);
         }
-        return GeometryFactory.createMultiPolygon(members);
+        return GeometryFactory.DEFAULT.createMultiPolygon(members);
     }
 
     /**
@@ -384,13 +384,13 @@ final class WellKnownBinaryParser {
     private MultiCurve<Curve> parseMultiCurve() {
         final int n = readCount();
         if (n == 0) {
-            return GeometryFactory.<Curve>createMultiCurve(crs());
+            return GeometryFactory.DEFAULT.createMultiCurve(crs());
         }
         final Curve[] members = new Curve[n];
         for (int i = 0; i < n; i++) {
             members[i] = readMember(Curve.class, MultiCurve.TYPE);
         }
-        return GeometryFactory.createMultiCurve(members);
+        return GeometryFactory.DEFAULT.createMultiCurve(members);
     }
 
     /**
@@ -400,13 +400,13 @@ final class WellKnownBinaryParser {
     private MultiSurface<Surface> parseMultiSurface() {
         final int n = readCount();
         if (n == 0) {
-            return GeometryFactory.<Surface>createMultiSurface(crs());
+            return GeometryFactory.DEFAULT.createMultiSurface(crs());
         }
         final Surface[] members = new Surface[n];
         for (int i = 0; i < n; i++) {
             members[i] = readMember(Surface.class, MultiSurface.TYPE);
         }
-        return GeometryFactory.createMultiSurface(members);
+        return GeometryFactory.DEFAULT.createMultiSurface(members);
     }
 
     /**
@@ -415,13 +415,13 @@ final class WellKnownBinaryParser {
     private GeometryCollection<Geometry> parseGeometryCollection() {
         final int n = readCount();
         if (n == 0) {
-            return GeometryFactory.<Geometry>createGeometryCollection(crs());
+            return GeometryFactory.DEFAULT.createGeometryCollection(crs());
         }
         final Geometry[] members = new Geometry[n];
         for (int i = 0; i < n; i++) {
             members[i] = parseGeometry();
         }
-        return GeometryFactory.createGeometryCollection(members);
+        return GeometryFactory.DEFAULT.createGeometryCollection(members);
     }
 
     // ////////////////////////////////////////////////////////////////////////
@@ -435,9 +435,9 @@ final class WellKnownBinaryParser {
     private Polygon readPolygonBody() {
         final List<LinearRing> rings = readRings();
         if (rings.isEmpty()) {
-            return GeometryFactory.createPolygon(emptyRing(), List.of());
+            return GeometryFactory.DEFAULT.createPolygon(emptyRing(), List.of());
         }
-        return GeometryFactory.createPolygon(rings.get(0), new ArrayList<>(rings.subList(1, rings.size())));
+        return GeometryFactory.DEFAULT.createPolygon(rings.get(0), new ArrayList<>(rings.subList(1, rings.size())));
     }
 
     /**
@@ -446,12 +446,12 @@ final class WellKnownBinaryParser {
     private Triangle readTriangleBody() {
         final List<LinearRing> rings = readRings();
         if (rings.isEmpty()) {
-            return GeometryFactory.createTriangle(emptyRing());
+            return GeometryFactory.DEFAULT.createTriangle(emptyRing());
         }
         if (rings.size() != 1) {
             throw error("A " + Triangle.TYPE + " patch has no interior ring, but " + (rings.size() - 1) + " were given");
         }
-        return GeometryFactory.createTriangle(rings.get(0));
+        return GeometryFactory.DEFAULT.createTriangle(rings.get(0));
     }
 
     /**
@@ -461,7 +461,7 @@ final class WellKnownBinaryParser {
         final int n = readCount();
         final List<LinearRing> rings = new ArrayList<>(n);
         for (int i = 0; i < n; i++) {
-            rings.add(GeometryFactory.createLinearRing(readPointList()));
+            rings.add(GeometryFactory.DEFAULT.createLinearRing(readPointList()));
         }
         return rings;
     }
@@ -482,7 +482,7 @@ final class WellKnownBinaryParser {
      * Returns an empty ring, for the zero counts of the types which are made of rings.
      */
     private LinearRing emptyRing() {
-        return GeometryFactory.createLinearRing(new Coordinates().build());
+        return GeometryFactory.DEFAULT.createLinearRing(new Coordinates().build());
     }
 
     /**
@@ -619,12 +619,12 @@ final class WellKnownBinaryParser {
             if (size == 0) {
                 final Array empty = NDArrays.of(posSystem, DataType.DOUBLE, 0);
                 if (!hasM) {
-                    return GeometryFactory.createSequence(empty);
+                    return GeometryFactory.DEFAULT.createDataPoints(empty);
                 }
                 return createSequence(empty, NDArrays.of(MEASURE_SYSTEM, DataType.DOUBLE, 0));
             }
             if (!hasM) {
-                return GeometryFactory.createSequence(NDArrays.of(posSystem, Arrays.copyOf(values, count)));
+                return GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(posSystem, Arrays.copyOf(values, count)));
             }
             /*
              * The measure is the ordinate following the position ones in each tuple of the bytes,
@@ -646,7 +646,7 @@ final class WellKnownBinaryParser {
             final Map<String,Array> attributes = new LinkedHashMap<>(4);
             attributes.put(DataPointsType.ATT_POSITION, positions);
             attributes.put(DataPointsType.ATT_M, measures);
-            return GeometryFactory.createSequence(attributes);
+            return GeometryFactory.DEFAULT.createDataPoints(attributes);
         }
     }
 
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/WellKnownTextParser.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/WellKnownTextParser.java
index c89ffbaafd..d61e9115b9 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/WellKnownTextParser.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/WellKnownTextParser.java
@@ -208,8 +208,8 @@ final class WellKnownTextParser {
         applyFlags(readFlags());
         switch (keyword) {
             case Point.TYPE:              return parsePoint();
-            case LineString.TYPE:         return GeometryFactory.createLineString(readPointList());
-            case CircularString.TYPE:     return GeometryFactory.createCircularString(readPointList());
+            case LineString.TYPE:         return GeometryFactory.DEFAULT.createLineString(readPointList());
+            case CircularString.TYPE:     return GeometryFactory.DEFAULT.createCircularString(readPointList());
             case CompoundCurve.TYPE:      return parseCompoundCurve();
             case Polygon.TYPE:            return readPolygonBody();
             case Triangle.TYPE:           return readTriangleBody();
@@ -239,9 +239,9 @@ final class WellKnownTextParser {
      */
     private Geometry parsePoint() {
         if (readEmpty()) {
-            return GeometryFactory.createEmpty(crs());
+            return GeometryFactory.DEFAULT.createEmpty(crs());
         }
-        return GeometryFactory.createPoint(readSinglePosition());
+        return GeometryFactory.DEFAULT.createPoint(readSinglePosition());
     }
 
     /**
@@ -249,7 +249,7 @@ final class WellKnownTextParser {
      */
     private CompoundCurve parseCompoundCurve() {
         if (readEmpty()) {
-            return GeometryFactory.createCompoundCurve(crs());
+            return GeometryFactory.DEFAULT.createCompoundCurve(crs());
         }
         final List<Curve> curves = new ArrayList<>();
         expect('(');
@@ -257,7 +257,7 @@ final class WellKnownTextParser {
             curves.add(readCurve(false));
         } while (accept(','));
         expect(')');
-        return GeometryFactory.createCompoundCurve(curves.toArray(Curve[]::new));
+        return GeometryFactory.DEFAULT.createCompoundCurve(curves.toArray(Curve[]::new));
     }
 
     /**
@@ -265,7 +265,7 @@ final class WellKnownTextParser {
      */
     private CurvePolygon parseCurvePolygon() {
         if (readEmpty()) {
-            return GeometryFactory.createCurvePolygon(emptyRing(), List.of());
+            return GeometryFactory.DEFAULT.createCurvePolygon(emptyRing(), List.of());
         }
         final List<Curve> rings = new ArrayList<>();
         expect('(');
@@ -273,7 +273,7 @@ final class WellKnownTextParser {
             rings.add(readCurve(true));
         } while (accept(','));
         expect(')');
-        return GeometryFactory.createCurvePolygon(rings.get(0), new ArrayList<>(rings.subList(1, rings.size())));
+        return GeometryFactory.DEFAULT.createCurvePolygon(rings.get(0), new ArrayList<>(rings.subList(1, rings.size())));
     }
 
     /**
@@ -282,7 +282,7 @@ final class WellKnownTextParser {
      */
     private PolyhedralSurface<Polygon> parsePolyhedralSurface() {
         if (readEmpty()) {
-            return GeometryFactory.createPolyhedralSurface(crs(), new Polygon[0]);
+            return GeometryFactory.DEFAULT.createPolyhedralSurface(crs(), new Polygon[0]);
         }
         final List<Polygon> patches = new ArrayList<>();
         expect('(');
@@ -290,7 +290,7 @@ final class WellKnownTextParser {
             patches.add(readPolygonBody());
         } while (accept(','));
         expect(')');
-        return GeometryFactory.createPolyhedralSurface(patches.toArray(Polygon[]::new));
+        return GeometryFactory.DEFAULT.createPolyhedralSurface(patches.toArray(Polygon[]::new));
     }
 
     /**
@@ -298,7 +298,7 @@ final class WellKnownTextParser {
      */
     private TIN parseTIN() {
         if (readEmpty()) {
-            return GeometryFactory.createTIN(crs(), new Triangle[0]);
+            return GeometryFactory.DEFAULT.createTIN(crs(), new Triangle[0]);
         }
         final List<Triangle> patches = new ArrayList<>();
         expect('(');
@@ -306,7 +306,7 @@ final class WellKnownTextParser {
             patches.add(readTriangleBody());
         } while (accept(','));
         expect(')');
-        return GeometryFactory.createTIN(patches.toArray(Triangle[]::new));
+        return GeometryFactory.DEFAULT.createTIN(patches.toArray(Triangle[]::new));
     }
 
     /**
@@ -315,7 +315,7 @@ final class WellKnownTextParser {
      */
     private MultiPoint<?> parseMultiPoint() {
         if (readEmpty()) {
-            return GeometryFactory.createMultiPoint(crs());
+            return GeometryFactory.DEFAULT.createMultiPoint(crs());
         }
         final List<Point> points = new ArrayList<>();
         expect('(');
@@ -324,15 +324,15 @@ final class WellKnownTextParser {
                 // See parsePoint(): there is no empty point to put in the collection.
                 throw error("A " + MultiPoint.TYPE + " cannot hold an empty point");
             } else if (peek() == '(') {
-                points.add(GeometryFactory.createPoint(readSinglePosition()));
+                points.add(GeometryFactory.DEFAULT.createPoint(readSinglePosition()));
             } else {
                 final Coordinates c = new Coordinates();
                 c.add(readTuple());
-                points.add(GeometryFactory.createPoint(c.build()));
+                points.add(GeometryFactory.DEFAULT.createPoint(c.build()));
             }
         } while (accept(','));
         expect(')');
-        return GeometryFactory.createMultiPoint(points.toArray(Point[]::new));
+        return GeometryFactory.DEFAULT.createMultiPoint(points.toArray(Point[]::new));
     }
 
     /**
@@ -340,15 +340,15 @@ final class WellKnownTextParser {
      */
     private MultiLineString parseMultiLineString() {
         if (readEmpty()) {
-            return GeometryFactory.createMultiLineString(crs());
+            return GeometryFactory.DEFAULT.createMultiLineString(crs());
         }
         final List<LineString> members = new ArrayList<>();
         expect('(');
         do {
-            members.add(GeometryFactory.createLineString(readPointList()));
+            members.add(GeometryFactory.DEFAULT.createLineString(readPointList()));
         } while (accept(','));
         expect(')');
-        return GeometryFactory.createMultiLineString(members.toArray(LineString[]::new));
+        return GeometryFactory.DEFAULT.createMultiLineString(members.toArray(LineString[]::new));
     }
 
     /**
@@ -356,7 +356,7 @@ final class WellKnownTextParser {
      */
     private MultiPolygon parseMultiPolygon() {
         if (readEmpty()) {
-            return GeometryFactory.createMultiPolygon(crs());
+            return GeometryFactory.DEFAULT.createMultiPolygon(crs());
         }
         final List<Polygon> members = new ArrayList<>();
         expect('(');
@@ -364,7 +364,7 @@ final class WellKnownTextParser {
             members.add(readPolygonBody());
         } while (accept(','));
         expect(')');
-        return GeometryFactory.createMultiPolygon(members.toArray(Polygon[]::new));
+        return GeometryFactory.DEFAULT.createMultiPolygon(members.toArray(Polygon[]::new));
     }
 
     /**
@@ -374,7 +374,7 @@ final class WellKnownTextParser {
      */
     private MultiCurve<Curve> parseMultiCurve() {
         if (readEmpty()) {
-            return GeometryFactory.<Curve>createMultiCurve(crs());
+            return GeometryFactory.DEFAULT.<Curve>createMultiCurve(crs());
         }
         final List<Curve> members = new ArrayList<>();
         expect('(');
@@ -382,7 +382,7 @@ final class WellKnownTextParser {
             members.add(readCurve(false));
         } while (accept(','));
         expect(')');
-        return GeometryFactory.createMultiCurve(members.toArray(Curve[]::new));
+        return GeometryFactory.DEFAULT.createMultiCurve(members.toArray(Curve[]::new));
     }
 
     /**
@@ -391,7 +391,7 @@ final class WellKnownTextParser {
      */
     private MultiSurface<Surface> parseMultiSurface() {
         if (readEmpty()) {
-            return GeometryFactory.<Surface>createMultiSurface(crs());
+            return GeometryFactory.DEFAULT.<Surface>createMultiSurface(crs());
         }
         final List<Surface> members = new ArrayList<>();
         expect('(');
@@ -403,7 +403,7 @@ final class WellKnownTextParser {
             }
         } while (accept(','));
         expect(')');
-        return GeometryFactory.createMultiSurface(members.toArray(Surface[]::new));
+        return GeometryFactory.DEFAULT.createMultiSurface(members.toArray(Surface[]::new));
     }
 
     /**
@@ -412,7 +412,7 @@ final class WellKnownTextParser {
      */
     private GeometryCollection<Geometry> parseGeometryCollection() {
         if (readEmpty()) {
-            return GeometryFactory.<Geometry>createGeometryCollection(crs());
+            return GeometryFactory.DEFAULT.<Geometry>createGeometryCollection(crs());
         }
         final List<Geometry> members = new ArrayList<>();
         expect('(');
@@ -420,7 +420,7 @@ final class WellKnownTextParser {
             members.add(parseGeometry());
         } while (accept(','));
         expect(')');
-        return GeometryFactory.createGeometryCollection(members.toArray(Geometry[]::new));
+        return GeometryFactory.DEFAULT.createGeometryCollection(members.toArray(Geometry[]::new));
     }
 
     // ////////////////////////////////////////////////////////////////////////
@@ -437,8 +437,8 @@ final class WellKnownTextParser {
     private Curve readCurve(final boolean asRing) {
         if (peek() == '(') {
             final DataPoints points = readPointList();
-            return asRing ? GeometryFactory.createLinearRing(points)
-                          : GeometryFactory.createLineString(points);
+            return asRing ? GeometryFactory.DEFAULT.createLinearRing(points)
+                          : GeometryFactory.DEFAULT.createLineString(points);
         }
         return expectType(parseGeometry(), Curve.class, asRing ? CurvePolygon.TYPE : CompoundCurve.TYPE);
     }
@@ -448,10 +448,10 @@ final class WellKnownTextParser {
      */
     private Polygon readPolygonBody() {
         if (readEmpty()) {
-            return GeometryFactory.createPolygon(emptyRing(), List.of());
+            return GeometryFactory.DEFAULT.createPolygon(emptyRing(), List.of());
         }
         final List<LinearRing> rings = readRings();
-        return GeometryFactory.createPolygon(rings.get(0), new ArrayList<>(rings.subList(1, rings.size())));
+        return GeometryFactory.DEFAULT.createPolygon(rings.get(0), new ArrayList<>(rings.subList(1, rings.size())));
     }
 
     /**
@@ -459,13 +459,13 @@ final class WellKnownTextParser {
      */
     private Triangle readTriangleBody() {
         if (readEmpty()) {
-            return GeometryFactory.createTriangle(emptyRing());
+            return GeometryFactory.DEFAULT.createTriangle(emptyRing());
         }
         final List<LinearRing> rings = readRings();
         if (rings.size() != 1) {
             throw error("A " + Triangle.TYPE + " patch has no interior ring, but " + (rings.size() - 1) + " were given");
         }
-        return GeometryFactory.createTriangle(rings.get(0));
+        return GeometryFactory.DEFAULT.createTriangle(rings.get(0));
     }
 
     /**
@@ -475,7 +475,7 @@ final class WellKnownTextParser {
         final List<LinearRing> rings = new ArrayList<>();
         expect('(');
         do {
-            rings.add(GeometryFactory.createLinearRing(readPointList()));
+            rings.add(GeometryFactory.DEFAULT.createLinearRing(readPointList()));
         } while (accept(','));
         expect(')');
         return rings;
@@ -512,7 +512,7 @@ final class WellKnownTextParser {
      * Returns an empty ring, for the {@code EMPTY} form of the types which are made of rings.
      */
     private LinearRing emptyRing() {
-        return GeometryFactory.createLinearRing(new Coordinates().build());
+        return GeometryFactory.DEFAULT.createLinearRing(new Coordinates().build());
     }
 
     /**
@@ -678,12 +678,12 @@ final class WellKnownTextParser {
             if (size == 0) {
                 final Array empty = NDArrays.of(posSystem, DataType.DOUBLE, 0);
                 if (!hasM) {
-                    return GeometryFactory.createSequence(empty);
+                    return GeometryFactory.DEFAULT.createDataPoints(empty);
                 }
                 return createSequence(empty, NDArrays.of(MEASURE_SYSTEM, DataType.DOUBLE, 0));
             }
             if (!hasM) {
-                return GeometryFactory.createSequence(NDArrays.of(posSystem, Arrays.copyOf(values, count)));
+                return GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(posSystem, Arrays.copyOf(values, count)));
             }
             /*
              * The measure is the ordinate following the position ones in each tuple of the text,
@@ -705,7 +705,7 @@ final class WellKnownTextParser {
             final Map<String,Array> attributes = new LinkedHashMap<>(4);
             attributes.put(DataPointsType.ATT_POSITION, positions);
             attributes.put(DataPointsType.ATT_M, measures);
-            return GeometryFactory.createSequence(attributes);
+            return GeometryFactory.DEFAULT.createDataPoints(attributes);
         }
     }
 
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/Wrapper.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/Wrapper.java
index b1ef4bb647..eab2f0d3f7 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/Wrapper.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/Wrapper.java
@@ -282,9 +282,9 @@ add:    for (Geometry next = geometry;;) {
         }
         addPolyline(lines, coordinates);
         switch (lines.size()) {
-            case 0:  return GeometryFactory.createEmpty(crs);
+            case 0:  return GeometryFactory.DEFAULT.createEmpty(crs);
             case 1:  return lines.get(0);
-            default: return GeometryFactory.createMultiLineString(crs, lines.toArray(LineString[]::new));
+            default: return GeometryFactory.DEFAULT.createMultiLineString(crs, lines.toArray(LineString[]::new));
         }
     }
 
@@ -312,7 +312,7 @@ add:    for (Geometry next = geometry;;) {
         if (coordinates.size() >= 2) {
             final Tuple<?> first = coordinates.get(0);
             final Array positions = NDArrays.of(coordinates, first.getSampleSystem(), first.getDataType());
-            lines.add(GeometryFactory.createLineString(GeometryFactory.createSequence(positions)));
+            lines.add(GeometryFactory.DEFAULT.createLineString(GeometryFactory.DEFAULT.createDataPoints(positions)));
         }
         coordinates.clear();
     }
@@ -543,7 +543,7 @@ add:    for (Geometry next = geometry;;) {
             }
             case LINESTRING: {
                 if (isCollection(geometry)) break;
-                return GeometryFactory.createLineString(GeometryFactory.copy(geometry.getDataPoints()));
+                return GeometryFactory.DEFAULT.createLineString(GeometryFactory.DEFAULT.createDataPoints(geometry.getDataPoints()));
             }
             case POLYGON: {
                 if (!geometry.isEmpty() && geometry instanceof MultiLineString lines) {
@@ -554,33 +554,33 @@ add:    for (Geometry next = geometry;;) {
                     for (int i=1; i<count; i++) {
                         interiors.add(toRing(lines.getGeometryN(i)));
                     }
-                    return GeometryFactory.createPolygon(exterior, interiors);
+                    return GeometryFactory.DEFAULT.createPolygon(exterior, interiors);
                 }
                 if (isCollection(geometry)) break;
-                return GeometryFactory.createPolygon(toRing(geometry), List.of());
+                return GeometryFactory.DEFAULT.createPolygon(toRing(geometry), List.of());
             }
             case MULTIPOINT: {
                 if (geometry instanceof Point point) {
-                    return GeometryFactory.createMultiPoint(point);
+                    return GeometryFactory.DEFAULT.createMultiPoint(point);
                 }
-                return GeometryFactory.createMultiPoint(GeometryFactory.copy(geometry.getDataPoints()));
+                return GeometryFactory.DEFAULT.createMultiPoint(GeometryFactory.DEFAULT.createDataPoints(geometry.getDataPoints()));
             }
             case MULTILINESTRING: {
-                return GeometryFactory.createMultiLineString(crs,
-                        components(LineString.class, LineString[]::new, GeometryFactory::createLineString));
+                return GeometryFactory.DEFAULT.createMultiLineString(crs,
+                        components(LineString.class, LineString[]::new, GeometryFactory.DEFAULT::createLineString));
             }
             case MULTIPOLYGON: {
-                return GeometryFactory.createMultiPolygon(crs,
+                return GeometryFactory.DEFAULT.createMultiPolygon(crs,
                         components(Polygon.class, Polygon[]::new,
-                                   (points) -> GeometryFactory.createPolygon(GeometryFactory.createLinearRing(points), List.of())));
+                                   (points) -> GeometryFactory.DEFAULT.createPolygon(GeometryFactory.DEFAULT.createLinearRing(points), List.of())));
             }
             case GEOMETRYCOLLECTION: {
                 if (geometry instanceof Point point) {
-                    return GeometryFactory.createMultiPoint(point);
+                    return GeometryFactory.DEFAULT.createMultiPoint(point);
                 } else if (geometry instanceof LineString line) {
-                    return GeometryFactory.createMultiLineString(line);
+                    return GeometryFactory.DEFAULT.createMultiLineString(line);
                 } else if (geometry instanceof Polygon polygon) {
-                    return GeometryFactory.createMultiPolygon(polygon);
+                    return GeometryFactory.DEFAULT.createMultiPolygon(polygon);
                 }
                 break;
             }
@@ -612,7 +612,7 @@ add:    for (Geometry next = geometry;;) {
             } else if (isCollection(element)) {
                 throw new IllegalArgumentException(Errors.format(Errors.Keys.NestedElementNotAllowed_1, GeometryCollection.class));
             } else {
-                components[i] = newComponent.apply(GeometryFactory.copy(element.getDataPoints()));
+                components[i] = newComponent.apply(GeometryFactory.DEFAULT.createDataPoints(element.getDataPoints()));
             }
         }
         return components;
@@ -634,7 +634,7 @@ add:    for (Geometry next = geometry;;) {
      * so that the returned ring does not share its data with the given geometry.
      */
     private static LinearRing toRing(final Geometry source) {
-        return GeometryFactory.createLinearRing(GeometryFactory.copy(source.getDataPoints()));
+        return GeometryFactory.DEFAULT.createLinearRing(GeometryFactory.DEFAULT.createDataPoints(source.getDataPoints()));
     }
 
     /**
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultGeometryCollection.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultGeometryCollection.java
index cf209c2106..f713514ae1 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultGeometryCollection.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultGeometryCollection.java
@@ -98,7 +98,7 @@ public non-sealed class DefaultGeometryCollection<T extends Geometry> extends Ab
     public Geometry getBoundary() {
         if (isEmpty()) {
             // The boundary of the empty set is empty.
-            return GeometryFactory.createEmpty(getCoordinateReferenceSystem());
+            return GeometryFactory.DEFAULT.createEmpty(getCoordinateReferenceSystem());
         }
         //TODO : fallback on JTS until implemented
         return fromJTS(asJTS().getBoundary());
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiPoint.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiPoint.java
index 4d82331193..5e7f4bf9a2 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiPoint.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiPoint.java
@@ -98,7 +98,7 @@ public non-sealed class DefaultMultiPoint extends AbstractGeometry implements Mu
     public Geometry getBoundary() {
         if (isEmpty()) {
             // The boundary of the empty set is empty.
-            return GeometryFactory.createEmpty(getCoordinateReferenceSystem());
+            return GeometryFactory.DEFAULT.createEmpty(getCoordinateReferenceSystem());
         }
         //TODO : fallback on JTS until implemented
         return fromJTS(asJTS().getBoundary());
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolygon.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolygon.java
index 34ab1a5e9f..42ab75bc80 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolygon.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolygon.java
@@ -133,7 +133,7 @@ public non-sealed class DefaultPolygon extends AbstractGeometry implements Polyg
     public Geometry getBoundary() {
         if (isEmpty()) {
             // The boundary of the empty set is empty.
-            return GeometryFactory.createEmpty(getCoordinateReferenceSystem());
+            return GeometryFactory.DEFAULT.createEmpty(getCoordinateReferenceSystem());
         }
         //TODO : fallback on JTS until implemented
         return fromJTS(asJTS().getBoundary());
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitive.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitive.java
index 20500e9a78..ead826af31 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitive.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitive.java
@@ -1177,7 +1177,7 @@ public sealed interface MeshPrimitive extends Geometry
         @Override
         public LineString getGeometryN(int n) {
             final int[] indices = (index == null) ? new int[]{n*2, n*2+1} : index.toArrayInt(n*2, 2);
-            return GeometryFactory.createLineString(new Sequence(this, indices));
+            return GeometryFactory.DEFAULT.createLineString(new Sequence(this, indices));
         }
     }
 
@@ -1232,7 +1232,7 @@ public sealed interface MeshPrimitive extends Geometry
                 indices = Arrays.copyOf(indices, 4);
                 indices[3] = indices[0];
             }
-            return GeometryFactory.createTriangle(GeometryFactory.createLinearRing(new Sequence(this, indices)));
+            return GeometryFactory.DEFAULT.createTriangle(GeometryFactory.DEFAULT.createLinearRing(new Sequence(this, indices)));
         }
     }
 
@@ -1260,7 +1260,7 @@ public sealed interface MeshPrimitive extends Geometry
                 indices[2] = (int) index.get(2 + n).get(0);
             }
                 indices[3] = indices[0];
-            return GeometryFactory.createTriangle(GeometryFactory.createLinearRing(new Sequence(this, indices)));
+            return GeometryFactory.DEFAULT.createTriangle(GeometryFactory.DEFAULT.createLinearRing(new Sequence(this, indices)));
         }
     }
 
@@ -1298,7 +1298,7 @@ public sealed interface MeshPrimitive extends Geometry
             }
             indices[3] = indices[0];
 
-            return GeometryFactory.createTriangle(GeometryFactory.createLinearRing(new Sequence(this, indices)));
+            return GeometryFactory.DEFAULT.createTriangle(GeometryFactory.DEFAULT.createLinearRing(new Sequence(this, indices)));
         }
     }
 }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveVisitor.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveVisitor.java
index 6c233654ca..86ac47bf73 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveVisitor.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveVisitor.java
@@ -193,11 +193,11 @@ public abstract class MeshPrimitiveVisitor {
     }
 
     private Triangle readTriangle(int idx0, int idx1, int idx2) {
-        return GeometryFactory.createTriangle(GeometryFactory.createLinearRing(new MeshPrimitive.Sequence(primitive, new int[]{idx0, idx1, idx2, idx0})));
+        return GeometryFactory.DEFAULT.createTriangle(GeometryFactory.DEFAULT.createLinearRing(new MeshPrimitive.Sequence(primitive, new int[]{idx0, idx1, idx2, idx0})));
     }
 
     private LineString readLine(int idx0, int idx1) {
-        return GeometryFactory.createLineString(new MeshPrimitive.Sequence(primitive, new int[]{idx0, idx1}));
+        return GeometryFactory.DEFAULT.createLineString(new MeshPrimitive.Sequence(primitive, new int[]{idx0, idx1}));
     }
 
     /**
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Intersection.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Intersection.java
index 0f22b3f04e..6003e4fb20 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Intersection.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Intersection.java
@@ -214,7 +214,7 @@ public final class Intersection {
                         final double[] bary2 = Triangle.getBarycentricValue2D(x1, y1, x2, y2, x3, y3, p2.get(0), p2.get(1), 0.0, false);
                         final Point point1 = triangle.interpolate(bary1);
                         final Point point2 = triangle.interpolate(bary2);
-                        segments.add(GeometryFactory.createLineString(new DefaultDataPoints(point1, point2)));
+                        segments.add(GeometryFactory.DEFAULT.createLineString(new DefaultDataPoints(point1, point2)));
                     }
                 }
             } catch (TransformException ex) {
@@ -222,7 +222,7 @@ public final class Intersection {
             }
         }
 
-        final MultiLineString mline = GeometryFactory.createMultiLineString(segments.toArray(LineString[]::new));
+        final MultiLineString mline = GeometryFactory.DEFAULT.createMultiLineString(segments.toArray(LineString[]::new));
         final MeshPrimitive intersection = (MeshPrimitive) new GeometryProcessor().toPrimitive(mline);
         return intersection;
     }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/To3D.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/To3D.java
index 30a25fed0b..b86acd45b7 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/To3D.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/To3D.java
@@ -120,7 +120,7 @@ public final class To3D {
      */
     public static Point to3D(Point base, CoordinateReferenceSystem crs3d, Consumer<Tuple> zeditor) {
         final DataPoints copy3d = to3d(base.getDataPoints(), crs3d, zeditor);
-        return GeometryFactory.createPoint(copy3d);
+        return GeometryFactory.DEFAULT.createPoint(copy3d);
     }
 
     /**
@@ -128,7 +128,7 @@ public final class To3D {
      */
     public static LineString to3D(LineString base, CoordinateReferenceSystem crs3d, Consumer<Tuple> zeditor) {
         final DataPoints copy3d = to3d(base.getDataPoints(), crs3d, zeditor);
-        return GeometryFactory.createLineString(copy3d);
+        return GeometryFactory.DEFAULT.createLineString(copy3d);
     }
 
     /**
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java
index 8a767e7150..696c50b5a3 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java
@@ -88,7 +88,7 @@ public final class Transform {
                 cp.setAttribute(name, ps.getAttributeArray(name).copy());
             }
         }
-        return GeometryFactory.createLinearRing(cp);
+        return GeometryFactory.DEFAULT.createLinearRing(cp);
     }
 
     public static Polygon transform(Polygon p, CoordinateReferenceSystem crs, MathTransform transform) throws OperationException {
@@ -100,7 +100,7 @@ public final class Transform {
             interiors.set(i, transform(interiors.get(i), crs, transform));
         }
 
-        return GeometryFactory.createPolygon(exterior, interiors);
+        return GeometryFactory.DEFAULT.createPolygon(exterior, interiors);
     }
 
     public static MultiMeshPrimitive<?> transform(MultiMeshPrimitive<?> mp, CoordinateReferenceSystem crs, MathTransform transform) throws OperationException {
@@ -196,7 +196,7 @@ public final class Transform {
                 cp.setAttribute(name, ps.getAttributeArray(name).copy());
             }
         }
-        return GeometryFactory.createTriangle(GeometryFactory.createLinearRing(cp));
+        return GeometryFactory.DEFAULT.createTriangle(GeometryFactory.DEFAULT.createLinearRing(cp));
     }
 
 }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/simplify/greedyinsert/TINBuilder.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/simplify/greedyinsert/TINBuilder.java
index 2690c30976..6308f563d9 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/simplify/greedyinsert/TINBuilder.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/simplify/greedyinsert/TINBuilder.java
@@ -124,9 +124,9 @@ public final class TINBuilder {
         for (int i = 0, n = finished.size(); i < n; i++) {
             final WTriangle t = finished.get(i);
             final Array positions = NDArrays.of(Arrays.asList(t.p0, t.p1, t.p2, t.p0), t.p0.getSampleSystem(), t.p0.getDataType());
-            final DataPoints points = GeometryFactory.createSequence(positions);
-            final LinearRing exterior = GeometryFactory.createLinearRing(points);
-            triangles.add(GeometryFactory.createTriangle(exterior));
+            final DataPoints points = GeometryFactory.DEFAULT.createDataPoints(positions);
+            final LinearRing exterior = GeometryFactory.DEFAULT.createLinearRing(points);
+            triangles.add(GeometryFactory.DEFAULT.createTriangle(exterior));
         }
         return triangles;
     }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/simplify/greedyinsert/WTriangle.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/simplify/greedyinsert/WTriangle.java
index a51c27e427..547d90a807 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/simplify/greedyinsert/WTriangle.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/simplify/greedyinsert/WTriangle.java
@@ -40,7 +40,7 @@ import org.apache.sis.maths.Tuple;
  */
 public final class WTriangle extends AbstractGeometry implements Triangle {
 
-    private final LinearRing ring = GeometryFactory.createLinearRing(new DataPoints() {
+    private final LinearRing ring = GeometryFactory.DEFAULT.createLinearRing(new DataPoints() {
         @Override
         public CoordinateReferenceSystem getCoordinateReferenceSystem() {
             return p0.getCoordinateReferenceSystem();
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/triangulate/delaunay/OrientedTriangle.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/triangulate/delaunay/OrientedTriangle.java
index ca29c55cc0..592e11e4ce 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/triangulate/delaunay/OrientedTriangle.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/triangulate/delaunay/OrientedTriangle.java
@@ -39,7 +39,7 @@ import org.apache.sis.referencing.internal.shared.ShapeUtilities;
  */
 public final class OrientedTriangle extends AbstractGeometry implements Triangle, DataPoints {
 
-    private final LinearRing ring = GeometryFactory.createLinearRing(this);
+    private final LinearRing ring = GeometryFactory.DEFAULT.createLinearRing(this);
 
     private boolean obsolete = false;
     public final OrientedEdge ab;
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Capsule.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Capsule.java
index 5ef9d757c9..9207df3619 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Capsule.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Capsule.java
@@ -60,7 +60,7 @@ public final class Capsule extends AbstractGeometry{
      * @param  top     the center of the top sphere, not null.
      */
     public Capsule(Tuple<?> bottom, Tuple<?> top) {
-        points = GeometryFactory.createSequence(NDArrays.of(bottom.getSampleSystem(), bottom.getDataType(), 2));
+        points = GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(bottom.getSampleSystem(), bottom.getDataType(), 2));
         points.setPosition(0, bottom);
         points.setPosition(1, top);
     }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Cylinder.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Cylinder.java
index 9d06ce8736..91b933a76c 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Cylinder.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Cylinder.java
@@ -66,7 +66,7 @@ public final class Cylinder extends AbstractGeometry{
      * @param  top     the center of the top circle, not null.
      */
     public Cylinder(Tuple<?> bottom, Tuple<?> top) {
-        points = GeometryFactory.createSequence(NDArrays.of(bottom.getSampleSystem(), bottom.getDataType(), 2));
+        points = GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(bottom.getSampleSystem(), bottom.getDataType(), 2));
         points.setPosition(0, bottom);
         points.setPosition(1, top);
     }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Ellipsoid.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Ellipsoid.java
new file mode 100644
index 0000000000..86ed1001f8
--- /dev/null
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Ellipsoid.java
@@ -0,0 +1,364 @@
+/*
+ * 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.sis.geometries.solid;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.measure.Quantity;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+import org.opengis.geometry.DirectPosition;
+import org.opengis.geometry.Envelope;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.geometries.BBox;
+import org.apache.sis.geometries.Curve;
+import org.apache.sis.geometries.DataPoints;
+import org.apache.sis.geometries.Geometries;
+import org.apache.sis.geometries.GeometryFactory;
+import org.apache.sis.geometries.GeometryType;
+import org.apache.sis.geometries.SurfaceInterpolation;
+import org.apache.sis.geometries.DataPointsType;
+import org.apache.sis.geometries.internal.shared.AbstractGeometry;
+import org.apache.sis.geometries.surface.ParametricCurveSurface;
+import org.apache.sis.maths.DataType;
+import org.apache.sis.maths.NDArrays;
+import org.apache.sis.maths.SampleSystem;
+import org.apache.sis.maths.Tuple;
+import org.apache.sis.util.ArgumentChecks;
+
+// Specific to the geoapi-4.0 branch:
+import org.opengis.metadata.Identifier;
+
+
+/**
+ * An ellipsoid geometry defined by a center and one semi-axis length per axis of the coordinate
+ * system.
+ *
+ * <p>As a conic surface, an ellipsoid is a parametric curve surface given as a family of ellipses
+ * whose positions vary along the axis of the ellipsoid. Its horizontal curves are therefore lines
+ * of constant latitude and its vertical curves lines of constant longitude.</p>
+ *
+ * <p>Constraints:</p>
+ * <ul>
+ *   <li>The up-normal is the outward normal when the control points are ordered by increasing
+ *       longitude and increasing latitude.</li>
+ *   <li>There is one semi-axis per axis of the coordinate system, and each of them is positive.</li>
+ * </ul>
+ *
+ * <p>Note: this geometry is not the ellipsoid used as a geometric reference surface
+ * (ISO 19107:2019 - 6.2.3.4), which {@link org.opengis.referencing.datum.Ellipsoid} describes.
+ * That one is a property of the coordinate reference system; this one is a geometry expressed
+ * in such a system.</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public final class Ellipsoid extends AbstractGeometry implements ParametricCurveSurface {
+
+    /**
+     * Must contain one point: the center of the ellipsoid.
+     */
+    private final DataPoints points;
+
+    /**
+     * Length of the semi-axis along each axis of the coordinate system,
+     * in the units of that axis. There is one value per dimension.
+     */
+    private final double[] semiAxes;
+
+    /**
+     * @param dimension number of dimensions of the ellipsoid, must be positive.
+     */
+    public Ellipsoid(int dimension) {
+        this(Geometries.getUndefinedCRS(dimension));
+    }
+
+    /**
+     * @param crs ellipsoid coordinate system, not null.
+     */
+    public Ellipsoid(CoordinateReferenceSystem crs) {
+        points = GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(SampleSystem.of(crs), DataType.DOUBLE, 1));
+        semiAxes = unitSemiAxes(crs.getCoordinateSystem().getDimension());
+    }
+
+    /**
+     * @param dimension number of dimensions of the ellipsoid, must be positive.
+     * @param semiAxes  length of the semi-axis along each axis, one value per dimension.
+     *                  Each of them must be positive.
+     */
+    public Ellipsoid(int dimension, double... semiAxes) {
+        this(Geometries.getUndefinedCRS(dimension), semiAxes);
+    }
+
+    /**
+     * @param crs       ellipsoid coordinate system, not null.
+     * @param semiAxes  length of the semi-axis along each axis, one value per dimension.
+     *                  Each of them must be positive.
+     */
+    public Ellipsoid(CoordinateReferenceSystem crs, double... semiAxes) {
+        points = GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(SampleSystem.of(crs), DataType.DOUBLE, 1));
+        this.semiAxes = checkedSemiAxes(crs.getCoordinateSystem().getDimension(), semiAxes);
+    }
+
+    /**
+     * Creates an ellipsoid centered on the single position of the given sequence. The sequence is
+     * taken as-is, so the caller may give the ellipsoid the attributes carried by that sequence.
+     *
+     * @param  points  the center of the ellipsoid.
+     * @throws IllegalArgumentException if the given sequence does not hold exactly one position.
+     */
+    public Ellipsoid(DataPoints points) {
+        this.points = checkedPoints(points);
+        semiAxes = unitSemiAxes(points.getDimension());
+    }
+
+    /**
+     * Creates an ellipsoid of the given semi-axes centered on the single position of the given
+     * sequence.
+     *
+     * @param  points    the center of the ellipsoid.
+     * @param  semiAxes  length of the semi-axis along each axis, one value per dimension.
+     *                   Each of them must be positive.
+     * @throws IllegalArgumentException if the given sequence does not hold exactly one position,
+     *         or if the number of semi-axes is not the number of dimensions.
+     */
+    public Ellipsoid(DataPoints points, double... semiAxes) {
+        this.points = checkedPoints(points);
+        this.semiAxes = checkedSemiAxes(points.getDimension(), semiAxes);
+    }
+
+    /**
+     * Returns the given sequence if it holds the single position an ellipsoid is centered on.
+     */
+    private static DataPoints checkedPoints(final DataPoints points) {
+        if (points.size() != 1) {
+            throw new IllegalArgumentException("Ellipsoid sequence must contain one point");
+        }
+        return points;
+    }
+
+    /**
+     * Returns the semi-axes of an ellipsoid of the given number of dimensions which is a unit sphere.
+     */
+    private static double[] unitSemiAxes(final int dimension) {
+        final var lengths = new double[dimension];
+        Arrays.fill(lengths, 1.0);
+        return lengths;
+    }
+
+    /**
+     * Returns a copy of the given semi-axes after verifying that there is one of them per dimension
+     * and that all of them are positive.
+     */
+    private static double[] checkedSemiAxes(final int dimension, final double[] semiAxes) {
+        ensureValidSemiAxes(dimension, semiAxes);
+        return semiAxes.clone();
+    }
+
+    /**
+     * Verifies that there is one semi-axis per dimension and that all of them are positive.
+     */
+    private static void ensureValidSemiAxes(final int dimension, final double[] semiAxes) {
+        if (semiAxes.length != dimension) {
+            throw new IllegalArgumentException("Ellipsoid must have one semi-axis per dimension, expected "
+                    + dimension + " but found " + semiAxes.length);
+        }
+        for (int i=0; i<semiAxes.length; i++) {
+            ArgumentChecks.ensurePositive("semiAxes[" + i + ']', semiAxes[i]);
+        }
+    }
+
+    @Override
+    public GeometryType getGeometryType() {
+        return GeometryType.ELLIPSOID;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return false;
+    }
+
+    @Override
+    public Quantity<?> getArea() {
+        throw new UnsupportedOperationException("Not supported.");
+    }
+
+    @Override
+    public void setCoordinateReferenceSystem(CoordinateReferenceSystem cs) throws IllegalArgumentException {
+        if (cs.getCoordinateSystem().getDimension() != getCoordinateReferenceSystem().getCoordinateSystem().getDimension()) {
+            throw new IllegalArgumentException("New CRS dimension must be the same as previous CRS");
+        }
+        points.setCoordinateReferenceSystem(cs);
+    }
+
+    @Override
+    public CoordinateReferenceSystem getCoordinateReferenceSystem() {
+        return points.getCoordinateReferenceSystem();
+    }
+
+    @Override
+    public DataPointsType getDataPointsType() {
+        return points.getType();
+    }
+
+    /**
+     * Returns {@link SurfaceInterpolation#ELLIPTICAL}: this surface is a section of an ellipsoid.
+     *
+     * @see ISO 19107:2019 - 8.5.2
+     */
+    @UML(identifier="interpolation", specification=ISO_19107)
+    @Override
+    public List<SurfaceInterpolation> getInterpolation() {
+        return List.of(SurfaceInterpolation.ELLIPTICAL);
+    }
+
+    /**
+     * Returns a copy of the semi-axis lengths, one per axis of the coordinate system.
+     * Writing in the returned array does not reshape this ellipsoid;
+     * use {@link #setSemiAxes(double...)} for that.
+     *
+     * @return length of the semi-axis along each axis.
+     */
+    public double[] getSemiAxes() {
+        return semiAxes.clone();
+    }
+
+    /**
+     * @param  dimension  index of the axis along which to measure the semi-axis.
+     * @return length of the semi-axis along the given axis.
+     */
+    public double getSemiAxis(int dimension) {
+        return semiAxes[dimension];
+    }
+
+    /**
+     * @param semiAxes new semi-axis lengths, one per dimension. Each of them must be positive.
+     * @throws IllegalArgumentException if the number of semi-axes is not the number of dimensions.
+     */
+    public void setSemiAxes(double... semiAxes) {
+        ensureValidSemiAxes(this.semiAxes.length, semiAxes);
+        System.arraycopy(semiAxes, 0, this.semiAxes, 0, this.semiAxes.length);
+    }
+
+    /**
+     * @param dimension index of the axis along which to set the semi-axis.
+     * @param length    new semi-axis length, must be positive.
+     */
+    public void setSemiAxis(int dimension, double length) {
+        ArgumentChecks.ensurePositive("length", length);
+        semiAxes[dimension] = length;
+    }
+
+    /**
+     * Returns a copy of the ellipsoid center. Writing in the returned tuple does not move this
+     * ellipsoid; use {@link #setCenter(Tuple)} for that.
+     *
+     * @return ellipsoid center.
+     */
+    public Tuple<?> getCenter() {
+        return points.getPosition(0);
+    }
+
+    /**
+     * @param position new center of the ellipsoid
+     */
+    public void setCenter(Tuple<?> position) {
+        points.setPosition(0, position);
+    }
+
+    /**
+     * {@inheritDoc }
+     *
+     * <p>An ellipsoid reaches its semi-axis away from its center on each axis, so the smallest box
+     * containing it is the box of that extent around the center.</p>
+     */
+    @Override
+    public Envelope getEnvelope() {
+        final Tuple<?> center = getCenter();
+        final BBox env = new BBox(center, center);
+        env.setCoordinateReferenceSystem(getCoordinateReferenceSystem());
+        for (int i = 0, n = getDimension(); i < n; i++) {
+            final double c = center.get(i);
+            final double a = semiAxes[i];
+            if (a > 0) {
+                env.setRange(i, c-a, c+a);
+            }
+        }
+        return env;
+    }
+
+    // methods from ParametricCurveSurface
+
+    @Override
+    public int getRows() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public int getColumns() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public List<DirectPosition> getControlPoints() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public GeometryType getHorizontalCurveType() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public GeometryType getVerticalCurveType() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public List<double[]> getKnots() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public Curve getHorizontalCurve(double v) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public Curve getVerticalCurve(double u) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public DirectPosition getSurface(double u, double v) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public Identifier getName() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Returns the center of this ellipsoid, as a sequence of one position. An ellipsoid is defined
+     * by that position and by its semi-axes, so the center is the only position it holds.
+     */
+    @Override
+    public DataPoints getDataPoints() {
+        return points;
+    }
+
+}
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Sphere.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Sphere.java
index e6179b6b98..0e5ffe21e0 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Sphere.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Sphere.java
@@ -27,15 +27,16 @@ import org.apache.sis.geometries.BBox;
 import org.apache.sis.geometries.Curve;
 import org.apache.sis.geometries.DataPoints;
 import org.apache.sis.geometries.Geometries;
+import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.GeometryType;
 import org.apache.sis.geometries.SurfaceInterpolation;
 import org.apache.sis.geometries.DataPointsType;
 import org.apache.sis.geometries.internal.shared.AbstractGeometry;
-import org.apache.sis.geometries.internal.shared.SinglePositionDataPoints;
 import org.apache.sis.geometries.surface.ParametricCurveSurface;
+import org.apache.sis.maths.DataType;
+import org.apache.sis.maths.NDArrays;
+import org.apache.sis.maths.SampleSystem;
 import org.apache.sis.maths.Tuple;
-import org.apache.sis.maths.Vector;
-import org.apache.sis.maths.Vectors;
 import org.apache.sis.util.ArgumentChecks;
 
 // Specific to the geoapi-4.0 branch:
@@ -70,7 +71,11 @@ import org.opengis.metadata.Identifier;
 @UML(identifier="Sphere", specification=ISO_19107)
 public final class Sphere extends AbstractGeometry implements ParametricCurveSurface {
 
-    private Tuple<?> center;
+    /**
+     * Must contain one point: the center of the sphere.
+     */
+    private final DataPoints points;
+
     private double radius = 1.0;
 
     /**
@@ -84,7 +89,7 @@ public final class Sphere extends AbstractGeometry implements ParametricCurveSur
      * @param crs sphere coordinate system, not null.
      */
     public Sphere(CoordinateReferenceSystem crs) {
-        center = Vectors.createDouble(crs);
+        points = GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(SampleSystem.of(crs), DataType.DOUBLE, 1));
     }
 
     /**
@@ -92,8 +97,7 @@ public final class Sphere extends AbstractGeometry implements ParametricCurveSur
      * @param radius radius new sphere radius, must be positive.
      */
     public Sphere(int dimension, double radius) {
-        this(Geometries.getUndefinedCRS(dimension));
-        this.radius = radius;
+        this(Geometries.getUndefinedCRS(dimension), radius);
     }
 
     /**
@@ -101,7 +105,33 @@ public final class Sphere extends AbstractGeometry implements ParametricCurveSur
      * @param radius radius new sphere radius, must be positive.
      */
     public Sphere(CoordinateReferenceSystem crs, double radius) {
-        center = Vectors.createDouble(crs);
+        this(crs);
+        this.radius = radius;
+    }
+
+    /**
+     * Creates a sphere centered on the single position of the given sequence. The sequence is
+     * taken as-is, so the caller may give the sphere the attributes carried by that sequence.
+     *
+     * @param  points  the center of the sphere.
+     * @throws IllegalArgumentException if the given sequence does not hold exactly one position.
+     */
+    public Sphere(DataPoints points) {
+        if (points.size() != 1) {
+            throw new IllegalArgumentException("Sphere sequence must contain one point");
+        }
+        this.points = points;
+    }
+
+    /**
+     * Creates a sphere of the given radius centered on the single position of the given sequence.
+     *
+     * @param  points  the center of the sphere.
+     * @param  radius  new sphere radius, must be positive.
+     * @throws IllegalArgumentException if the given sequence does not hold exactly one position.
+     */
+    public Sphere(DataPoints points, double radius) {
+        this(points);
         this.radius = radius;
     }
 
@@ -125,19 +155,17 @@ public final class Sphere extends AbstractGeometry implements ParametricCurveSur
         if (cs.getCoordinateSystem().getDimension() != getCoordinateReferenceSystem().getCoordinateSystem().getDimension()) {
             throw new IllegalArgumentException("New CRS dimension must be the same as previous CRS");
         }
-        Vector v = Vectors.create(cs, center.getDataType());
-        v.set(center);
-        center = v;
+        points.setCoordinateReferenceSystem(cs);
     }
 
     @Override
     public CoordinateReferenceSystem getCoordinateReferenceSystem() {
-        return center.getCoordinateReferenceSystem();
+        return points.getCoordinateReferenceSystem();
     }
 
     @Override
     public DataPointsType getDataPointsType() {
-        return getDataPoints().getType();
+        return points.getType();
     }
 
     /**
@@ -167,10 +195,20 @@ public final class Sphere extends AbstractGeometry implements ParametricCurveSur
     }
 
     /**
-     * @return sphere center, modifiable.
+     * Returns a copy of the sphere center. Writing in the returned tuple does not move this
+     * sphere; use {@link #setCenter(Tuple)} for that.
+     *
+     * @return sphere center.
      */
     public Tuple<?> getCenter() {
-        return center;
+        return points.getPosition(0);
+    }
+
+    /**
+     * @param position new center of the sphere
+     */
+    public void setCenter(Tuple<?> position) {
+        points.setPosition(0, position);
     }
 
     /**
@@ -184,7 +222,7 @@ public final class Sphere extends AbstractGeometry implements ParametricCurveSur
         if (radius > 0) {
             for (int i = 0, n = getDimension(); i < n; i++) {
                 double c = center.get(i);
-                env.setRange(0, c-radius, c+radius);
+                env.setRange(i, c-radius, c+radius);
             }
         }
         return env;
@@ -248,7 +286,7 @@ public final class Sphere extends AbstractGeometry implements ParametricCurveSur
      */
     @Override
     public DataPoints getDataPoints() {
-        return new SinglePositionDataPoints(this::getCenter);
+        return points;
     }
 
 }
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/polyhedron/AbstractPolyhedron.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/polyhedron/AbstractPolyhedron.java
index 4f6c95e638..a3fa73b8c2 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/polyhedron/AbstractPolyhedron.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/polyhedron/AbstractPolyhedron.java
@@ -193,8 +193,8 @@ public abstract sealed class AbstractPolyhedron extends AbstractGeometry impleme
      */
     protected static Polygon toPolygon(Array vertices, int[] face) {
         final Array positions = NDArrays.subset(vertices, face);
-        final LinearRing ring = GeometryFactory.createLinearRing(GeometryFactory.createSequence(positions));
-        return GeometryFactory.createPolygon(ring, null);
+        final LinearRing ring = GeometryFactory.DEFAULT.createLinearRing(GeometryFactory.DEFAULT.createDataPoints(positions));
+        return GeometryFactory.DEFAULT.createPolygon(ring, null);
     }
 
 
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/ParametricCurveSurface.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/ParametricCurveSurface.java
index 2b0329269c..df0b18c59b 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/ParametricCurveSurface.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/ParametricCurveSurface.java
@@ -26,6 +26,7 @@ import org.apache.sis.geometries.DataPoints;
 import org.apache.sis.geometries.GeometryType;
 import org.apache.sis.geometries.Surface;
 import org.apache.sis.geometries.SurfaceInterpolation;
+import org.apache.sis.geometries.solid.Ellipsoid;
 import org.apache.sis.geometries.solid.Sphere;
 
 
@@ -64,6 +65,7 @@ import org.apache.sis.geometries.solid.Sphere;
 public sealed interface ParametricCurveSurface extends Surface, ReferenceSystem
         permits BilinearGrid,
                 BSplineSurface,
+                Ellipsoid,
                 Sphere
 {
 
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/GML2Reader.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/GML2Reader.java
index 0fffcc11f3..ad9aaf42ea 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/GML2Reader.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/GML2Reader.java
@@ -130,7 +130,7 @@ public final class GML2Reader extends AbstractGMLReader {
         if (coordinates.size() != 1) {
             throw new DataStoreContentException("A GML 2.0 Point must contain exactly one coordinate tuple.");
         }
-        return GeometryFactory.createPoint(coordinates.build(crs));
+        return GeometryFactory.DEFAULT.createPoint(coordinates.build(crs));
     }
 
     /**
@@ -144,7 +144,7 @@ public final class GML2Reader extends AbstractGMLReader {
         if (coordinates.size() < 2) {
             throw new DataStoreContentException("A GML 2.0 LineString must contain at least two coordinate tuples.");
         }
-        return GeometryFactory.createLineString(coordinates.build(crs));
+        return GeometryFactory.DEFAULT.createLineString(coordinates.build(crs));
     }
 
     /**
@@ -158,7 +158,7 @@ public final class GML2Reader extends AbstractGMLReader {
         if (coordinates.size() < 4) {
             throw new DataStoreContentException("A GML 2.0 LinearRing must contain at least four coordinate tuples.");
         }
-        return GeometryFactory.createLinearRing(coordinates.build(crs));
+        return GeometryFactory.DEFAULT.createLinearRing(coordinates.build(crs));
     }
 
     /**
@@ -192,7 +192,7 @@ public final class GML2Reader extends AbstractGMLReader {
                         if (shell == null) {
                             throw new DataStoreContentException("A GML 2.0 Polygon must contain an outerBoundaryIs element.");
                         }
-                        return GeometryFactory.createPolygon(shell, holes);
+                        return GeometryFactory.DEFAULT.createPolygon(shell, holes);
                     }
                     break;
                 }
@@ -283,7 +283,7 @@ public final class GML2Reader extends AbstractGMLReader {
                 }
                 case END_ELEMENT: {
                     if (GML2Tags.MULTI_POINT.equals(reader.getLocalName())) {
-                        return GeometryFactory.createMultiPoint(aggregateCRS(crs, members),
+                        return GeometryFactory.DEFAULT.createMultiPoint(aggregateCRS(crs, members),
                                 members.toArray(Point[]::new));
                     }
                     break;
@@ -313,7 +313,7 @@ public final class GML2Reader extends AbstractGMLReader {
                 }
                 case END_ELEMENT: {
                     if (GML2Tags.MULTI_LINE_STRING.equals(reader.getLocalName())) {
-                        return GeometryFactory.createMultiLineString(aggregateCRS(crs, members),
+                        return GeometryFactory.DEFAULT.createMultiLineString(aggregateCRS(crs, members),
                                 members.toArray(LineString[]::new));
                     }
                     break;
@@ -343,7 +343,7 @@ public final class GML2Reader extends AbstractGMLReader {
                 }
                 case END_ELEMENT: {
                     if (GML2Tags.MULTI_POLYGON.equals(reader.getLocalName())) {
-                        return GeometryFactory.createMultiPolygon(aggregateCRS(crs, members),
+                        return GeometryFactory.DEFAULT.createMultiPolygon(aggregateCRS(crs, members),
                                 members.toArray(Polygon[]::new));
                     }
                     break;
@@ -373,7 +373,7 @@ public final class GML2Reader extends AbstractGMLReader {
                 }
                 case END_ELEMENT: {
                     if (GML2Tags.MULTI_GEOMETRY.equals(reader.getLocalName())) {
-                        return GeometryFactory.createGeometryCollection(aggregateCRS(crs, members),
+                        return GeometryFactory.DEFAULT.createGeometryCollection(aggregateCRS(crs, members),
                                 members.toArray(Geometry[]::new));
                     }
                     break;
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/GML3Reader.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/GML3Reader.java
index 9710cd1f4b..046aa757e5 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/GML3Reader.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/GML3Reader.java
@@ -286,7 +286,7 @@ public final class GML3Reader extends AbstractGMLReader {
         if (coordinates.size() != 1) {
             throw new DataStoreContentException("A GML 3 Point must contain exactly one coordinate tuple.");
         }
-        return GeometryFactory.createPoint(coordinates.build(crs));
+        return GeometryFactory.DEFAULT.createPoint(coordinates.build(crs));
     }
 
     /**
@@ -300,7 +300,7 @@ public final class GML3Reader extends AbstractGMLReader {
         if (coordinates.size() < 2) {
             throw new DataStoreContentException("A GML 3 LineString must contain at least two coordinate tuples.");
         }
-        return GeometryFactory.createLineString(coordinates.build(crs));
+        return GeometryFactory.DEFAULT.createLineString(coordinates.build(crs));
     }
 
     /**
@@ -314,7 +314,7 @@ public final class GML3Reader extends AbstractGMLReader {
         if (coordinates.size() < 4) {
             throw new DataStoreContentException("A GML 3 LinearRing must contain at least four coordinate tuples.");
         }
-        return GeometryFactory.createLinearRing(coordinates.build(crs));
+        return GeometryFactory.DEFAULT.createLinearRing(coordinates.build(crs));
     }
 
     /**
@@ -438,9 +438,9 @@ public final class GML3Reader extends AbstractGMLReader {
                                     linearHoles.add((LinearRing) hole);
                                 }
                             }
-                            return GeometryFactory.createPolygon((LinearRing) shell, linearHoles);
+                            return GeometryFactory.DEFAULT.createPolygon((LinearRing) shell, linearHoles);
                         }
-                        return GeometryFactory.createCurvePolygon(shell, holes);
+                        return GeometryFactory.DEFAULT.createCurvePolygon(shell, holes);
                     }
                     break;
                 }
@@ -510,7 +510,7 @@ public final class GML3Reader extends AbstractGMLReader {
                 }
                 case END_ELEMENT: {
                     if (GML2Tags.MULTI_POINT.equals(reader.getLocalName())) {
-                        return GeometryFactory.createMultiPoint(aggregateCRS(crs, members),
+                        return GeometryFactory.DEFAULT.createMultiPoint(aggregateCRS(crs, members),
                                 members.toArray(Point[]::new));
                     }
                     break;
@@ -548,10 +548,10 @@ public final class GML3Reader extends AbstractGMLReader {
                     if (enclosingTagName.equals(reader.getLocalName())) {
                         final CoordinateReferenceSystem fallback = aggregateCRS(crs, members);
                         if (allInstanceOf(members, LineString.class)) {
-                            return GeometryFactory.createMultiLineString(fallback,
+                            return GeometryFactory.DEFAULT.createMultiLineString(fallback,
                                     members.toArray(LineString[]::new));
                         }
-                        return GeometryFactory.createMultiCurve(fallback, members.toArray(Curve[]::new));
+                        return GeometryFactory.DEFAULT.createMultiCurve(fallback, members.toArray(Curve[]::new));
                     }
                     break;
                 }
@@ -588,10 +588,10 @@ public final class GML3Reader extends AbstractGMLReader {
                     if (enclosingTagName.equals(reader.getLocalName())) {
                         final CoordinateReferenceSystem fallback = aggregateCRS(crs, members);
                         if (allInstanceOf(members, Polygon.class)) {
-                            return GeometryFactory.createMultiPolygon(fallback,
+                            return GeometryFactory.DEFAULT.createMultiPolygon(fallback,
                                     members.toArray(Polygon[]::new));
                         }
-                        return GeometryFactory.createMultiSurface(fallback, members.toArray(Surface[]::new));
+                        return GeometryFactory.DEFAULT.createMultiSurface(fallback, members.toArray(Surface[]::new));
                     }
                     break;
                 }
@@ -622,7 +622,7 @@ public final class GML3Reader extends AbstractGMLReader {
                 }
                 case END_ELEMENT: {
                     if (GML2Tags.MULTI_GEOMETRY.equals(reader.getLocalName())) {
-                        return GeometryFactory.createGeometryCollection(aggregateCRS(crs, members),
+                        return GeometryFactory.DEFAULT.createGeometryCollection(aggregateCRS(crs, members),
                                 members.toArray(Geometry[]::new));
                     }
                     break;
@@ -680,7 +680,7 @@ public final class GML3Reader extends AbstractGMLReader {
                             throw new DataStoreContentException("A GML 3 Curve must contain at least one segment.");
                         }
                         return (segments.size() == 1) ? segments.get(0)
-                                : GeometryFactory.createCompoundCurve(crs, segments.toArray(Curve[]::new));
+                                : GeometryFactory.DEFAULT.createCompoundCurve(crs, segments.toArray(Curve[]::new));
                     }
                     break;
                 }
@@ -710,7 +710,7 @@ public final class GML3Reader extends AbstractGMLReader {
                         case GML3Tags.LINE_STRING_SEGMENT:
                         case GML3Tags.GEODESIC_STRING:
                         case GML3Tags.GEODESIC: {
-                            addTo.add(GeometryFactory.createLineString(parseCoordinateSequence(segment, crs).build(crs)));
+                            addTo.add(GeometryFactory.DEFAULT.createLineString(parseCoordinateSequence(segment, crs).build(crs)));
                             break;
                         }
                         /*
@@ -719,7 +719,7 @@ public final class GML3Reader extends AbstractGMLReader {
                          */
                         case GML3Tags.ARC:
                         case GML3Tags.ARC_STRING: {
-                            addTo.add(GeometryFactory.createCircularString(parseCoordinateSequence(segment, crs).build(crs)));
+                            addTo.add(GeometryFactory.DEFAULT.createCircularString(parseCoordinateSequence(segment, crs).build(crs)));
                             break;
                         }
                         case GML3Tags.ARC_BY_CENTER_POINT: {
@@ -809,7 +809,7 @@ public final class GML3Reader extends AbstractGMLReader {
                                         + " centre as either a pointProperty or exactly one coordinate tuple,"
                                         + " but " + coordinates.size() + " tuples were found.");
                             }
-                            center = GeometryFactory.createPoint(coordinates.build(crs));
+                            center = GeometryFactory.DEFAULT.createPoint(coordinates.build(crs));
                         }
                         if (Double.isNaN(radius)) {
                             throw new DataStoreContentException("A GML 3 ArcByCenterPoint must contain a radius element.");
@@ -819,7 +819,7 @@ public final class GML3Reader extends AbstractGMLReader {
                                     + " startAngle and an endAngle element.");
                         }
                         try {
-                            return GeometryFactory.createArcByCenterPoint(center, radius, unit, startAngle, endAngle);
+                            return GeometryFactory.DEFAULT.createArcByCenterPoint(center, radius, unit, startAngle, endAngle);
                         } catch (IllegalArgumentException e) {
                             throw new DataStoreContentException(e.getMessage(), e);
                         }
@@ -879,7 +879,7 @@ public final class GML3Reader extends AbstractGMLReader {
                         final Vector<?> direction = Vectors.createDouble(normal.length);
                         direction.set(normal);
                         try {
-                            return GeometryFactory.createArcByBulge(coordinates.build(crs), bulge, direction);
+                            return GeometryFactory.DEFAULT.createArcByBulge(coordinates.build(crs), bulge, direction);
                         } catch (IllegalArgumentException e) {
                             throw new DataStoreContentException(e.getMessage(), e);
                         }
@@ -977,7 +977,7 @@ public final class GML3Reader extends AbstractGMLReader {
             throws XMLStreamException, DataStoreContentException, DataStoreReferencingException
     {
         final List<Curve> members = parseCurveMembers(crs, GML3Tags.COMPOSITE_CURVE);
-        return GeometryFactory.createCompoundCurve(aggregateCRS(crs, members), members.toArray(Curve[]::new));
+        return GeometryFactory.DEFAULT.createCompoundCurve(aggregateCRS(crs, members), members.toArray(Curve[]::new));
     }
 
     /**
@@ -995,7 +995,7 @@ public final class GML3Reader extends AbstractGMLReader {
         if (members.size() == 1 && members.get(0) instanceof LinearRing single) {
             return single;
         }
-        return GeometryFactory.createCompoundCurve(aggregateCRS(crs, members), members.toArray(Curve[]::new));
+        return GeometryFactory.DEFAULT.createCompoundCurve(aggregateCRS(crs, members), members.toArray(Curve[]::new));
     }
 
     /**
@@ -1011,7 +1011,7 @@ public final class GML3Reader extends AbstractGMLReader {
                 reader.getAttributeValue(null, GML3Tags.ORIENTATION));
         final Curve base = parseSingleProperty(Curve.class, GML3Tags.BASE_CURVE,
                 GML3Tags.ORIENTABLE_CURVE, crs);
-        return reversed ? GeometryFactory.createReversed(base) : base;
+        return reversed ? GeometryFactory.DEFAULT.createReversed(base) : base;
     }
 
     // ////////////////////////////////////////////////////////////////////////
@@ -1075,18 +1075,18 @@ public final class GML3Reader extends AbstractGMLReader {
                 throw new DataStoreContentException("A GML 3 <" + enclosingTagName
                         + "> must contain only gml:Triangle patches.");
             }
-            return GeometryFactory.createTIN(fallback, patches.toArray(Triangle[]::new));
+            return GeometryFactory.DEFAULT.createTIN(fallback, patches.toArray(Triangle[]::new));
         }
         if (!allInstanceOf(patches, Polygon.class)) {
-            return GeometryFactory.createMultiSurface(fallback, patches.toArray(Surface[]::new));
+            return GeometryFactory.DEFAULT.createMultiSurface(fallback, patches.toArray(Surface[]::new));
         }
         if (patches.size() == 1) {
             return patches.get(0);
         }
         if (!patches.isEmpty() && allInstanceOf(patches, Triangle.class)) {
-            return GeometryFactory.createTIN(fallback, patches.toArray(Triangle[]::new));
+            return GeometryFactory.DEFAULT.createTIN(fallback, patches.toArray(Triangle[]::new));
         }
-        return GeometryFactory.createPolyhedralSurface(fallback, patches.toArray(Polygon[]::new));
+        return GeometryFactory.DEFAULT.createPolyhedralSurface(fallback, patches.toArray(Polygon[]::new));
     }
 
     /**
@@ -1112,7 +1112,7 @@ public final class GML3Reader extends AbstractGMLReader {
                             if (!(s instanceof Polygon p)) {
                                 throw new DataStoreContentException("A GML 3 Triangle patch must have a linear boundary.");
                             }
-                            addTo.add(GeometryFactory.createTriangle(p.getExteriorRing()));
+                            addTo.add(GeometryFactory.DEFAULT.createTriangle(p.getExteriorRing()));
                             break;
                         }
                         default: skipUntilEnd(); break;
@@ -1156,9 +1156,9 @@ public final class GML3Reader extends AbstractGMLReader {
                     if (GML3Tags.COMPOSITE_SURFACE.equals(reader.getLocalName())) {
                         final CoordinateReferenceSystem fallback = aggregateCRS(crs, members);
                         if (allInstanceOf(members, Polygon.class)) {
-                            return GeometryFactory.createPolyhedralSurface(fallback, members.toArray(Polygon[]::new));
+                            return GeometryFactory.DEFAULT.createPolyhedralSurface(fallback, members.toArray(Polygon[]::new));
                         }
-                        return GeometryFactory.createMultiSurface(fallback, members.toArray(Surface[]::new));
+                        return GeometryFactory.DEFAULT.createMultiSurface(fallback, members.toArray(Surface[]::new));
                     }
                     break;
                 }
@@ -1179,7 +1179,7 @@ public final class GML3Reader extends AbstractGMLReader {
                 reader.getAttributeValue(null, GML3Tags.ORIENTATION));
         final Surface base = parseSingleProperty(Surface.class, GML3Tags.BASE_SURFACE,
                 GML3Tags.ORIENTABLE_SURFACE, crs);
-        return reversed ? GeometryFactory.createReversed(base) : base;
+        return reversed ? GeometryFactory.DEFAULT.createReversed(base) : base;
     }
 
     // ////////////////////////////////////////////////////////////////////////
@@ -1223,7 +1223,7 @@ public final class GML3Reader extends AbstractGMLReader {
                         if (exterior == null) {
                             throw new DataStoreContentException("A GML 3 Solid must contain an exterior shell.");
                         }
-                        return GeometryFactory.createPolyhedron(exterior, interiors);
+                        return GeometryFactory.DEFAULT.createPolyhedron(exterior, interiors);
                     }
                     break;
                 }
@@ -1286,7 +1286,7 @@ public final class GML3Reader extends AbstractGMLReader {
                 }
                 case END_ELEMENT: {
                     if (GML3Tags.SHELL.equals(reader.getLocalName())) {
-                        return GeometryFactory.createMultiPolygon(aggregateCRS(crs, faces),
+                        return GeometryFactory.DEFAULT.createMultiPolygon(aggregateCRS(crs, faces),
                                 faces.toArray(Polygon[]::new));
                     }
                     break;
@@ -1318,7 +1318,7 @@ public final class GML3Reader extends AbstractGMLReader {
                 }
                 case END_ELEMENT: {
                     if (enclosingTagName.equals(reader.getLocalName())) {
-                        return GeometryFactory.createMultiPolyhedron(aggregateCRS(crs, members),
+                        return GeometryFactory.DEFAULT.createMultiPolyhedron(aggregateCRS(crs, members),
                                 members.toArray(Polyhedron[]::new));
                     }
                     break;
diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/PositionListBuilder.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/PositionListBuilder.java
index 9894f3d501..e6dacaec37 100644
--- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/PositionListBuilder.java
+++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/gml/PositionListBuilder.java
@@ -177,9 +177,9 @@ final class PositionListBuilder {
          */
         if (count == 0) {
             final SampleSystem ss = SampleSystem.of(GMLCRS.forDimension(inScope, (dimension != 0) ? dimension : 2));
-            return GeometryFactory.createSequence(NDArrays.of(ss, DataType.DOUBLE, 0));
+            return GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(ss, DataType.DOUBLE, 0));
         }
         final SampleSystem ss = SampleSystem.of(GMLCRS.forDimension(inScope, dimension));
-        return GeometryFactory.createSequence(NDArrays.of(ss, toFlatArray()));
+        return GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(ss, toFlatArray()));
     }
 }
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/ShapeAdapterTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/ShapeAdapterTest.java
index 4a5b18e07f..90d28c0ce2 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/ShapeAdapterTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/ShapeAdapterTest.java
@@ -98,7 +98,7 @@ public final class ShapeAdapterTest {
      */
     @Test
     public void testPoint() {
-        initialize(GeometryFactory.createPoint(CARTESIAN_2D, 10, 20));
+        initialize(GeometryFactory.DEFAULT.createPoint(CARTESIAN_2D, 10, 20));
         assertSegmentEquals(PathIterator.SEG_MOVETO, 10, 20);
         assertTrue(iterator.isDone());
     }
@@ -108,7 +108,7 @@ public final class ShapeAdapterTest {
      */
     @Test
     public void testLineString() {
-        initialize(GeometryFactory.createLineString(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
+        initialize(GeometryFactory.DEFAULT.createLineString(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
             3,1,
             7,6,
             5,2
@@ -124,16 +124,16 @@ public final class ShapeAdapterTest {
      */
     @Test
     public void testMultiLineString() {
-        final LineString line1 = GeometryFactory.createLineString(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
+        final LineString line1 = GeometryFactory.DEFAULT.createLineString(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
             10, 12,
             5, 2
         })));
-        final LineString line2 = GeometryFactory.createLineString(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
+        final LineString line2 = GeometryFactory.DEFAULT.createLineString(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
             3, 1,
             7, 6,
             5, 2
         })));
-        initialize(GeometryFactory.createMultiLineString(line1, line2));
+        initialize(GeometryFactory.DEFAULT.createMultiLineString(line1, line2));
         assertSegmentEquals(PathIterator.SEG_MOVETO, 10, 12);
         assertSegmentEquals(PathIterator.SEG_LINETO, 5, 2);
         assertSegmentEquals(PathIterator.SEG_MOVETO, 3, 1);
@@ -147,13 +147,13 @@ public final class ShapeAdapterTest {
      */
     @Test
     public void testPolygon() {
-        final LinearRing ring = GeometryFactory.createLinearRing(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
+        final LinearRing ring = GeometryFactory.DEFAULT.createLinearRing(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
             3, 1,
             7, 6,
             5, 2,
             3, 1
         })));
-        initialize(GeometryFactory.createPolygon(ring, null));
+        initialize(GeometryFactory.DEFAULT.createPolygon(ring, null));
         assertSegmentEquals(PathIterator.SEG_MOVETO, 3, 1);
         assertSegmentEquals(PathIterator.SEG_LINETO, 7, 6);
         assertSegmentEquals(PathIterator.SEG_LINETO, 5, 2);
@@ -166,21 +166,21 @@ public final class ShapeAdapterTest {
      */
     @Test
     public void testMultiPolygon() {
-        final LinearRing ring1 = GeometryFactory.createLinearRing(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
+        final LinearRing ring1 = GeometryFactory.DEFAULT.createLinearRing(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
             3, 1,
             7, 6,
             5, 2,
             3, 1
         })));
-        final LinearRing ring2 = GeometryFactory.createLinearRing(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
+        final LinearRing ring2 = GeometryFactory.DEFAULT.createLinearRing(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
             12, 3,
             1, 9,
             4, 6,
             12, 3
         })));
-        final Polygon polygon1 = GeometryFactory.createPolygon(ring1, null);
-        final Polygon polygon2 = GeometryFactory.createPolygon(ring2, null);
-        initialize(GeometryFactory.createMultiPolygon(polygon1, polygon2));
+        final Polygon polygon1 = GeometryFactory.DEFAULT.createPolygon(ring1, null);
+        final Polygon polygon2 = GeometryFactory.DEFAULT.createPolygon(ring2, null);
+        initialize(GeometryFactory.DEFAULT.createMultiPolygon(polygon1, polygon2));
 
         // First polygon.
         assertSegmentEquals(PathIterator.SEG_MOVETO, 3, 1);
@@ -201,7 +201,7 @@ public final class ShapeAdapterTest {
      */
     @Test
     public void testAsDecimatedShapeLineString() {
-        final LineString line = GeometryFactory.createLineString(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
+        final LineString line = GeometryFactory.DEFAULT.createLineString(new ArrayDataPoints(NDArrays.of(CARTESIAN_2D, new double[]{
             0, 0,
             1, 0,
             2, 0
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/WellKnownBinaryTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/WellKnownBinaryTest.java
index b152fe623d..2ab943ce35 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/WellKnownBinaryTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/WellKnownBinaryTest.java
@@ -212,7 +212,7 @@ public final class WellKnownBinaryTest {
      */
     @Test
     public void testEmptyGeometry() {
-        final Geometry empty = GeometryFactory.createEmpty(Geometries.getUndefinedCRS(2));
+        final Geometry empty = GeometryFactory.DEFAULT.createEmpty(Geometries.getUndefinedCRS(2));
         assertEquals("000000000700000000", hex(wkb.encode(empty)));
         assertEquals("000000000700000000", hex(empty.asBinary()));
     }
@@ -287,10 +287,10 @@ public final class WellKnownBinaryTest {
      */
     @Test
     public void testUnsupportedType() {
-        final DataPoints points = GeometryFactory.createSequence(
+        final DataPoints points = GeometryFactory.DEFAULT.createDataPoints(
                 NDArrays.of(SampleSystem.of(Geometries.getUndefinedCRS(2)), 0, 0, 1, 1));
-        assertThrows(IllegalArgumentException.class, () -> wkb.encode(GeometryFactory.createGeodesic(points)));
-        assertThrows(IllegalArgumentException.class, () -> wkb.encode(GeometryFactory.createRhumb(points)));
+        assertThrows(IllegalArgumentException.class, () -> wkb.encode(GeometryFactory.DEFAULT.createGeodesic(points)));
+        assertThrows(IllegalArgumentException.class, () -> wkb.encode(GeometryFactory.DEFAULT.createRhumb(points)));
     }
 
     /**
@@ -299,7 +299,7 @@ public final class WellKnownBinaryTest {
      */
     @Test
     public void testTooManyDimensions() {
-        final Point point = GeometryFactory.createPoint(Geometries.getUndefinedCRS(4), 1, 2, 3, 4);
+        final Point point = GeometryFactory.DEFAULT.createPoint(Geometries.getUndefinedCRS(4), 1, 2, 3, 4);
         assertThrows(IllegalArgumentException.class, () -> wkb.encode(point));
     }
 
@@ -380,7 +380,7 @@ public final class WellKnownBinaryTest {
          * The 0x20000000 bit announces the identifier, which follows the type code.
          * EPSG:4326 is 0x10E6.
          */
-        final Geometry point = GeometryFactory.createPoint(CommonCRS.WGS84.geographic(), 1, 2);
+        final Geometry point = GeometryFactory.DEFAULT.createPoint(CommonCRS.WGS84.geographic(), 1, 2);
         final byte[] bytes = ewkb.encode(point);
         assertEquals("00" + "20000001" + "000010E6" + ONE + TWO, hex(bytes));
         /*
@@ -401,9 +401,9 @@ public final class WellKnownBinaryTest {
     public void testExtendedIdentifierOnOutermostOnly() {
         final WellKnownBinary ewkb = new WellKnownBinary(WellKnownBinary.Flavor.EWKB);
         final CoordinateReferenceSystem crs = CommonCRS.WGS84.geographic();
-        final byte[] bytes = ewkb.encode(GeometryFactory.createMultiPoint(
-                GeometryFactory.createPoint(crs, 1, 2),
-                GeometryFactory.createPoint(crs, 3, 4)));
+        final byte[] bytes = ewkb.encode(GeometryFactory.DEFAULT.createMultiPoint(
+                GeometryFactory.DEFAULT.createPoint(crs, 1, 2),
+                GeometryFactory.DEFAULT.createPoint(crs, 3, 4)));
         assertEquals("00" + "20000004" + "000010E6" + "00000002"
                    + "00" + "00000001" + ONE   + TWO
                    + "00" + "00000001" + THREE + FOUR, hex(bytes));
@@ -461,7 +461,7 @@ public final class WellKnownBinaryTest {
          * The standard dialect rejects the high order bits of the extended one.
          */
         assertMalformed(ewkb.encode(wkt.decode("POINT Z (1 2 3)")));
-        assertMalformed(ewkb.encode(GeometryFactory.createPoint(CommonCRS.WGS84.geographic(), 1, 2)));
+        assertMalformed(ewkb.encode(GeometryFactory.DEFAULT.createPoint(CommonCRS.WGS84.geographic(), 1, 2)));
     }
 
     /**
@@ -471,7 +471,7 @@ public final class WellKnownBinaryTest {
     @Test
     public void testExtendedPrecedenceAndErrors() {
         final WellKnownBinary ewkb = new WellKnownBinary(WellKnownBinary.Flavor.EWKB);
-        final byte[] bytes = ewkb.encode(GeometryFactory.createPoint(CommonCRS.WGS84.geographic(), 1, 2));
+        final byte[] bytes = ewkb.encode(GeometryFactory.DEFAULT.createPoint(CommonCRS.WGS84.geographic(), 1, 2));
         final CoordinateReferenceSystem crs = Geometries.getUndefinedCRS(2);
         assertSame(crs, ewkb.decode(bytes, crs).getCoordinateReferenceSystem());
         /*
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/WellKnownTextTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/WellKnownTextTest.java
index cb8d066e12..820b29130d 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/WellKnownTextTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/WellKnownTextTest.java
@@ -178,7 +178,7 @@ public final class WellKnownTextTest {
      */
     @Test
     public void testEmptyGeometry() {
-        final Geometry empty = GeometryFactory.createEmpty(Geometries.getUndefinedCRS(2));
+        final Geometry empty = GeometryFactory.DEFAULT.createEmpty(Geometries.getUndefinedCRS(2));
         assertEquals("GEOMETRYCOLLECTION EMPTY", wkt.encode(empty));
     }
 
@@ -234,7 +234,7 @@ public final class WellKnownTextTest {
      */
     @Test
     public void testWholeNumbers() {
-        final Point point = GeometryFactory.createPoint(Geometries.getUndefinedCRS(3), 1, 2, 3);
+        final Point point = GeometryFactory.DEFAULT.createPoint(Geometries.getUndefinedCRS(3), 1, 2, 3);
         assertEquals("POINT Z (1 2 3)", wkt.encode(point));
     }
 
@@ -258,10 +258,10 @@ public final class WellKnownTextTest {
      */
     @Test
     public void testUnsupportedType() {
-        final DataPoints points = GeometryFactory.createSequence(
+        final DataPoints points = GeometryFactory.DEFAULT.createDataPoints(
                 NDArrays.of(SampleSystem.of(Geometries.getUndefinedCRS(2)), 0, 0, 1, 1));
-        assertThrows(IllegalArgumentException.class, () -> wkt.encode(GeometryFactory.createGeodesic(points)));
-        assertThrows(IllegalArgumentException.class, () -> wkt.encode(GeometryFactory.createRhumb(points)));
+        assertThrows(IllegalArgumentException.class, () -> wkt.encode(GeometryFactory.DEFAULT.createGeodesic(points)));
+        assertThrows(IllegalArgumentException.class, () -> wkt.encode(GeometryFactory.DEFAULT.createRhumb(points)));
     }
 
     /**
@@ -270,7 +270,7 @@ public final class WellKnownTextTest {
      */
     @Test
     public void testTooManyDimensions() {
-        final Point point = GeometryFactory.createPoint(Geometries.getUndefinedCRS(4), 1, 2, 3, 4);
+        final Point point = GeometryFactory.DEFAULT.createPoint(Geometries.getUndefinedCRS(4), 1, 2, 3, 4);
         assertThrows(IllegalArgumentException.class, () -> wkt.encode(point));
     }
 
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/AbstractD9IMTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/AbstractD9IMTest.java
index 53d54afda6..f565b90ac1 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/AbstractD9IMTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/AbstractD9IMTest.java
@@ -69,34 +69,34 @@ public abstract class AbstractD9IMTest {
      * An empty geometry. Together with {@link #EMPTY_2}, it allows to verify that the result of an
      * operation on the empty set depends on the emptiness of the operands, not on their identity.
      */
-    public static final Empty EMPTY_1 = GeometryFactory.createEmpty(CRS_2D);
+    public static final Empty EMPTY_1 = GeometryFactory.DEFAULT.createEmpty(CRS_2D);
 
     /**
      * Another empty geometry, distinct from {@link #EMPTY_1} but equal to it as a set of positions.
      */
-    public static final Empty EMPTY_2 = GeometryFactory.createEmpty(CRS_2D);
+    public static final Empty EMPTY_2 = GeometryFactory.DEFAULT.createEmpty(CRS_2D);
 
     /**
      * An arbitrary geometry which is not empty, used as the other operand of the operations
      * tested against the empty set.
      */
-    public static final Point NON_EMPTY = GeometryFactory.createPoint(CRS_2D, 10.0, 5.0);
+    public static final Point NON_EMPTY = GeometryFactory.DEFAULT.createPoint(CRS_2D, 10.0, 5.0);
 
     /**
      * An arbitrary point. Together with {@link #POINT_A_BIS}, it allows to verify that the result
      * of an operation on two points depends on their positions, not on their identity.
      */
-    public static final Point POINT_A = GeometryFactory.createPoint(CRS_2D, 10.0, 5.0);
+    public static final Point POINT_A = GeometryFactory.DEFAULT.createPoint(CRS_2D, 10.0, 5.0);
 
     /**
      * Another point, distinct from {@link #POINT_A} but at the same position.
      */
-    public static final Point POINT_A_BIS = GeometryFactory.createPoint(CRS_2D, 10.0, 5.0);
+    public static final Point POINT_A_BIS = GeometryFactory.DEFAULT.createPoint(CRS_2D, 10.0, 5.0);
 
     /**
      * A point at a position different than {@link #POINT_A}.
      */
-    public static final Point POINT_B = GeometryFactory.createPoint(CRS_2D, 20.0, 15.0);
+    public static final Point POINT_B = GeometryFactory.DEFAULT.createPoint(CRS_2D, 20.0, 15.0);
 
     /**
      * The empty geometry expected as the result of an operation which found no position,
@@ -104,7 +104,7 @@ public abstract class AbstractD9IMTest {
      * It is a distinct instance from {@link #EMPTY_1} on purpose: an operation builds its
      * result rather than returning an operand when neither operand is empty.
      */
-    public static final Empty EMPTY_RESULT = GeometryFactory.createEmpty(CRS_2D);
+    public static final Empty EMPTY_RESULT = GeometryFactory.DEFAULT.createEmpty(CRS_2D);
 
     /*
      * ────────────────────────────────────────────────────────────────────────────────────────
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/DistanceTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/DistanceTest.java
index 562a1066dd..c21f4b1b7b 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/DistanceTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/DistanceTest.java
@@ -42,23 +42,23 @@ public class DistanceTest extends AbstractD9IMTest {
     /**
      * Two points at the same position, and a third one at a distance of 1 along the second axis.
      */
-    private static final Point POINT_10_5     = GeometryFactory.createPoint(CRS2D, 10.0, 5.0);
-    private static final Point POINT_10_5_BIS = GeometryFactory.createPoint(CRS2D, 10.0, 5.0);
-    private static final Point POINT_10_6     = GeometryFactory.createPoint(CRS2D, 10.0, 6.0);
+    private static final Point POINT_10_5     = GeometryFactory.DEFAULT.createPoint(CRS2D, 10.0, 5.0);
+    private static final Point POINT_10_5_BIS = GeometryFactory.DEFAULT.createPoint(CRS2D, 10.0, 5.0);
+    private static final Point POINT_10_6     = GeometryFactory.DEFAULT.createPoint(CRS2D, 10.0, 6.0);
 
     /**
      * Two points in a three-dimensional coordinate reference system, at the same horizontal
      * position but at different heights.
      */
     private static final SampleSystem CRS3D = SampleSystem.of(CommonCRS.WGS84.geographic3D());
-    private static final Point POINT_3D_LOW  = GeometryFactory.createPoint(CRS3D, 10.0, 5.0,   0.0);
-    private static final Point POINT_3D_HIGH = GeometryFactory.createPoint(CRS3D, 10.0, 5.0, 100.0);
+    private static final Point POINT_3D_LOW  = GeometryFactory.DEFAULT.createPoint(CRS3D, 10.0, 5.0,   0.0);
+    private static final Point POINT_3D_HIGH = GeometryFactory.DEFAULT.createPoint(CRS3D, 10.0, 5.0, 100.0);
 
     /**
      * Two points using coordinate reference systems which differ by their axis order.
      */
-    private static final Point POINT_GEOGRAPHIC = GeometryFactory.createPoint(CommonCRS.WGS84.geographic());
-    private static final Point POINT_NORMALIZED = GeometryFactory.createPoint(CommonCRS.WGS84.normalizedGeographic());
+    private static final Point POINT_GEOGRAPHIC = GeometryFactory.DEFAULT.createPoint(CommonCRS.WGS84.geographic());
+    private static final Point POINT_NORMALIZED = GeometryFactory.DEFAULT.createPoint(CommonCRS.WGS84.normalizedGeographic());
 
     /**
      * The distance from an empty geometry to any geometry, including itself, is infinite.
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/To3DTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/To3DTest.java
index fbbd2e39eb..f873ceb5fd 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/To3DTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/To3DTest.java
@@ -52,7 +52,7 @@ public class To3DTest {
 
     @Test
     public void testPoint() {
-        final Point point = GeometryFactory.createPoint(CRS2D, 10.0, 5.0);
+        final Point point = GeometryFactory.DEFAULT.createPoint(CRS2D, 10.0, 5.0);
         final Geometry result = new GeometryProcessor().to3D(point, CRS2DZ, (Tuple t) -> t.set(2, 15));
         assertInstanceOf(Point.class, result);
         assertEquals(CRS2DZ, result.getCoordinateReferenceSystem());
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/ToPrimitiveTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/ToPrimitiveTest.java
index f342395ceb..9bf978e286 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/ToPrimitiveTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/ToPrimitiveTest.java
@@ -48,7 +48,7 @@ public class ToPrimitiveTest {
 
     @Test
     public void testPoint() {
-        final Point point = GeometryFactory.createPoint(CRS2D, 1, 2);
+        final Point point = GeometryFactory.DEFAULT.createPoint(CRS2D, 1, 2);
         final Geometry result = new GeometryProcessor().toPrimitive(point);
         assertTrue(result instanceof MeshPrimitive);
         final MeshPrimitive primitive = (MeshPrimitive) result;
@@ -58,8 +58,8 @@ public class ToPrimitiveTest {
     @Test
     public void testLineString() {
         final Array positions = NDArrays.of(CRS2D, new double[]{0,1,2,3});
-        final DataPoints points = GeometryFactory.createSequence(positions);
-        final LineString line = GeometryFactory.createLineString(points);
+        final DataPoints points = GeometryFactory.DEFAULT.createDataPoints(positions);
+        final LineString line = GeometryFactory.DEFAULT.createLineString(points);
         final Geometry result = new GeometryProcessor().toPrimitive(line);
         assertTrue(result instanceof MeshPrimitive);
         final MeshPrimitive primitive = (MeshPrimitive) result;
@@ -69,9 +69,9 @@ public class ToPrimitiveTest {
     @Test
     public void testPolygon() {
         final Array positions = NDArrays.of(CRS2D, new double[]{0,1,2,3});
-        final DataPoints points = GeometryFactory.createSequence(positions);
-        final LinearRing exterior = GeometryFactory.createLinearRing(points);
-        final Polygon point = GeometryFactory.createPolygon(exterior, null);
+        final DataPoints points = GeometryFactory.DEFAULT.createDataPoints(positions);
+        final LinearRing exterior = GeometryFactory.DEFAULT.createLinearRing(points);
+        final Polygon point = GeometryFactory.DEFAULT.createPolygon(exterior, null);
         final Geometry result = new GeometryProcessor().toPrimitive(point);
         assertTrue(result instanceof MeshPrimitive);
         final MeshPrimitive primitive = (MeshPrimitive) result;
@@ -82,14 +82,14 @@ public class ToPrimitiveTest {
     public void testMultiLineString() {
         { //one line has 3 points, so we must obtain a MultiPrimitive
             final Array positions1 = NDArrays.of(CRS2D, new double[]{0,1,2,3});
-            final DataPoints points1 = GeometryFactory.createSequence(positions1);
-            final LineString line1 = GeometryFactory.createLineString(points1);
+            final DataPoints points1 = GeometryFactory.DEFAULT.createDataPoints(positions1);
+            final LineString line1 = GeometryFactory.DEFAULT.createLineString(points1);
 
             final Array positions2 = NDArrays.of(CRS2D, new double[]{3,4,5,6,7,8});
-            final DataPoints points2 = GeometryFactory.createSequence(positions2);
-            final LineString line2 = GeometryFactory.createLineString(points2);
+            final DataPoints points2 = GeometryFactory.DEFAULT.createDataPoints(positions2);
+            final LineString line2 = GeometryFactory.DEFAULT.createLineString(points2);
 
-            final MultiLineString mlines = GeometryFactory.createMultiLineString(line1, line2);
+            final MultiLineString mlines = GeometryFactory.DEFAULT.createMultiLineString(line1, line2);
 
             final Geometry result = new GeometryProcessor().toPrimitive(mlines);
             assertTrue(result instanceof MultiMeshPrimitive);
@@ -106,14 +106,14 @@ public class ToPrimitiveTest {
         }
         { //all linestrings are lines, we must obtain a Primitive.Lines
             final Array positions1 = NDArrays.of(CRS2D, new double[]{0,1,2,3});
-            final DataPoints points1 = GeometryFactory.createSequence(positions1);
-            final LineString line1 = GeometryFactory.createLineString(points1);
+            final DataPoints points1 = GeometryFactory.DEFAULT.createDataPoints(positions1);
+            final LineString line1 = GeometryFactory.DEFAULT.createLineString(points1);
 
             final Array positions2 = NDArrays.of(CRS2D, new double[]{3,4,5,6});
-            final DataPoints points2 = GeometryFactory.createSequence(positions2);
-            final LineString line2 = GeometryFactory.createLineString(points2);
+            final DataPoints points2 = GeometryFactory.DEFAULT.createDataPoints(positions2);
+            final LineString line2 = GeometryFactory.DEFAULT.createLineString(points2);
 
-            final MultiLineString mlines = GeometryFactory.createMultiLineString(line1, line2);
+            final MultiLineString mlines = GeometryFactory.DEFAULT.createMultiLineString(line1, line2);
 
             final Geometry result = new GeometryProcessor().toPrimitive(mlines);
             assertTrue(result instanceof MeshPrimitive.Lines);
@@ -129,8 +129,8 @@ public class ToPrimitiveTest {
     @Test
     public void testMultiPoint() {
         final Array positions1 = NDArrays.of(CRS2D, new double[]{0,1,2,3});
-        final DataPoints points = GeometryFactory.createSequence(positions1);
-        final MultiPoint mpoints = GeometryFactory.createMultiPoint(points);
+        final DataPoints points = GeometryFactory.DEFAULT.createDataPoints(positions1);
+        final MultiPoint mpoints = GeometryFactory.DEFAULT.createMultiPoint(points);
 
         final Geometry result = new GeometryProcessor().toPrimitive(mpoints);
         assertTrue(result instanceof MeshPrimitive);
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/surface/TriangleTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/surface/TriangleTest.java
index 1dd505c2c7..71cf51e844 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/surface/TriangleTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/surface/TriangleTest.java
@@ -98,9 +98,9 @@ public class TriangleTest extends GeometryTest {
     public void constructorTest() {
 
         final Array positions = NDArrays.of(CommonCRS.WGS84.normalizedGeographic(), new double[]{0,0, 1,0, 0,1, 0,0});
-        final DataPoints points = GeometryFactory.createSequence(positions);
-        final LinearRing exterior = GeometryFactory.createLinearRing(points);
-        final Triangle triangle = GeometryFactory.createTriangle(exterior);
+        final DataPoints points = GeometryFactory.DEFAULT.createDataPoints(positions);
+        final LinearRing exterior = GeometryFactory.DEFAULT.createLinearRing(points);
+        final Triangle triangle = GeometryFactory.DEFAULT.createTriangle(exterior);
 
         assertNotNull(triangle.getExteriorRing());
         assertTrue(triangle.getInteriorRings().isEmpty());
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML2ReaderTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML2ReaderTest.java
index 348ac51dd4..dc1144a248 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML2ReaderTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML2ReaderTest.java
@@ -91,14 +91,14 @@ public final class GML2ReaderTest {
      * Creates a point sequence in the {@link #wgs84} CRS from a flat list of ordinates.
      */
     private DataPoints sequence(final double... ordinates) {
-        return GeometryFactory.createSequence(NDArrays.of(SampleSystem.of(wgs84), ordinates));
+        return GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(SampleSystem.of(wgs84), ordinates));
     }
 
     /**
      * Creates a closed rectangular ring in the {@link #wgs84} CRS.
      */
     private LinearRing ring(final double minX, final double minY, final double maxX, final double maxY) {
-        return GeometryFactory.createLinearRing(sequence(
+        return GeometryFactory.DEFAULT.createLinearRing(sequence(
                 minX, minY,
                 maxX, minY,
                 maxX, maxY,
@@ -113,7 +113,7 @@ public final class GML2ReaderTest {
     public void testPoint() throws Exception {
         final Geometry g = read(TestData.POINT);
         assertInstanceOf(Point.class, g);
-        assertGeometryEquals(GeometryFactory.createPoint(sequence(10.0, 20.0)), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createPoint(sequence(10.0, 20.0)), g);
         assertCRS(wgs84, g);
     }
 
@@ -124,7 +124,7 @@ public final class GML2ReaderTest {
     public void testPointCoordForm() throws Exception {
         final Geometry g = read(TestData.POINT_COORD);
         assertInstanceOf(Point.class, g);
-        assertGeometryEquals(GeometryFactory.createPoint(sequence(10.0, 20.0)), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createPoint(sequence(10.0, 20.0)), g);
         assertCRS(wgs84, g);
     }
 
@@ -135,7 +135,7 @@ public final class GML2ReaderTest {
     public void testLineString() throws Exception {
         final Geometry g = read(TestData.LINE_STRING);
         assertInstanceOf(LineString.class, g);
-        assertGeometryEquals(GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0)), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0)), g);
         assertCRS(wgs84, g);
     }
 
@@ -146,7 +146,7 @@ public final class GML2ReaderTest {
     public void testLineStringCoordForm() throws Exception {
         final Geometry g = read(TestData.LINE_STRING_COORD);
         assertInstanceOf(LineString.class, g);
-        assertGeometryEquals(GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0)), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0)), g);
         assertCRS(wgs84, g);
     }
 
@@ -168,7 +168,7 @@ public final class GML2ReaderTest {
     public void testPolygon() throws Exception {
         final Geometry g = read(TestData.POLYGON);
         assertInstanceOf(Polygon.class, g);
-        assertGeometryEquals(GeometryFactory.createPolygon(ring(0, 0, 10, 10), List.of(ring(2, 2, 4, 4))), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), List.of(ring(2, 2, 4, 4))), g);
         assertCRS(wgs84, g);
     }
 
@@ -194,9 +194,9 @@ public final class GML2ReaderTest {
     public void testMultiPoint() throws Exception {
         final Geometry g = read(TestData.MULTI_POINT);
         assertInstanceOf(MultiPoint.class, g);
-        assertGeometryEquals(GeometryFactory.createMultiPoint(
-                GeometryFactory.createPoint(sequence(0.0, 0.0)),
-                GeometryFactory.createPoint(sequence(10.0, 10.0))), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createMultiPoint(
+                GeometryFactory.DEFAULT.createPoint(sequence(0.0, 0.0)),
+                GeometryFactory.DEFAULT.createPoint(sequence(10.0, 10.0))), g);
         assertCRS(wgs84, g);
     }
 
@@ -207,9 +207,9 @@ public final class GML2ReaderTest {
     public void testMultiLineString() throws Exception {
         final Geometry g = read(TestData.MULTI_LINE_STRING);
         assertInstanceOf(MultiLineString.class, g);
-        assertGeometryEquals(GeometryFactory.createMultiLineString(
-                GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0)),
-                GeometryFactory.createLineString(sequence(20.0, 20.0, 30.0, 30.0, 40.0, 20.0))), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createMultiLineString(
+                GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0)),
+                GeometryFactory.DEFAULT.createLineString(sequence(20.0, 20.0, 30.0, 30.0, 40.0, 20.0))), g);
         assertCRS(wgs84, g);
     }
 
@@ -220,9 +220,9 @@ public final class GML2ReaderTest {
     public void testMultiPolygon() throws Exception {
         final Geometry g = read(TestData.MULTI_POLYGON);
         assertInstanceOf(MultiPolygon.class, g);
-        assertGeometryEquals(GeometryFactory.createMultiPolygon(
-                GeometryFactory.createPolygon(ring(0, 0, 10, 10), null),
-                GeometryFactory.createPolygon(ring(20, 20, 30, 30), null)), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createMultiPolygon(
+                GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), null),
+                GeometryFactory.DEFAULT.createPolygon(ring(20, 20, 30, 30), null)), g);
         assertCRS(wgs84, g);
     }
 
@@ -233,9 +233,9 @@ public final class GML2ReaderTest {
     public void testMultiGeometry() throws Exception {
         final Geometry g = read(TestData.MULTI_GEOMETRY);
         assertInstanceOf(GeometryCollection.class, g);
-        assertGeometryEquals(GeometryFactory.createGeometryCollection(
-                GeometryFactory.createPoint(sequence(0.0, 0.0)),
-                GeometryFactory.createLineString(sequence(10.0, 10.0, 20.0, 20.0))), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createGeometryCollection(
+                GeometryFactory.DEFAULT.createPoint(sequence(0.0, 0.0)),
+                GeometryFactory.DEFAULT.createLineString(sequence(10.0, 10.0, 20.0, 20.0))), g);
         assertCRS(wgs84, g);
     }
 
@@ -247,7 +247,7 @@ public final class GML2ReaderTest {
     public void testMissingNamespace() throws Exception {
         final Geometry g = read(TestData.NO_NAMESPACE);
         assertInstanceOf(Point.class, g);
-        assertGeometryEquals(GeometryFactory.createPoint(sequence(10.0, 20.0)), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createPoint(sequence(10.0, 20.0)), g);
         assertCRS(wgs84, g);
     }
 
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML2WriterTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML2WriterTest.java
index eea274ad3f..06d136a968 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML2WriterTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML2WriterTest.java
@@ -69,14 +69,14 @@ public final class GML2WriterTest extends TestCase {
      * Creates a point sequence in the {@link #wgs84} CRS from a flat list of ordinates.
      */
     private DataPoints sequence(final double... ordinates) {
-        return GeometryFactory.createSequence(NDArrays.of(SampleSystem.of(wgs84), ordinates));
+        return GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(SampleSystem.of(wgs84), ordinates));
     }
 
     /**
      * Creates a closed rectangular ring in the {@link #wgs84} CRS.
      */
     private LinearRing ring(final double minX, final double minY, final double maxX, final double maxY) {
-        return GeometryFactory.createLinearRing(sequence(
+        return GeometryFactory.DEFAULT.createLinearRing(sequence(
                 minX, minY,
                 maxX, minY,
                 maxX, maxY,
@@ -89,7 +89,7 @@ public final class GML2WriterTest extends TestCase {
      */
     @Test
     public void testPoint() throws Exception {
-        final Point g = GeometryFactory.createPoint(sequence(10.0, 20.0));
+        final Point g = GeometryFactory.DEFAULT.createPoint(sequence(10.0, 20.0));
         assertXmlEquals(TestData.V2.openStream(TestData.POINT), write(g), "xmlns:*");
     }
 
@@ -98,7 +98,7 @@ public final class GML2WriterTest extends TestCase {
      */
     @Test
     public void testLineString() throws Exception {
-        final Geometry g = GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0));
+        final Geometry g = GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0));
         assertXmlEquals(TestData.V2.openStream(TestData.LINE_STRING), write(g), "xmlns:*");
     }
 
@@ -116,7 +116,7 @@ public final class GML2WriterTest extends TestCase {
      */
     @Test
     public void testPolygon() throws Exception {
-        final Geometry g = GeometryFactory.createPolygon(ring(0, 0, 10, 10), List.of(ring(2, 2, 4, 4)));
+        final Geometry g = GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), List.of(ring(2, 2, 4, 4)));
         assertXmlEquals(TestData.V2.openStream(TestData.POLYGON), write(g), "xmlns:*");
     }
 
@@ -125,9 +125,9 @@ public final class GML2WriterTest extends TestCase {
      */
     @Test
     public void testMultiPoint() throws Exception {
-        final Geometry g = GeometryFactory.createMultiPoint(
-                GeometryFactory.createPoint(sequence(0.0, 0.0)),
-                GeometryFactory.createPoint(sequence(10.0, 10.0)));
+        final Geometry g = GeometryFactory.DEFAULT.createMultiPoint(
+                GeometryFactory.DEFAULT.createPoint(sequence(0.0, 0.0)),
+                GeometryFactory.DEFAULT.createPoint(sequence(10.0, 10.0)));
         assertXmlEquals(TestData.V2.openStream(TestData.MULTI_POINT), write(g), "xmlns:*");
     }
 
@@ -136,9 +136,9 @@ public final class GML2WriterTest extends TestCase {
      */
     @Test
     public void testMultiLineString() throws Exception {
-        final Geometry g = GeometryFactory.createMultiLineString(
-                GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0)),
-                GeometryFactory.createLineString(sequence(20.0, 20.0, 30.0, 30.0, 40.0, 20.0)));
+        final Geometry g = GeometryFactory.DEFAULT.createMultiLineString(
+                GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0)),
+                GeometryFactory.DEFAULT.createLineString(sequence(20.0, 20.0, 30.0, 30.0, 40.0, 20.0)));
         assertXmlEquals(TestData.V2.openStream(TestData.MULTI_LINE_STRING), write(g), "xmlns:*");
     }
 
@@ -147,9 +147,9 @@ public final class GML2WriterTest extends TestCase {
      */
     @Test
     public void testMultiPolygon() throws Exception {
-        final Geometry g = GeometryFactory.createMultiPolygon(
-                GeometryFactory.createPolygon(ring(0, 0, 10, 10), null),
-                GeometryFactory.createPolygon(ring(20, 20, 30, 30), null));
+        final Geometry g = GeometryFactory.DEFAULT.createMultiPolygon(
+                GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), null),
+                GeometryFactory.DEFAULT.createPolygon(ring(20, 20, 30, 30), null));
         assertXmlEquals(TestData.V2.openStream(TestData.MULTI_POLYGON), write(g), "xmlns:*");
     }
 
@@ -158,9 +158,9 @@ public final class GML2WriterTest extends TestCase {
      */
     @Test
     public void testMultiGeometry() throws Exception {
-        final Geometry g = GeometryFactory.createGeometryCollection(
-                GeometryFactory.createPoint(sequence(0.0, 0.0)),
-                GeometryFactory.createLineString(sequence(10.0, 10.0, 20.0, 20.0)));
+        final Geometry g = GeometryFactory.DEFAULT.createGeometryCollection(
+                GeometryFactory.DEFAULT.createPoint(sequence(0.0, 0.0)),
+                GeometryFactory.DEFAULT.createLineString(sequence(10.0, 10.0, 20.0, 20.0)));
         assertXmlEquals(TestData.V2.openStream(TestData.MULTI_GEOMETRY), write(g), "xmlns:*");
     }
 
@@ -179,8 +179,8 @@ public final class GML2WriterTest extends TestCase {
      */
     @Test
     public void testExplicitCRS() throws Exception {
-        final Point g = GeometryFactory.createPoint(
-                GeometryFactory.createSequence(NDArrays.of(
+        final Point g = GeometryFactory.DEFAULT.createPoint(
+                GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(
                         SampleSystem.of(Geometries.getUndefinedCRS(2)), 10.0, 20.0)));
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
         try (GML2Writer writer = new GML2Writer(out)) {
@@ -195,8 +195,8 @@ public final class GML2WriterTest extends TestCase {
      */
     @Test
     public void testUndefinedCRSOmitsSrsName() throws Exception {
-        final Point g = GeometryFactory.createPoint(
-                GeometryFactory.createSequence(NDArrays.of(
+        final Point g = GeometryFactory.DEFAULT.createPoint(
+                GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(
                         SampleSystem.of(Geometries.getUndefinedCRS(2)), 10.0, 20.0)));
         assertFalse(write(g).contains(GML2Tags.SRS_NAME), "srsName should be omitted for an undefined CRS.");
     }
@@ -208,7 +208,7 @@ public final class GML2WriterTest extends TestCase {
     @Test
     public void testThreeDimensionalCoordinates() throws Exception {
         final CoordinateReferenceSystem crs3D = CRS.forCode("EPSG:4979");
-        final Geometry g = GeometryFactory.createLineString(GeometryFactory.createSequence(
+        final Geometry g = GeometryFactory.DEFAULT.createLineString(GeometryFactory.DEFAULT.createDataPoints(
                 NDArrays.of(SampleSystem.of(crs3D), 0.0, 0.0, 1.0, 10.0, 10.0, 2.0)));
         final String xml = write(g);
         assertTrue(xml.contains("0.0,0.0,1.0 10.0,10.0,2.0"), () -> "Expected all three ordinates in: " + xml);
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML3ReaderTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML3ReaderTest.java
index 5753c89b4a..20dd4e646b 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML3ReaderTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML3ReaderTest.java
@@ -105,14 +105,14 @@ public final class GML3ReaderTest {
      * Creates a point sequence in the {@link #wgs84} CRS from a flat list of ordinates.
      */
     private DataPoints sequence(final double... ordinates) {
-        return GeometryFactory.createSequence(NDArrays.of(SampleSystem.of(wgs84), ordinates));
+        return GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(SampleSystem.of(wgs84), ordinates));
     }
 
     /**
      * Creates a closed rectangular ring in the {@link #wgs84} CRS.
      */
     private LinearRing ring(final double minX, final double minY, final double maxX, final double maxY) {
-        return GeometryFactory.createLinearRing(sequence(
+        return GeometryFactory.DEFAULT.createLinearRing(sequence(
                 minX, minY,
                 maxX, minY,
                 maxX, maxY,
@@ -127,7 +127,7 @@ public final class GML3ReaderTest {
     public void testPoint() throws Exception {
         final Geometry g = read(TestData.V3, TestData.POINT);
         assertInstanceOf(Point.class, g);
-        assertGeometryEquals(GeometryFactory.createPoint(sequence(10.0, 20.0)), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createPoint(sequence(10.0, 20.0)), g);
         assertCRS(wgs84, g);
     }
 
@@ -138,7 +138,7 @@ public final class GML3ReaderTest {
     public void testLineStringPosList() throws Exception {
         final Geometry g = read(TestData.V3, TestData.LINE_STRING_POSLIST);
         assertInstanceOf(LineString.class, g);
-        assertGeometryEquals(GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0)), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0)), g);
         assertCRS(wgs84, g);
     }
 
@@ -160,7 +160,7 @@ public final class GML3ReaderTest {
     public void testPolygonExteriorInterior() throws Exception {
         final Geometry g = read(TestData.V3, TestData.POLYGON_EXTERIOR);
         assertInstanceOf(Polygon.class, g);
-        assertGeometryEquals(GeometryFactory.createPolygon(ring(0, 0, 10, 10), List.of(ring(2, 2, 4, 4))), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), List.of(ring(2, 2, 4, 4))), g);
         assertCRS(wgs84, g);
     }
 
@@ -187,9 +187,9 @@ public final class GML3ReaderTest {
     }
 
     private MultiPoint<?> expectedMultiPoint() {
-        return GeometryFactory.createMultiPoint(
-                GeometryFactory.createPoint(sequence(0.0, 0.0)),
-                GeometryFactory.createPoint(sequence(10.0, 10.0)));
+        return GeometryFactory.DEFAULT.createMultiPoint(
+                GeometryFactory.DEFAULT.createPoint(sequence(0.0, 0.0)),
+                GeometryFactory.DEFAULT.createPoint(sequence(10.0, 10.0)));
     }
 
     /**
@@ -201,9 +201,9 @@ public final class GML3ReaderTest {
     public void testMultiCurve() throws Exception {
         final Geometry g = read(TestData.V3, TestData.MULTI_CURVE);
         assertInstanceOf(MultiLineString.class, g);
-        assertGeometryEquals(GeometryFactory.createMultiLineString(
-                GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0)),
-                GeometryFactory.createLineString(sequence(20.0, 20.0, 30.0, 30.0, 40.0, 20.0))), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createMultiLineString(
+                GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0)),
+                GeometryFactory.DEFAULT.createLineString(sequence(20.0, 20.0, 30.0, 30.0, 40.0, 20.0))), g);
         assertCRS(wgs84, g);
     }
 
@@ -216,9 +216,9 @@ public final class GML3ReaderTest {
     public void testMultiSurface() throws Exception {
         final Geometry g = read(TestData.V3, TestData.MULTI_SURFACE);
         assertInstanceOf(MultiPolygon.class, g);
-        assertGeometryEquals(GeometryFactory.createMultiPolygon(
-                GeometryFactory.createPolygon(ring(0, 0, 10, 10), null),
-                GeometryFactory.createPolygon(ring(20, 20, 30, 30), null)), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createMultiPolygon(
+                GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), null),
+                GeometryFactory.DEFAULT.createPolygon(ring(20, 20, 30, 30), null)), g);
         assertCRS(wgs84, g);
     }
 
@@ -229,9 +229,9 @@ public final class GML3ReaderTest {
     public void testMultiGeometry() throws Exception {
         final Geometry g = read(TestData.V3, TestData.MULTI_GEOMETRY);
         assertInstanceOf(GeometryCollection.class, g);
-        assertGeometryEquals(GeometryFactory.createGeometryCollection(
-                GeometryFactory.createPoint(sequence(0.0, 0.0)),
-                GeometryFactory.createLineString(sequence(10.0, 10.0, 20.0, 20.0))), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createGeometryCollection(
+                GeometryFactory.DEFAULT.createPoint(sequence(0.0, 0.0)),
+                GeometryFactory.DEFAULT.createLineString(sequence(10.0, 10.0, 20.0, 20.0))), g);
         assertCRS(wgs84, g);
     }
 
@@ -261,7 +261,7 @@ public final class GML3ReaderTest {
     public void testToleranceNewStyleUnderOldNamespace() throws Exception {
         final Geometry g = read(TestData.V3, TestData.TOLERANCE_NEW_STYLE_OLD_NAMESPACE);
         assertInstanceOf(LineString.class, g);
-        assertGeometryEquals(GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0)), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0)), g);
         assertCRS(wgs84, g);
     }
 
@@ -273,7 +273,7 @@ public final class GML3ReaderTest {
     public void testToleranceLegacyStyleUnderNewNamespace() throws Exception {
         final Geometry g = read(TestData.V3, TestData.TOLERANCE_LEGACY_STYLE_NEW_NAMESPACE);
         assertInstanceOf(Polygon.class, g);
-        assertGeometryEquals(GeometryFactory.createPolygon(ring(0, 0, 10, 10), null), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), null), g);
         assertCRS(wgs84, g);
     }
 
@@ -407,7 +407,7 @@ public final class GML3ReaderTest {
     public void testCurve() throws Exception {
         final Geometry g = read(TestData.V3, TestData.CURVE);
         assertInstanceOf(LineString.class, g);
-        assertGeometryEquals(GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0)), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0)), g);
         assertCRS(wgs84, g);
     }
 
@@ -580,7 +580,7 @@ public final class GML3ReaderTest {
     public void testSurface() throws Exception {
         final Geometry g = read(TestData.V3, TestData.SURFACE);
         assertInstanceOf(Polygon.class, g);
-        assertGeometryEquals(GeometryFactory.createPolygon(ring(0, 0, 10, 10), null), g);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), null), g);
         assertCRS(wgs84, g);
     }
 
@@ -669,7 +669,7 @@ public final class GML3ReaderTest {
         final Geometry g = read(TestData.V3, TestData.COMPOSITE_CURVE);
         final CompoundCurve c = assertInstanceOf(CompoundCurve.class, g);
         assertEquals(1, c.getNumCurves());
-        assertGeometryEquals(GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0)), c.getCurveN(0));
+        assertGeometryEquals(GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0)), c.getCurveN(0));
         assertCRS(wgs84, g);
     }
 
@@ -684,7 +684,7 @@ public final class GML3ReaderTest {
         final Geometry g = read(TestData.V3, TestData.COMPOSITE_SURFACE);
         final PolyhedralSurface<?> s = assertInstanceOf(PolyhedralSurface.class, g);
         assertEquals(1, s.getNumPatches());
-        assertGeometryEquals(GeometryFactory.createPolygon(ring(0, 0, 10, 10), null), s.getPatchN(0));
+        assertGeometryEquals(GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), null), s.getPatchN(0));
         assertCRS(wgs84, g);
     }
 
@@ -698,7 +698,7 @@ public final class GML3ReaderTest {
         final Curve c = assertInstanceOf(Curve.class, g);
         assertEquals(Orientable.Sign.NEGATIVE, c.getOrientationSign());
         final Geometry base = assertInstanceOf(LineString.class, c.getPrimitive());
-        assertGeometryEquals(GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0)), base);
+        assertGeometryEquals(GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0)), base);
         assertCRS(wgs84, g);
     }
 
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML3WriterTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML3WriterTest.java
index e238ee863a..6194d4995d 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML3WriterTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GML3WriterTest.java
@@ -74,14 +74,14 @@ public final class GML3WriterTest extends TestCase {
      * Creates a point sequence in the {@link #wgs84} CRS from a flat list of ordinates.
      */
     private DataPoints sequence(final double... ordinates) {
-        return GeometryFactory.createSequence(NDArrays.of(SampleSystem.of(wgs84), ordinates));
+        return GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(SampleSystem.of(wgs84), ordinates));
     }
 
     /**
      * Creates a closed rectangular ring in the {@link #wgs84} CRS.
      */
     private LinearRing ring(final double minX, final double minY, final double maxX, final double maxY) {
-        return GeometryFactory.createLinearRing(sequence(
+        return GeometryFactory.DEFAULT.createLinearRing(sequence(
                 minX, minY,
                 maxX, minY,
                 maxX, maxY,
@@ -94,7 +94,7 @@ public final class GML3WriterTest extends TestCase {
      */
     @Test
     public void testPoint() throws Exception {
-        final Point g = GeometryFactory.createPoint(sequence(10.0, 20.0));
+        final Point g = GeometryFactory.DEFAULT.createPoint(sequence(10.0, 20.0));
         assertXmlEquals(TestData.V3.openStream(TestData.POINT), write(g), "xmlns:*");
     }
 
@@ -103,7 +103,7 @@ public final class GML3WriterTest extends TestCase {
      */
     @Test
     public void testLineString() throws Exception {
-        final Geometry g = GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0));
+        final Geometry g = GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0, 20.0, 0.0));
         assertXmlEquals(TestData.V3.openStream(TestData.LINE_STRING_POSLIST), write(g), "xmlns:*");
     }
 
@@ -120,7 +120,7 @@ public final class GML3WriterTest extends TestCase {
      */
     @Test
     public void testPolygon() throws Exception {
-        final Geometry g = GeometryFactory.createPolygon(ring(0, 0, 10, 10), List.of(ring(2, 2, 4, 4)));
+        final Geometry g = GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), List.of(ring(2, 2, 4, 4)));
         assertXmlEquals(TestData.V3.openStream(TestData.POLYGON_EXTERIOR), write(g), "xmlns:*");
     }
 
@@ -129,9 +129,9 @@ public final class GML3WriterTest extends TestCase {
      */
     @Test
     public void testMultiPoint() throws Exception {
-        final Geometry g = GeometryFactory.createMultiPoint(
-                GeometryFactory.createPoint(sequence(0.0, 0.0)),
-                GeometryFactory.createPoint(sequence(10.0, 10.0)));
+        final Geometry g = GeometryFactory.DEFAULT.createMultiPoint(
+                GeometryFactory.DEFAULT.createPoint(sequence(0.0, 0.0)),
+                GeometryFactory.DEFAULT.createPoint(sequence(10.0, 10.0)));
         assertXmlEquals(TestData.V3.openStream(TestData.MULTI_POINT), write(g), "xmlns:*");
     }
 
@@ -141,9 +141,9 @@ public final class GML3WriterTest extends TestCase {
      */
     @Test
     public void testMultiCurve() throws Exception {
-        final Geometry g = GeometryFactory.createMultiLineString(
-                GeometryFactory.createLineString(sequence(0.0, 0.0, 10.0, 10.0)),
-                GeometryFactory.createLineString(sequence(20.0, 20.0, 30.0, 30.0, 40.0, 20.0)));
+        final Geometry g = GeometryFactory.DEFAULT.createMultiLineString(
+                GeometryFactory.DEFAULT.createLineString(sequence(0.0, 0.0, 10.0, 10.0)),
+                GeometryFactory.DEFAULT.createLineString(sequence(20.0, 20.0, 30.0, 30.0, 40.0, 20.0)));
         assertXmlEquals(TestData.V3.openStream(TestData.MULTI_CURVE), write(g), "xmlns:*");
     }
 
@@ -153,9 +153,9 @@ public final class GML3WriterTest extends TestCase {
      */
     @Test
     public void testMultiSurface() throws Exception {
-        final Geometry g = GeometryFactory.createMultiPolygon(
-                GeometryFactory.createPolygon(ring(0, 0, 10, 10), null),
-                GeometryFactory.createPolygon(ring(20, 20, 30, 30), null));
+        final Geometry g = GeometryFactory.DEFAULT.createMultiPolygon(
+                GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), null),
+                GeometryFactory.DEFAULT.createPolygon(ring(20, 20, 30, 30), null));
         assertXmlEquals(TestData.V3.openStream(TestData.MULTI_SURFACE), write(g), "xmlns:*");
     }
 
@@ -164,9 +164,9 @@ public final class GML3WriterTest extends TestCase {
      */
     @Test
     public void testMultiGeometry() throws Exception {
-        final Geometry g = GeometryFactory.createGeometryCollection(
-                GeometryFactory.createPoint(sequence(0.0, 0.0)),
-                GeometryFactory.createLineString(sequence(10.0, 10.0, 20.0, 20.0)));
+        final Geometry g = GeometryFactory.DEFAULT.createGeometryCollection(
+                GeometryFactory.DEFAULT.createPoint(sequence(0.0, 0.0)),
+                GeometryFactory.DEFAULT.createLineString(sequence(10.0, 10.0, 20.0, 20.0)));
         assertXmlEquals(TestData.V3.openStream(TestData.MULTI_GEOMETRY), write(g), "xmlns:*");
     }
 
@@ -187,8 +187,8 @@ public final class GML3WriterTest extends TestCase {
     @Test
     public void testExplicitCRS() throws Exception {
         // Built with the placeholder CRS, so that writing it without an explicit CRS emits no srsName.
-        final Point g = GeometryFactory.createPoint(
-                GeometryFactory.createSequence(NDArrays.of(
+        final Point g = GeometryFactory.DEFAULT.createPoint(
+                GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(
                         SampleSystem.of(Geometries.getUndefinedCRS(2)), 10.0, 20.0)));
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
         try (GML3Writer writer = new GML3Writer(out)) {
@@ -203,8 +203,8 @@ public final class GML3WriterTest extends TestCase {
      */
     @Test
     public void testUndefinedCRSOmitsSrsName() throws Exception {
-        final Point g = GeometryFactory.createPoint(
-                GeometryFactory.createSequence(NDArrays.of(
+        final Point g = GeometryFactory.DEFAULT.createPoint(
+                GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(
                         SampleSystem.of(Geometries.getUndefinedCRS(2)), 10.0, 20.0)));
         assertFalse(write(g).contains(GML2Tags.SRS_NAME), "srsName should be omitted for an undefined CRS.");
     }
@@ -216,7 +216,7 @@ public final class GML3WriterTest extends TestCase {
     @Test
     public void testThreeDimensionalPosList() throws Exception {
         final CoordinateReferenceSystem crs3D = CRS.forCode("EPSG:4979");
-        final Geometry g = GeometryFactory.createLineString(GeometryFactory.createSequence(
+        final Geometry g = GeometryFactory.DEFAULT.createLineString(GeometryFactory.DEFAULT.createDataPoints(
                 NDArrays.of(SampleSystem.of(crs3D), 0.0, 0.0, 1.0, 10.0, 10.0, 2.0)));
         final String xml = write(g);
         assertTrue(xml.contains("srsDimension=\"3\""), () -> "Expected srsDimension=\"3\" in: " + xml);
@@ -284,8 +284,8 @@ public final class GML3WriterTest extends TestCase {
      */
     @Test
     public void testArcByCenterPointWithoutRadiusUnit() throws Exception {
-        final Geometry g = GeometryFactory.createArcByCenterPoint(
-                GeometryFactory.createPoint(sequence(10.0, 20.0)), 5.0, null,0.0, 90.0);
+        final Geometry g = GeometryFactory.DEFAULT.createArcByCenterPoint(
+                GeometryFactory.DEFAULT.createPoint(sequence(10.0, 20.0)), 5.0, null,0.0, 90.0);
         final String xml = write(g);
         assertTrue(xml.contains("ArcByCenterPoint"), () -> "Expected a gml:ArcByCenterPoint in: " + xml);
         assertTrue(xml.contains("<gml:radius>5.0</gml:radius>")
@@ -302,7 +302,7 @@ public final class GML3WriterTest extends TestCase {
     public void testArcByBulge() throws Exception {
         final Vector<?> normal = Vectors.createDouble(2);
         normal.set(new double[] {0, 1});
-        final Geometry g = GeometryFactory.createArcByBulge(sequence(0.0, 0.0, 10.0, 0.0), 2.0, normal);
+        final Geometry g = GeometryFactory.DEFAULT.createArcByBulge(sequence(0.0, 0.0, 10.0, 0.0), 2.0, normal);
         final String xml = write(g);
         assertTrue(xml.contains("ArcByBulge"), () -> "Expected a gml:ArcByBulge in: " + xml);
         assertTrue(xml.contains("0.0 0.0 10.0 0.0"), () -> "Expected the two end points in: " + xml);
@@ -402,8 +402,8 @@ public final class GML3WriterTest extends TestCase {
      */
     @Test
     public void testCurvePolygon() throws Exception {
-        final Geometry arc = GeometryFactory.createCircularString(sequence(0, 0, 5, 5, 10, 0, 5, -5, 0, 0));
-        final Geometry g = GeometryFactory.createCurvePolygon((Curve) arc, null);
+        final Geometry arc = GeometryFactory.DEFAULT.createCircularString(sequence(0, 0, 5, 5, 10, 0, 5, -5, 0, 0));
+        final Geometry g = GeometryFactory.DEFAULT.createCurvePolygon((Curve) arc, null);
         final String xml = write(g);
         assertTrue(xml.contains("Ring"), () -> "Expected a gml:Ring boundary in: " + xml);
         assertTrue(xml.contains("ArcString"), () -> "Expected the arc to be preserved in: " + xml);
@@ -416,9 +416,9 @@ public final class GML3WriterTest extends TestCase {
      */
     @Test
     public void testPolyhedralSurface() throws Exception {
-        final Geometry g = GeometryFactory.createPolyhedralSurface(
-                GeometryFactory.createPolygon(ring(0, 0, 10, 10), null),
-                GeometryFactory.createPolygon(ring(10, 0, 20, 10), null));
+        final Geometry g = GeometryFactory.DEFAULT.createPolyhedralSurface(
+                GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), null),
+                GeometryFactory.DEFAULT.createPolygon(ring(10, 0, 20, 10), null));
         final String xml = write(g);
         assertTrue(xml.contains("patches"), () -> "Expected gml:patches in: " + xml);
         assertEquals(2, countOccurrences(xml, "<PolygonPatch"), () -> "Expected two patches in: " + xml);
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GMLWriterTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GMLWriterTest.java
index e2e1b77c7e..d9ab6c5b78 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GMLWriterTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/GMLWriterTest.java
@@ -52,8 +52,8 @@ public final class GMLWriterTest extends TestCase {
      * the resulting XML document as a string.
      */
     private String write(final GMLVersion version) throws Exception {
-        final Point g = GeometryFactory.createPoint(
-                GeometryFactory.createSequence(NDArrays.of(SampleSystem.of(wgs84), 10.0, 20.0)));
+        final Point g = GeometryFactory.DEFAULT.createPoint(
+                GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(SampleSystem.of(wgs84), 10.0, 20.0)));
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
         try (GMLWriter writer = new GMLWriter(out, version)) {
             writer.writeGeometry(g);
diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/JAXBGeometryAdapterTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/JAXBGeometryAdapterTest.java
index dbb6cd1179..822dedaa0f 100644
--- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/JAXBGeometryAdapterTest.java
+++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/gml/JAXBGeometryAdapterTest.java
@@ -125,14 +125,14 @@ public final class JAXBGeometryAdapterTest {
      * Creates a point sequence in the {@link #wgs84} CRS from a flat list of ordinates.
      */
     private DataPoints sequence(final double... ordinates) {
-        return GeometryFactory.createSequence(NDArrays.of(SampleSystem.of(wgs84), ordinates));
+        return GeometryFactory.DEFAULT.createDataPoints(NDArrays.of(SampleSystem.of(wgs84), ordinates));
     }
 
     /**
      * Creates a closed rectangular ring in the {@link #wgs84} CRS.
      */
     private LinearRing ring(final double minX, final double minY, final double maxX, final double maxY) {
-        return GeometryFactory.createLinearRing(sequence(
+        return GeometryFactory.DEFAULT.createLinearRing(sequence(
                 minX, minY,
                 maxX, minY,
                 maxX, maxY,
@@ -146,7 +146,7 @@ public final class JAXBGeometryAdapterTest {
     @Test
     @Disabled("TODO missing jaxb implementation")
     public void testPoint() throws Exception {
-        final Point expected = GeometryFactory.createPoint(sequence(10.0, 20.0));
+        final Point expected = GeometryFactory.DEFAULT.createPoint(sequence(10.0, 20.0));
 
         final String xml = marshal(new TestFeature("A", expected));
         assertTrue(xml.toLowerCase().contains("point"), () -> "Expected a GML Point element in: " + xml);
@@ -164,7 +164,7 @@ public final class JAXBGeometryAdapterTest {
     @Test
     @Disabled("TODO missing jaxb implementation")
     public void testPolygon() throws Exception {
-        final Polygon expected = GeometryFactory.createPolygon(ring(0, 0, 10, 10), List.of(ring(2, 2, 4, 4)));
+        final Polygon expected = GeometryFactory.DEFAULT.createPolygon(ring(0, 0, 10, 10), List.of(ring(2, 2, 4, 4)));
 
         final String xml = marshal(new TestFeature("B", expected));
         assertTrue(xml.toLowerCase().contains("polygon"), () -> "Expected a GML Polygon element in: " + xml);
diff --git a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/dggs/DiscreteGlobalGridSystems.java b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/dggs/DiscreteGlobalGridSystems.java
index 091583f8c4..56488e9042 100644
--- a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/dggs/DiscreteGlobalGridSystems.java
+++ b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/dggs/DiscreteGlobalGridSystems.java
@@ -259,8 +259,8 @@ public final class DiscreteGlobalGridSystems {
         final double[] coords = S2.toArray(s2.loop(0));
         final Array positions = NDArrays.of(CommonCRS.WGS84.normalizedGeographic(), coords);
         final DataPoints sequence = new ArrayDataPoints(positions);
-        final LinearRing exterior = org.apache.sis.geometries.GeometryFactory.createLinearRing(sequence);
-        return org.apache.sis.geometries.GeometryFactory.createPolygon(exterior, null);
+        final LinearRing exterior = org.apache.sis.geometries.GeometryFactory.DEFAULT.createLinearRing(sequence);
+        return org.apache.sis.geometries.GeometryFactory.DEFAULT.createPolygon(exterior, null);
     }
 
     public static S2Polygon toS2Polygon(GeographicExtent extent) {