sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: A CSAuthorityFactory containing at least the coordinate system EPSG::4400 should be available even if there is no connection to the EPSG database. This is required for some data stores like netCDF. The CSAuthorityFactory interface is added on EPSGFactoryFallback.
Date Sun, 28 Apr 2019 15:23:51 GMT
This is an automated email from the ASF dual-hosted git repository.

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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 9987015  A CSAuthorityFactory containing at least the coordinate system EPSG::4400 should be available even if there is no connection to the EPSG database. This is required for some data stores like netCDF. The CSAuthorityFactory interface is added on EPSGFactoryFallback.
9987015 is described below

commit 9987015db5075b13ffbf96b160ed8225911192ed
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sun Apr 28 17:21:19 2019 +0200

    A CSAuthorityFactory containing at least the coordinate system EPSG::4400 should be available even if there is no connection to the EPSG database.
    This is required for some data stores like netCDF. The CSAuthorityFactory interface is added on EPSGFactoryFallback.
---
 .../org/apache/sis/metadata/TreeTableView.java     |   2 +-
 .../internal/referencing/ReferencingUtilities.java |  16 +-
 .../org/apache/sis/parameter/ParameterFormat.java  |   2 +-
 .../java/org/apache/sis/referencing/CommonCRS.java |  46 ++---
 .../sis/referencing/EPSGFactoryFallback.java       | 186 +++++++++++++++------
 .../sis/referencing/StandardDefinitions.java       |  85 ++++++----
 .../java/org/apache/sis/referencing/cs/Codes.java  |   3 +-
 .../referencing/factory/sql/EPSGDataAccess.java    |   2 +-
 .../org/apache/sis/geometry/TransformTestCase.java |   2 +-
 .../java/org/apache/sis/referencing/CRSTest.java   |   4 +-
 .../sis/referencing/EPSGFactoryFallbackTest.java   |  38 ++++-
 .../sis/referencing/StandardDefinitionsTest.java   |  33 +++-
 .../sis/referencing/cs/DefaultCartesianCSTest.java |   7 +-
 .../org/apache/sis/internal/util/Constants.java    |   6 -
 .../sis/internal/util/StandardDateFormat.java      |   2 +-
 .../java/org/apache/sis/util/collection/Cache.java |   2 +-
 .../java/org/apache/sis/util/package-info.java     |   2 +-
 .../sis/internal/storage/xml/package-info.java     |   2 +-
 18 files changed, 292 insertions(+), 148 deletions(-)

diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java
index 3e6cca4..792659b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java
@@ -185,7 +185,7 @@ final class TreeTableView implements TreeTable, TreeFormatCustomization, Seriali
             }
             /*
              * Filter out the ISBN and ISSN identifiers if they are inside a Citation object.
-             * We keep them if the user added them to other kind of objects.
+             * We keep them if the user added them to other kinds of objects.
              */
             if (value instanceof SpecializedIdentifier) {
                 final Citation authority = ((SpecializedIdentifier) value).getAuthority();
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
index 06f6233..b66cec7 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
@@ -40,7 +40,6 @@ import org.opengis.referencing.datum.VerticalDatumType;
 import org.opengis.referencing.operation.CoordinateOperationFactory;
 import org.opengis.util.FactoryException;
 import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.Utilities;
 import org.apache.sis.util.CharSequences;
@@ -460,19 +459,20 @@ public final class ReferencingUtilities extends Static {
 
     /**
      * Returns the a coordinate system for map projections with (easting, northing) axes in metres.
-     * This coordinate system is identified by EPSG:{@value Constants#EPSG_PROJECTED_CS}.
+     * EPSG::4400 — Cartesian 2D CS. Axes: easting, northing (E,N). Orientations: east, north. UoM: m.
      *
-     * @param  factory the factory to use for creating the coordinate system, or {@code null} for the default.
+     * @param  factory the EPSG factory to use for creating the coordinate system.
      * @return a coordinate system with (easting, northing) axes in metres.
      * @throws FactoryException if an error occurred while creating the coordinate system.
      *
      * @since 1.0
      */
-    public static CartesianCS standardProjectedCS(CSAuthorityFactory factory) throws FactoryException {
-        if (factory == null) {
-            factory = DefaultFactories.forBuildin(CSAuthorityFactory.class);
-        }
-        return factory.createCartesianCS(String.valueOf(Constants.EPSG_PROJECTED_CS));
+    public static CartesianCS standardProjectedCS(final CSAuthorityFactory factory) throws FactoryException {
+        /*
+         * Note: we may provide a default factory in a future SIS version.
+         * We may need to mimic ReferencingFactoryContainer.getCSAuthorityFactory().
+         */
+        return factory.createCartesianCS("4400");
     }
 
     /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
index 399f23a..1e4ae6b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
@@ -88,7 +88,7 @@ import static org.apache.sis.util.collection.Containers.hashMapCapacity;
  * }
  * </div>
  *
- * The kind of objects accepted by this formatter are:
+ * The kinds of objects accepted by this formatter are:
  * <table class="sis">
  *   <caption>Formattable object types</caption>
  *   <tr><th>Class</th> <th>Remarks</th></tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
index 715d532..3b8facd 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
@@ -305,11 +305,6 @@ public enum CommonCRS {
     static final CommonCRS DEFAULT = WGS84;
 
     /**
-     * Properties to exclude when using an other object as a template.
-     */
-    private static final String[] EXCLUDE = new String[] {IdentifiedObject.IDENTIFIERS_KEY};
-
-    /**
      * The EPSG code of the two-dimensional geographic CRS.
      */
     final short geographic;
@@ -352,7 +347,7 @@ public enum CommonCRS {
     final byte firstZone, lastZone;
 
     /**
-     * The cached object. This is initially {@code null}, then set to various kind of objects depending
+     * The cached object. This is initially {@code null}, then set to various kinds of objects depending
      * on which method has been invoked. The kind of object stored in this field may change during the
      * application execution.
      */
@@ -645,7 +640,7 @@ public enum CommonCRS {
                      */
                     final EllipsoidalCS cs;
                     if (this == DEFAULT) {
-                        cs = (EllipsoidalCS) StandardDefinitions.createCoordinateSystem((short) 6422);
+                        cs = (EllipsoidalCS) StandardDefinitions.createCoordinateSystem(StandardDefinitions.ELLIPSOIDAL_2D, true);
                     } else {
                         cs = DEFAULT.geographic().getCoordinateSystem();
                     }
@@ -703,7 +698,7 @@ public enum CommonCRS {
                      */
                     final EllipsoidalCS cs;
                     if (this == DEFAULT) {
-                        cs = (EllipsoidalCS) StandardDefinitions.createCoordinateSystem((short) 6423);
+                        cs = (EllipsoidalCS) StandardDefinitions.createCoordinateSystem(StandardDefinitions.ELLIPSOIDAL_3D, true);
                     } else {
                         cs = DEFAULT.geographic3D().getCoordinateSystem();
                     }
@@ -762,7 +757,7 @@ public enum CommonCRS {
                      */
                     final CartesianCS cs;
                     if (this == DEFAULT) {
-                        cs = (CartesianCS) StandardDefinitions.createCoordinateSystem((short) 6500);
+                        cs = (CartesianCS) StandardDefinitions.createCoordinateSystem(StandardDefinitions.EARTH_CENTRED, true);
                     } else {
                         cs = (CartesianCS) DEFAULT.geocentric().getCoordinateSystem();
                     }
@@ -806,19 +801,19 @@ public enum CommonCRS {
                     if (this == DEFAULT) {
                         final GeodeticAuthorityFactory factory = factory();
                         if (factory != null) try {
-                            cs = factory.createSphericalCS("6404");
+                            cs = factory.createSphericalCS(Short.toString(StandardDefinitions.SPHERICAL));
                         } catch (FactoryException e) {
-                            failure(this, "spherical", e, (short) 6404);
+                            failure(this, "spherical", e, StandardDefinitions.SPHERICAL);
                         }
                         if (cs == null) {
-                            cs = (SphericalCS) StandardDefinitions.createCoordinateSystem((short) 6404);
+                            cs = (SphericalCS) StandardDefinitions.createCoordinateSystem(StandardDefinitions.SPHERICAL, true);
                         }
                     } else {
                         cs = (SphericalCS) DEFAULT.spherical().getCoordinateSystem();
                     }
                     // Use same name and datum than the geographic CRS.
                     final GeographicCRS base = geographic();
-                    object = new DefaultGeocentricCRS(IdentifiedObjects.getProperties(base, EXCLUDE), base.getDatum(), cs);
+                    object = new DefaultGeocentricCRS(IdentifiedObjects.getProperties(base, exclude()), base.getDatum(), cs);
                     cachedSpherical = object;
                 }
             }
@@ -1153,7 +1148,9 @@ public enum CommonCRS {
                     cs = DEFAULT.universal(latitude, longitude).getCoordinateSystem();
                 } else {
                     cs = (CartesianCS) StandardDefinitions.createCoordinateSystem(
-                            isUTM ? Constants.EPSG_PROJECTED_CS : isSouth ? (short) 1027 : (short) 1026);
+                            isUTM   ? StandardDefinitions.CARTESIAN_2D :
+                            isSouth ? StandardDefinitions.UPS_SOUTH
+                                    : StandardDefinitions.UPS_NORTH, true);
                 }
             }
             crs = StandardDefinitions.createUniversal(code, geographic(), isUTM, latitude, longitude, cs);
@@ -1312,7 +1309,7 @@ public enum CommonCRS {
         final short datum;
 
         /**
-         * The cached object. This is initially {@code null}, then set to various kind of objects depending
+         * The cached object. This is initially {@code null}, then set to various kinds of objects depending
          * on which method has been invoked. The kind of object stored in this field may change during the
          * application execution.
          */
@@ -1389,7 +1386,7 @@ public enum CommonCRS {
                             object = StandardDefinitions.createVerticalCRS(crs, datum());
                         } else {
                             final VerticalCS cs = cs();
-                            object = new DefaultVerticalCRS(IdentifiedObjects.getProperties(cs, EXCLUDE), datum(), cs);
+                            object = new DefaultVerticalCRS(IdentifiedObjects.getProperties(cs, exclude()), datum(), cs);
                         }
                         cached = object;
                     }
@@ -1577,7 +1574,7 @@ public enum CommonCRS {
         private final long epoch;
 
         /**
-         * The cached object. This is initially {@code null}, then set to various kind of objects depending
+         * The cached object. This is initially {@code null}, then set to various kinds of objects depending
          * on which method has been invoked. The kind of object stored in this field may change during the
          * application execution.
          */
@@ -1659,7 +1656,7 @@ public enum CommonCRS {
                     object = crs(cached);
                     if (object == null) {
                         final TemporalDatum datum = datum();
-                        object = new DefaultTemporalCRS(IdentifiedObjects.getProperties(datum, EXCLUDE), datum, cs());
+                        object = new DefaultTemporalCRS(IdentifiedObjects.getProperties(datum, exclude()), datum, cs());
                         cached = object;
                     }
                 }
@@ -1687,8 +1684,8 @@ public enum CommonCRS {
                 case UNIX: {
                     // Share the NamedIdentifier created for Java time.
                     final TimeCS share = JAVA.crs().getCoordinateSystem();
-                    cs   = IdentifiedObjects.getProperties(share, EXCLUDE);
-                    axis = IdentifiedObjects.getProperties(share.getAxis(0), EXCLUDE);
+                    cs   = IdentifiedObjects.getProperties(share, exclude());
+                    axis = IdentifiedObjects.getProperties(share.getAxis(0), exclude());
                     break;
                 }
                 case JAVA: {
@@ -1788,12 +1785,19 @@ public enum CommonCRS {
      * Returns the same properties than the given object, except for the identifier which is set to the given code.
      */
     private static Map<String,?> properties(final IdentifiedObject template, final short code) {
-        final Map<String,Object> properties = new HashMap<>(IdentifiedObjects.getProperties(template, EXCLUDE));
+        final Map<String,Object> properties = new HashMap<>(IdentifiedObjects.getProperties(template, exclude()));
         properties.put(GeographicCRS.IDENTIFIERS_KEY, new NamedIdentifier(Citations.EPSG, String.valueOf(code)));
         return properties;
     }
 
     /**
+     * Properties to exclude when using another object as a template.
+     */
+    private static String[] exclude() {
+        return new String[] {IdentifiedObject.IDENTIFIERS_KEY};
+    }
+
+    /**
      * Returns the EPSG factory to use for creating CRS, or {@code null} if none.
      * If this method returns {@code null}, then the caller will silently fallback on hard-coded values.
      */
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/EPSGFactoryFallback.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/EPSGFactoryFallback.java
index fd2bad3..014924b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/EPSGFactoryFallback.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/EPSGFactoryFallback.java
@@ -19,6 +19,7 @@ package org.apache.sis.referencing;
 import java.util.Collections;
 import java.util.Set;
 import java.util.LinkedHashSet;
+import javax.measure.Unit;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.NoSuchAuthorityCodeException;
 import org.opengis.referencing.datum.DatumAuthorityFactory;
@@ -33,6 +34,12 @@ import org.opengis.referencing.crs.ProjectedCRS;
 import org.opengis.referencing.crs.VerticalCRS;
 import org.opengis.referencing.crs.CRSAuthorityFactory;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.cs.CSAuthorityFactory;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.cs.SphericalCS;
+import org.opengis.referencing.cs.CartesianCS;
 import org.opengis.metadata.citation.Citation;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
@@ -46,6 +53,7 @@ import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Debug;
 import org.apache.sis.measure.Latitude;
+import org.apache.sis.measure.Units;
 
 
 /**
@@ -54,12 +62,14 @@ import org.apache.sis.measure.Latitude;
  * in the {@link CRS#forCode(String)} method javadoc is always available.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.7
  * @module
  */
 @Fallback
-final class EPSGFactoryFallback extends GeodeticAuthorityFactory implements CRSAuthorityFactory, DatumAuthorityFactory {
+final class EPSGFactoryFallback extends GeodeticAuthorityFactory
+        implements CRSAuthorityFactory, CSAuthorityFactory, DatumAuthorityFactory
+{
     /**
      * Whether to disallow {@code CommonCRS} to use {@link org.apache.sis.referencing.factory.sql.EPSGFactory}
      * (in which case {@code CommonCRS} will fallback on hard-coded values).
@@ -74,11 +84,6 @@ final class EPSGFactoryFallback extends GeodeticAuthorityFactory implements CRSA
     static final EPSGFactoryFallback INSTANCE = new EPSGFactoryFallback();
 
     /**
-     * Kinds of object created by this factory. Used as bitmask.
-     */
-    private static final int CRS = 1, DATUM = 2, ELLIPSOID = 4, PRIME_MERIDIAN = 8;
-
-    /**
      * The authority to report in exceptions. Not necessarily the same than the {@link #authority} title.
      */
     private static final String AUTHORITY = Constants.EPSG + "-subset";
@@ -155,11 +160,28 @@ final class EPSGFactoryFallback extends GeodeticAuthorityFactory implements CRSA
         if (vertical || vdatum) {
             for (final CommonCRS.Vertical candidate : CommonCRS.Vertical.values()) {
                 if (candidate.isEPSG) {
-                    if (vertical) codes.add(Integer.toString(candidate.crs));
-                    if (vdatum)   codes.add(Integer.toString(candidate.datum));
+                    if (vertical) add(codes, candidate.crs);
+                    if (vdatum)   add(codes, candidate.datum);
                 }
             }
         }
+        if (type.isAssignableFrom(EllipsoidalCS.class)) {
+            add(codes, StandardDefinitions.ELLIPSOIDAL_2D);
+            add(codes, StandardDefinitions.ELLIPSOIDAL_3D);
+        }
+        if (type.isAssignableFrom(SphericalCS.class)) {
+            add(codes, StandardDefinitions.SPHERICAL);
+        }
+        if (type.isAssignableFrom(CartesianCS.class)) {
+            add(codes, StandardDefinitions.EARTH_CENTRED);
+            add(codes, StandardDefinitions.CARTESIAN_2D);
+            add(codes, StandardDefinitions.UPS_NORTH);
+            add(codes, StandardDefinitions.UPS_SOUTH);
+        }
+        if (type.isAssignableFrom(Unit.class)) {
+            add(codes, Constants.EPSG_METRE);
+            add(codes, Constants.EPSG_AXIS_DEGREES);
+        }
         return codes;
     }
 
@@ -167,13 +189,17 @@ final class EPSGFactoryFallback extends GeodeticAuthorityFactory implements CRSA
      * Adds the given value to the given set, provided that the value is different than zero.
      * Zero is used as a sentinel value in {@link CommonCRS} meaning "no EPSG code".
      */
-    private static void add(final Set<String> codes, final int value) {
-        if (value != 0) {
-            codes.add(Integer.toString(value));
-        }
+    private static void add(final Set<String> codes, final short value) {
+        if (value != 0) codes.add(Short.toString(value));
     }
 
     /**
+     * Kinds of object created by this factory, as bitmask. Note that objects
+     * created for {@link #CS} and {@link #AXIS} kinds are currently not cached.
+     */
+    private static final int CRS=0x1, DATUM=0x2, ELLIPSOID=0x4, PRIME_MERIDIAN=0x8, UNIT=0x10, AXIS=0x20, CS=0x40;
+
+    /**
      * Returns a prime meridian for the given EPSG code.
      */
     @Override
@@ -207,22 +233,50 @@ final class EPSGFactoryFallback extends GeodeticAuthorityFactory implements CRSA
     }
 
     /**
+     * Returns a coordinate system for the given EPSG code. Contrarily to other kinds of objects,
+     * coordinate systems are not cached because we can not use {@link CommonCRS} as a store for
+     * them (because all enumerated values use the same coordinate systems). The lack of caching
+     * should not be an issue since standalone CS objects (without CRS) are rarely be needed.
+     */
+    @Override
+    public CoordinateSystem createCoordinateSystem(final String code) throws NoSuchAuthorityCodeException {
+        return (CoordinateSystem) predefined(code, CS);
+    }
+
+    /**
+     * Returns a coordinate system axis for the given EPSG code. Axes are not cached for the same
+     * reasons than {@link #createCoordinateSystem(String)}.
+     */
+    @Override
+    public CoordinateSystemAxis createCoordinateSystemAxis(final String code) throws NoSuchAuthorityCodeException {
+        return (CoordinateSystemAxis) predefined(code, AXIS);
+    }
+
+    /**
+     * Returns a unit of measurement for the given code.
+     */
+    @Override
+    public Unit<?> createUnit(final String code) throws NoSuchAuthorityCodeException {
+        return (Unit) predefined(code, UNIT);
+    }
+
+    /**
      * Returns a coordinate reference system, datum or ellipsoid for the given EPSG code.
      */
     @Override
     public IdentifiedObject createObject(final String code) throws NoSuchAuthorityCodeException {
-        return predefined(code, -1);
+        return (IdentifiedObject) predefined(code, -1 & ~UNIT);
     }
 
     /**
      * Implementation of all {@code createFoo(String)} methods in this fallback class.
      *
      * @param  code  the EPSG code.
-     * @param  kind  any combination of {@link #CRS}, {@link #DATUM}, {@link #ELLIPSOID} or {@link #PRIME_MERIDIAN} bits.
+     * @param  kind  any combination of {@code *_MASK} bits.
      * @return the requested object.
      * @throws NoSuchAuthorityCodeException if no matching object has been found.
      */
-    private IdentifiedObject predefined(String code, final int kind) throws NoSuchAuthorityCodeException {
+    private Object predefined(String code, final int kind) throws NoSuchAuthorityCodeException {
         try {
             /*
              * Parse the value after the last ':'. We do not bother to verify if the part before ':' is legal
@@ -232,48 +286,67 @@ final class EPSGFactoryFallback extends GeodeticAuthorityFactory implements CRSA
              * when using the factory returned by AuthorityFactories.fallback(…).
              */
             code = CharSequences.trimWhitespaces(code, code.lastIndexOf(DefaultNameSpace.DEFAULT_SEPARATOR) + 1, code.length()).toString();
-            final int n = Integer.parseInt(code);
-            if ((kind & PRIME_MERIDIAN) != 0  &&  n == Constants.EPSG_GREENWICH) {
-                return CommonCRS.WGS84.primeMeridian();
-            }
-            for (final CommonCRS crs : CommonCRS.values()) {
-                /*
-                 * In a complete EPSG dataset we could have an ambiguity below because the same code can be used
-                 * for datum, ellipsoid and CRS objects. However in the particular case of this EPSG-subset, we
-                 * ensured that there is no such collision - see CommonCRSTest.ensureNoCodeCollision().
-                 */
-                if ((kind & ELLIPSOID) != 0  &&  n == crs.ellipsoid) return crs.ellipsoid();
-                if ((kind & DATUM)     != 0  &&  n == crs.datum)     return crs.datum();
-                if ((kind & CRS) != 0) {
-                    if (n == crs.geographic) return crs.geographic();
-                    if (n == crs.geocentric) return crs.geocentric();
-                    if (n == crs.geo3D)      return crs.geographic3D();
-                    final double latitude;
-                    int zone;
-                    if (crs.northUTM != 0 && (zone = n - crs.northUTM) >= crs.firstZone && zone <= crs.lastZone) {
-                        latitude = +1;          // Any north latitude below 56°N (because of Norway exception) is okay
-                    } else if (crs.southUTM != 0 && (zone = n - crs.southUTM) >= crs.firstZone && zone <= crs.lastZone) {
-                        latitude = -1;          // Any south latitude above 80°S (because of UPS south case) is okay.
-                    } else if (n == crs.northUPS) {
-                        latitude = Latitude.MAX_VALUE;
-                        zone     = 30;                  // Any random UTM zone is okay.
-                    } else if (n == crs.southUPS) {
-                        latitude = Latitude.MIN_VALUE;
-                        zone     = 30;                  // Any random UTM zone is okay.
-                    } else {
-                        continue;
+            final short n = Short.parseShort(code);
+            if ((kind & (ELLIPSOID | DATUM | CRS)) != 0) {
+                for (final CommonCRS crs : CommonCRS.values()) {
+                    /*
+                     * In a complete EPSG dataset we could have an ambiguity below because the same code can be used
+                     * for datum, ellipsoid and CRS objects. However in the particular case of this EPSG-subset, we
+                     * ensured that there is no such collision - see CommonCRSTest.ensureNoCodeCollision().
+                     */
+                    if ((kind & ELLIPSOID) != 0  &&  n == crs.ellipsoid) return crs.ellipsoid();
+                    if ((kind & DATUM)     != 0  &&  n == crs.datum)     return crs.datum();
+                    if ((kind & CRS) != 0) {
+                        if (n == crs.geographic) return crs.geographic();
+                        if (n == crs.geocentric) return crs.geocentric();
+                        if (n == crs.geo3D)      return crs.geographic3D();
+                        final double latitude;
+                        int zone;
+                        if (crs.northUTM != 0 && (zone = n - crs.northUTM) >= crs.firstZone && zone <= crs.lastZone) {
+                            latitude = +1;          // Any north latitude below 56°N (because of Norway exception) is okay
+                        } else if (crs.southUTM != 0 && (zone = n - crs.southUTM) >= crs.firstZone && zone <= crs.lastZone) {
+                            latitude = -1;          // Any south latitude above 80°S (because of UPS south case) is okay.
+                        } else if (n == crs.northUPS) {
+                            latitude = Latitude.MAX_VALUE;
+                            zone     = 30;                  // Any random UTM zone is okay.
+                        } else if (n == crs.southUPS) {
+                            latitude = Latitude.MIN_VALUE;
+                            zone     = 30;                  // Any random UTM zone is okay.
+                        } else {
+                            continue;
+                        }
+                        return crs.universal(latitude, TransverseMercator.Zoner.UTM.centralMeridian(zone));
                     }
-                    return crs.universal(latitude, TransverseMercator.Zoner.UTM.centralMeridian(zone));
                 }
-            }
-            if ((kind & (DATUM | CRS)) != 0) {
-                for (final CommonCRS.Vertical candidate : CommonCRS.Vertical.values()) {
-                    if (candidate.isEPSG) {
-                        if ((kind & DATUM) != 0  &&  candidate.datum == n) return candidate.datum();
-                        if ((kind & CRS)   != 0  &&  candidate.crs   == n) return candidate.crs();
+                if ((kind & (DATUM | CRS)) != 0) {
+                    for (final CommonCRS.Vertical candidate : CommonCRS.Vertical.values()) {
+                        if (candidate.isEPSG) {
+                            if ((kind & DATUM) != 0  &&  candidate.datum == n) return candidate.datum();
+                            if ((kind & CRS)   != 0  &&  candidate.crs   == n) return candidate.crs();
+                        }
                     }
                 }
             }
+            /*
+             * Other kinds of objects (prime meridian, units of measurement, etc). We check those candidates only after
+             * above loop (CRS, datum, etc.) in order to give precedence to CRS if the same code is used for both kinds
+             * of objects. We do not bother to cache coordinate system and axis instances.
+             */
+            if ((kind & PRIME_MERIDIAN) != 0  &&  n == Constants.EPSG_GREENWICH) {
+                return CommonCRS.WGS84.primeMeridian();
+            }
+            if ((kind & CS) != 0) {
+                final CoordinateSystem cs = StandardDefinitions.createCoordinateSystem(n, false);
+                if (cs != null) return cs;
+            }
+            if ((kind & AXIS) != 0) {
+                final CoordinateSystemAxis axis = StandardDefinitions.createAxis(n, false);
+                if (axis != null) return axis;
+            }
+            if ((kind & UNIT) != 0) {
+                final Unit<?> unit = Units.valueOfEPSG(n);
+                if (unit != null) return unit;
+            }
         } catch (NumberFormatException cause) {
             final NoSuchAuthorityCodeException e = new NoSuchAuthorityCodeException(Resources.format(
                     Resources.Keys.NoSuchAuthorityCode_3, Constants.EPSG, toClass(kind), code), AUTHORITY, code);
@@ -285,8 +358,8 @@ final class EPSGFactoryFallback extends GeodeticAuthorityFactory implements CRSA
     }
 
     /**
-     * Returns the interface for the given {@link #CRS}, {@link #DATUM}, {@link #ELLIPSOID} or {@link #PRIME_MERIDIAN}
-     * constant. This is used for formatting error message only.
+     * Returns the interface for the given {@code *_MASK} constant.
+     * This is used for formatting error message only.
      */
     private static Class<?> toClass(final int kind) {
         switch (kind) {
@@ -294,6 +367,9 @@ final class EPSGFactoryFallback extends GeodeticAuthorityFactory implements CRSA
             case DATUM:          return Datum.class;
             case ELLIPSOID:      return Ellipsoid.class;
             case PRIME_MERIDIAN: return PrimeMeridian.class;
+            case UNIT:           return Unit.class;
+            case AXIS:           return CoordinateSystemAxis.class;
+            case CS:             return CoordinateSystem.class;
             default:             return IdentifiedObject.class;
         }
     }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java
index 5a1f579..af3a7fc 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java
@@ -251,7 +251,7 @@ final class StandardDefinitions {
      */
     static PrimeMeridian primeMeridian() {
         final Map<String,Object> properties = new HashMap<>(4);
-        properties.put(NAME_KEY, new NamedIdentifier(Citations.EPSG, "Greenwich")); // Name is fixed by ISO 19111.
+        properties.put(NAME_KEY, new NamedIdentifier(Citations.EPSG, "Greenwich"));         // Name is fixed by ISO 19111.
         properties.put(IDENTIFIERS_KEY, new NamedIdentifier(Citations.EPSG, GREENWICH));
         return new DefaultPrimeMeridian(properties, 0, Units.DEGREE);
     }
@@ -264,32 +264,34 @@ final class StandardDefinitions {
      * @return the vertical CRS for the given code.
      */
     static VerticalCRS createVerticalCRS(final short code, final VerticalDatum datum) {
-        String cs   = "Vertical CS. Axis: height (H).";   // Default coordinate system
-        short  c    = 6499;                               // EPSG code of above coordinate system.
-        short  axis = 114;                                // Axis of above coordinate system.
-        String wms  = null;
+        String csName = "Vertical CS. Axis: height (H).";   // Default coordinate system
+        short  csCode = 6499;                               // EPSG code of above coordinate system.
+        short  axis   = 114;                                // Axis of above coordinate system.
+        String wms    = null;
         final  String name, alias;
         switch (code) {
-            case 5703: wms   = "88";
-                       name  = "NAVD88 height";
-                       alias = "North American Vertical Datum of 1988 height (m)";
+            case 5703: wms    = "88";
+                       name   = "NAVD88 height";
+                       alias  = "North American Vertical Datum of 1988 height (m)";
                        break;
-            case 5714: name  = "MSL height";
-                       alias = "mean sea level height";
+            case 5714: name   = "MSL height";
+                       alias  = "mean sea level height";
                        break;
-            case 5715: name  = "MSL depth";
-                       alias = "mean sea level depth";
-                       cs    = "Vertical CS. Axis: depth (D).";
-                       c     = 6498;
-                       axis  = 113;
+            case 5715: name   = "MSL depth";
+                       alias  = "mean sea level depth";
+                       csName = "Vertical CS. Axis: depth (D).";
+                       csCode = 6498;
+                       axis   = 113;
                        break;
             default:   throw new AssertionError(code);
         }
-        final Map<String,Object> properties = properties(code, name, alias, true);
+        Map<String,Object> properties = properties(csCode, csName, null, false);
+        final DefaultVerticalCS cs = new DefaultVerticalCS(properties, createAxis(axis, true));
+        properties = properties(code, name, alias, true);
         if (wms != null) {
             addWMS(properties, wms);
         }
-        return new DefaultVerticalCRS(properties, datum, new DefaultVerticalCS(properties(c, cs, null, false), createAxis(axis)));
+        return new DefaultVerticalCRS(properties, datum, cs);
     }
 
     /**
@@ -310,36 +312,51 @@ final class StandardDefinitions {
     }
 
     /**
+     * EPSG codes of coordinate systems supported by this class. We provide constants only for
+     * coordinate systems because those codes appear directly in method bodies, contrarily to
+     * other kinds of object where the code are stored in {@link CommonCRS} fields.
+     */
+    static final short ELLIPSOIDAL_2D = (short) 6422,
+                       ELLIPSOIDAL_3D = (short) 6423,
+                       SPHERICAL      = (short) 6404,
+                       EARTH_CENTRED  = (short) 6500,
+                       CARTESIAN_2D   = (short) 4400,
+                       UPS_NORTH      = (short) 1026,
+                       UPS_SOUTH      = (short) 1027;
+
+    /**
      * Creates a coordinate system from hard-coded values for the given code.
      * The coordinate system names used by this method contains only the first
      * part of the names declared in the EPSG database.
      *
-     * @param  code  the EPSG code.
+     * @param  code       the EPSG code.
+     * @param  mandatory  whether to fail or return {@code null} if the given code is unknown.
      * @return the coordinate system for the given code.
      */
     @SuppressWarnings("fallthrough")
-    static CoordinateSystem createCoordinateSystem(final short code) {
+    static CoordinateSystem createCoordinateSystem(final short code, final boolean mandatory) {
         final String name;
         int type = 0;                   // 0= Cartesian (default), 1= Spherical, 2= Ellipsoidal
         int dim = 2;                    // Number of dimension, default to 2.
         short axisCode;                 // Code of first axis + dim (or code after the last axis).
         switch (code) {
-            case 6422: name = "Ellipsoidal 2D"; type = 2;          axisCode =  108; break;
-            case 6423: name = "Ellipsoidal 3D"; type = 2; dim = 3; axisCode =  111; break;
-            case 6404: name = "Spherical";      type = 1; dim = 3; axisCode =   63; break;
-            case 6500: name = "Earth centred";            dim = 3; axisCode =  118; break;
-            case 4400: name = "Cartesian 2D";                      axisCode =    3; break;
-            case 1026: name = "Cartesian 2D for UPS north";        axisCode = 1067; break;
-            case 1027: name = "Cartesian 2D for UPS south";        axisCode = 1059; break;
-            default:   throw new AssertionError(code);
+            case ELLIPSOIDAL_2D: name = "Ellipsoidal 2D"; type = 2;          axisCode =  108; break;
+            case ELLIPSOIDAL_3D: name = "Ellipsoidal 3D"; type = 2; dim = 3; axisCode =  111; break;
+            case SPHERICAL:      name = "Spherical";      type = 1; dim = 3; axisCode =   63; break;
+            case EARTH_CENTRED:  name = "Earth centred";            dim = 3; axisCode =  118; break;
+            case CARTESIAN_2D:   name = "Cartesian 2D";                      axisCode =    3; break;
+            case UPS_NORTH:      name = "Cartesian 2D for UPS north";        axisCode = 1067; break;
+            case UPS_SOUTH:      name = "Cartesian 2D for UPS south";        axisCode = 1059; break;
+            default:   if (!mandatory) return null;
+                       throw new AssertionError(code);
         }
         final Map<String,?> properties = properties(code, name, null, false);
         CoordinateSystemAxis xAxis = null, yAxis = null, zAxis = null;
         switch (dim) {
             default: throw new AssertionError(dim);
-            case 3:  zAxis = createAxis(--axisCode);
-            case 2:  yAxis = createAxis(--axisCode);
-            case 1:  xAxis = createAxis(--axisCode);
+            case 3:  zAxis = createAxis(--axisCode, true);
+            case 2:  yAxis = createAxis(--axisCode, true);
+            case 1:  xAxis = createAxis(--axisCode, true);
             case 0:  break;
         }
         switch (type) {
@@ -355,10 +372,11 @@ final class StandardDefinitions {
     /**
      * Creates an axis from hard-coded values for the given code.
      *
-     * @param  code  the EPSG code.
+     * @param  code       the EPSG code.
+     * @param  mandatory  whether to fail or return {@code null} if the given code is unknown.
      * @return the coordinate system axis for the given code.
      */
-    static CoordinateSystemAxis createAxis(final short code) {
+    static CoordinateSystemAxis createAxis(final short code, final boolean mandatory) {
         final String name, abrv;
         Unit<?> unit = Units.METRE;
         double min = Double.NEGATIVE_INFINITY;
@@ -455,7 +473,8 @@ final class StandardDefinitions {
                        abrv = "N";
                        dir  = CoordinateSystems.directionAlongMeridian(AxisDirection.SOUTH, 180);
                        break;
-            default:   throw new AssertionError(code);
+            default:   if (!mandatory) return null;
+                       throw new AssertionError(code);
         }
         final Map<String,Object> properties = properties(code, name, null, false);
         properties.put(DefaultCoordinateSystemAxis.MINIMUM_VALUE_KEY, min);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Codes.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Codes.java
index 5ff01a4..7a5f8c5 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Codes.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Codes.java
@@ -25,7 +25,6 @@ import org.opengis.referencing.cs.AxisDirection;
 
 import static org.apache.sis.internal.util.Constants.EPSG_METRE;
 import static org.apache.sis.internal.util.Constants.EPSG_AXIS_DEGREES;
-import static org.apache.sis.internal.util.Constants.EPSG_PROJECTED_CS;
 
 
 /**
@@ -144,7 +143,7 @@ loop:   for (int i=0; ; i++) {
             final short epsg;
             short to3D = 0;
             switch (i) {
-                case  0: epsg = EPSG_PROJECTED_CS;                           break;      //  Cartesian   [E,N] in metres
+                case  0: epsg = 4400;                                        break;      //  Cartesian   [E,N] in metres
                 case  1: epsg = 1039;              unit = 9002;              break;      //  Cartesian   [E,N] in feet
                 case  2: epsg = 4497;              unit = 9003;              break;      //  Cartesian   [E,N] in US survey feet
                 case  3: epsg = 4403;              unit = 9005;              break;      //  Cartesian   [E,N] in Clarke feet
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index 3fdec31..aee1e41 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@ -1219,7 +1219,7 @@ codes:  for (int i=0; i<codes.length; i++) {
      * until a successful one is found.
      *
      * <p><strong>Note that this method may be ambiguous</strong> since the same EPSG code can be used for different
-     * kind of objects. This method throws an exception if it detects an ambiguity on a <em>best-effort</em> basis.
+     * kinds of objects. This method throws an exception if it detects an ambiguity on a <em>best-effort</em> basis.
      * It is recommended to invoke the most specific {@code createFoo(String)} method when the desired type is known,
      * both for performance reason and for avoiding ambiguity.</p>
      *
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java b/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java
index 9170dde..d38fa26 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java
@@ -44,7 +44,7 @@ import static org.apache.sis.test.ReferencingAssert.*;
 
 /**
  * Tests envelope transformations using either {@link Envelopes} or {@link Shapes2D} transform methods.
- * This base class allows us to perform the same tests on both kind of objects.
+ * This base class allows us to perform the same tests on both kinds of objects.
  * All tests performed by this class are two-dimensional.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
index 10c694b..cd64b83 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
@@ -30,13 +30,13 @@ import org.apache.sis.referencing.crs.DefaultGeographicCRS;
 import org.apache.sis.referencing.crs.DefaultProjectedCRS;
 import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
 import org.apache.sis.metadata.iso.extent.DefaultExtent;
-import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.Utilities;
 
 // Test imports
 import org.apache.sis.referencing.operation.HardCodedConversions;
 import org.apache.sis.referencing.crs.HardCodedCRS;
+import org.apache.sis.referencing.cs.HardCodedCS;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -161,7 +161,7 @@ public final strictfp class CRSTest extends TestCase {
          * different domain of validity. CRS[1] is given a domain large enough for all CRS except the last one.
          */
         final Map<String,Object> properties = new HashMap<>(4);
-        final CartesianCS cs = (CartesianCS) StandardDefinitions.createCoordinateSystem(Constants.EPSG_PROJECTED_CS);
+        final CartesianCS cs = HardCodedCS.PROJECTED;
         final ProjectedCRS[] crs = new ProjectedCRS[4];
         for (int i=0; i<crs.length; i++) {
             final CommonCRS baseCRS;
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java
index 4145b19..21a3666 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java
@@ -27,6 +27,10 @@ import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.crs.GeocentricCRS;
 import org.opengis.referencing.crs.ProjectedCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.cs.SphericalCS;
+import org.opengis.referencing.cs.CartesianCS;
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.datum.PrimeMeridian;
@@ -48,7 +52,7 @@ import static org.apache.sis.test.Assert.*;
  * Tests the {@link EPSGFactoryFallback} class.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.7
  * @module
  */
@@ -70,6 +74,12 @@ public final strictfp class EPSGFactoryFallbackTest extends TestCase {
                 EPSGFactoryFallback.INSTANCE.getAuthorityCodes(Ellipsoid.class));
         assertSetEquals(Arrays.asList("6326", "6322", "6269", "6267", "6258", "6230", "6019", "6047", "5100", "5103"),
                 EPSGFactoryFallback.INSTANCE.getAuthorityCodes(Datum.class));
+        assertSetEquals(Arrays.asList("6422", "6423"),
+                EPSGFactoryFallback.INSTANCE.getAuthorityCodes(EllipsoidalCS.class));
+        assertSetEquals(Arrays.asList("6404"),
+                EPSGFactoryFallback.INSTANCE.getAuthorityCodes(SphericalCS.class));
+        assertSetEquals(Arrays.asList("6500", "4400", "1026", "1027"),
+                EPSGFactoryFallback.INSTANCE.getAuthorityCodes(CartesianCS.class));
         assertSetEquals(Arrays.asList("4978", "4984", "4936"),
                 EPSGFactoryFallback.INSTANCE.getAuthorityCodes(GeocentricCRS.class));
         assertSetEquals(Arrays.asList("4326", "4322", "4019", "4047", "4269", "4267", "4258", "4230", "4979", "4985", "4937"),
@@ -77,7 +87,7 @@ public final strictfp class EPSGFactoryFallbackTest extends TestCase {
         assertSetEquals(Arrays.asList("5714", "5715", "5703"),
                 EPSGFactoryFallback.INSTANCE.getAuthorityCodes(VerticalCRS.class));
         /*
-         * There is two many ProjectedCRS codes for enumerating all of them, so test only a sampling.
+         * There is too many ProjectedCRS codes for enumerating all of them, so test only a sampling.
          */
         final Set<String> codes = EPSGFactoryFallback.INSTANCE.getAuthorityCodes(ProjectedCRS.class);
         assertTrue(codes.containsAll(Arrays.asList("5041", "5042", "32601", "32660", "32701", "32760")));
@@ -125,6 +135,18 @@ public final strictfp class EPSGFactoryFallbackTest extends TestCase {
     }
 
     /**
+     * Tests {@link EPSGFactoryFallback#createCoordinateSystem(String)}.
+     *
+     * @throws FactoryException if a CS can not be constructed.
+     */
+    @Test
+    public void testCreateCS() throws FactoryException {
+        verifyCreateCS(CommonCRS.DEFAULT.geographic(),   "6422");
+        verifyCreateCS(CommonCRS.DEFAULT.geographic3D(), "6423");
+        verifyCreateCS(CommonCRS.DEFAULT.spherical(),    "6404");
+    }
+
+    /**
      * Tests {@link EPSGFactoryFallback#createCoordinateReferenceSystem(String)}.
      *
      * @throws FactoryException if a CRS can not be constructed.
@@ -188,6 +210,18 @@ public final strictfp class EPSGFactoryFallbackTest extends TestCase {
     }
 
     /**
+     * Asserts that the result of {@link EPSGFactoryFallback#createObject(String)} is CS of the given CRS.
+     * Contrarily to other kinds of objects, coordinate systems are currently not cached. Consequently we
+     * can not assert that instances are the same.
+     */
+    private static void verifyCreateCS(final CoordinateReferenceSystem crs, final String code) throws FactoryException {
+        final CoordinateSystem expected = crs.getCoordinateSystem();
+        final CoordinateSystem actual = EPSGFactoryFallback.INSTANCE.createCoordinateSystem(code);
+        assertEquals(code, actual, EPSGFactoryFallback.INSTANCE.createObject(code));
+        assertEqualsIgnoreMetadata(expected, actual);
+    }
+
+    /**
      * Sets the EPSG factory to the given instance and clears the cache of all {@link CommonCRS} enumeration values.
      */
     private static void setEPSGFactory(final GeodeticAuthorityFactory factory) {
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/StandardDefinitionsTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/StandardDefinitionsTest.java
index 26f2858..842e8da 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/StandardDefinitionsTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/StandardDefinitionsTest.java
@@ -22,6 +22,7 @@ import org.opengis.referencing.crs.ProjectedCRS;
 import org.opengis.referencing.crs.VerticalCRS;
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.referencing.datum.Ellipsoid;
@@ -30,6 +31,7 @@ import org.opengis.referencing.datum.GeodeticDatum;
 import org.opengis.referencing.datum.VerticalDatum;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.internal.util.Constants;
+import org.apache.sis.measure.Units;
 
 // Test dependencies
 import org.apache.sis.referencing.datum.GeodeticDatumMock;
@@ -43,14 +45,14 @@ import org.apache.sis.referencing.cs.HardCodedCS;
 import org.apache.sis.referencing.datum.HardCodedDatum;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
+import static org.opengis.test.Assert.*;
 
 
 /**
  * Tests the {@link StandardDefinitions} class.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.4
  * @module
  */
@@ -71,6 +73,23 @@ public final strictfp class StandardDefinitionsTest extends TestCase {
     }
 
     /**
+     * Tests {@link StandardDefinitions#createCoordinateSystem(short, boolean)}.
+     *
+     * @since 1.0
+     */
+    @Test
+    @DependsOnMethod("testCreateAxis")
+    public void testCreateCoordinateSystem() {
+        CoordinateSystem cs = StandardDefinitions.createCoordinateSystem((short) 4400, true);
+        assertInstanceOf("projected", CartesianCS.class, cs);
+        assertEquals("dimension", 2, cs.getDimension());
+        assertEquals("unit",      Units.METRE,         cs.getAxis(0).getUnit());
+        assertEquals("unit",      Units.METRE,         cs.getAxis(1).getUnit());
+        assertEquals("direction", AxisDirection.EAST,  cs.getAxis(0).getDirection());
+        assertEquals("direction", AxisDirection.NORTH, cs.getAxis(1).getDirection());
+    }
+
+    /**
      * Tests {@link StandardDefinitions#createUniversal(int, GeographicCRS, boolean, double, double, CartesianCS)}
      * for a Universal Transverse Mercator (UTM) projection.
      *
@@ -128,7 +147,7 @@ public final strictfp class StandardDefinitionsTest extends TestCase {
     @DependsOnMethod("testCreateAxis")
     public void testCreateGeographicCRS() {
         final PrimeMeridian pm = StandardDefinitions.primeMeridian();
-        final EllipsoidalCS cs = (EllipsoidalCS) StandardDefinitions.createCoordinateSystem((short) 6422);
+        final EllipsoidalCS cs = (EllipsoidalCS) StandardDefinitions.createCoordinateSystem((short) 6422, true);
         for (final CommonCRS e : CommonCRS.values()) {
             final Ellipsoid ellipsoid = StandardDefinitions.createEllipsoid(e.ellipsoid);
             switch (e) {
@@ -179,14 +198,14 @@ public final strictfp class StandardDefinitionsTest extends TestCase {
     }
 
     /**
-     * Compares the values created by {@link StandardDefinitions#createAxis(short)} against the {@link HardCodedAxes}
-     * constants. Actually this is more a {@code HardCodedAxes} test than a {@code StandardDefinitions} one - in case
-     * of test failure, both classes could be at fault.
+     * Compares the values created by {@link StandardDefinitions#createAxis(short, boolean)} against the {@link HardCodedAxes}
+     * constants. Actually this is more a {@code HardCodedAxes} test than a {@code StandardDefinitions} one - in case of test
+     * failure, both classes could be at fault.
      */
     @Test
     public void testCreateAxis() {
         for (final short code : new short[] {1, 2, 60, 61, 62, 106, 107, 110, 114, 113}) {
-            final CoordinateSystemAxis actual = StandardDefinitions.createAxis(code);
+            final CoordinateSystemAxis actual = StandardDefinitions.createAxis(code, true);
             Validators.validate(actual);
             switch (code) {
                 case   1: compare(HardCodedAxes.EASTING,                actual); break;
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCartesianCSTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCartesianCSTest.java
index f297392..d918df8 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCartesianCSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCartesianCSTest.java
@@ -22,7 +22,6 @@ import org.opengis.test.Validators;
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.apache.sis.referencing.GeodeticObjectVerifier;
-import org.apache.sis.internal.util.Constants;
 import org.apache.sis.measure.Units;
 import org.apache.sis.test.xml.TestCase;
 import org.apache.sis.test.DependsOn;
@@ -216,9 +215,9 @@ public final strictfp class DefaultCartesianCSTest extends TestCase {
         final CoordinateSystemAxis N = cs.getAxis(1);
         assertEquals("name",    "Easting, northing (E,N)", cs.getName().getCode());
         assertEquals("remarks", "Used in ProjectedCRS.", cs.getRemarks().toString());
-        assertEpsgIdentifierEquals(String.valueOf(Constants.EPSG_PROJECTED_CS), getSingleton(cs.getIdentifiers()));
-        assertEpsgIdentifierEquals("1", getSingleton(E.getIdentifiers()));
-        assertEpsgIdentifierEquals("2", getSingleton(N.getIdentifiers()));
+        assertEpsgIdentifierEquals("4400", getSingleton(cs.getIdentifiers()));
+        assertEpsgIdentifierEquals("1",    getSingleton(E.getIdentifiers()));
+        assertEpsgIdentifierEquals("2",    getSingleton(N.getIdentifiers()));
         assertAxisEquals("Easting",  "E", AxisDirection.EAST,  Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Units.METRE, null, E);
         assertAxisEquals("Northing", "N", AxisDirection.NORTH, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Units.METRE, null, N);
         /*
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java
index afd1b0d..4f78385 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java
@@ -223,12 +223,6 @@ public final class Constants extends Static {
     public static final short EPSG_GREENWICH = 8901;
 
     /**
-     * The EPSG code for the two-dimensional Cartesian coordinate system with axes in metres.
-     * Cartesian 2D CS. Axes: easting, northing (E,N). Orientations: east, north. UoM: m.
-     */
-    public static final short EPSG_PROJECTED_CS = 4400;
-
-    /**
      * EPSG code of "WGS 84 / Arctic Polar Stereographic" projection.
      * Latitude of standard parallel is 71°N. All other parameters are zero.
      */
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/StandardDateFormat.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/StandardDateFormat.java
index 86ed80d..f058773 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/StandardDateFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/StandardDateFormat.java
@@ -103,7 +103,7 @@ public final class StandardDateFormat extends DateFormat {
             .toFormatter(Locale.ROOT);
 
     /**
-     * The kind of objects to get from calls to {@link #parseBest(CharSequence)}, in preference order.
+     * The kinds of objects to get from calls to {@link #parseBest(CharSequence)}, in preference order.
      * The time is converted to UTC timezone if possible.
      *
      * Tip: if we want to preserve the timezone instead than converting to UTC, we could try replacing
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java b/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
index 7a4d37b..3342adf 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
@@ -1305,7 +1305,7 @@ public class Cache<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V> {
      * error, so the default {@code Cache} behavior is to thrown an {@link IllegalStateException}
      * in such cases, typically when {@link Handler#putAndUnlock(Object)} is invoked. However in
      * some cases we may want to relax this check. For example the EPSG database sometime assigns
-     * the same key to different kind of objects.
+     * the same key to different kinds of objects.
      *
      * <p>If key collisions are allowed and two threads invoke {@link #lock(Object)} concurrently
      * for the same key, then the value to be stored in the map will be the one computed by the
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/package-info.java b/core/sis-utility/src/main/java/org/apache/sis/util/package-info.java
index 3124c80..c957633 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/package-info.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/package-info.java
@@ -32,7 +32,7 @@
  * <p>Some other noticeable services are:</p>
  * <ul>
  *   <li>{@link org.apache.sis.util.ObjectConverters}, together with the
- *       {@link org.apache.sis.util.ObjectConverter} interface, for converting various kind of objects.</li>
+ *       {@link org.apache.sis.util.ObjectConverter} interface, for converting various kinds of objects.</li>
  *   <li>{@link org.apache.sis.util.Utilities}, together with the
  *       {@link org.apache.sis.util.LenientComparable} interface, for comparing objects in various ways.</li>
  * </ul>
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/package-info.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/package-info.java
index 728ca50..dbd4be6 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/package-info.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/package-info.java
@@ -17,7 +17,7 @@
 
 /**
  * {@link org.apache.sis.storage.DataStore} implementation for XML files that can be (un)marshalled by the
- * {@link org.apache.sis.xml.XML} class. The kind of objects recognized by this package is listed in the
+ * {@link org.apache.sis.xml.XML} class. The kinds of objects recognized by this package is listed in the
  * {@link org.apache.sis.internal.storage.xml.Store} class.
  *
  * <p>This base package is designed for use with JAXB, which allows this package to be very small since most of the


Mime
View raw message