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

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

commit 3bb55654d2758254dd9dda8a4c956118bc2436fb
Merge: d8e3bc5a7f e79df9c2d3
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Tue Aug 5 15:29:44 2025 +0200

    Merge branch 'geoapi-4.0' into geoapi-3.1:
    
    Update the EPSG geodetic dataset from version 9.9.1 to version 12.013.
    This merge addresses only the code that read an existing database.
    Update of the code installing the database will be in a separated merge.
    
    Noticeable changes:
    
    * Removed tables: Area.
    * Added tables: ConventionalRS, DatumEnsemble, DatumEnsembleMember,
      DatumRealizationMethod, DefiningOperation, Extent, Scope, Usage.
    * The `SOURCE_GEOGCRS_CODE` column has been renamed `BASE_CRS_CODE`.
    
    The merge contains also work on GeoTIFF and on the geometry module 
(incubator).

 .../sis/buildtools/coding/ReorganizeImports.java   |    7 +-
 .../org.apache.sis.feature/main/module-info.java   |    3 +
 .../main/org/apache/sis/coverage/CategoryList.java |    2 +-
 .../org/apache/sis/coverage/SampleDimension.java   |   27 +-
 .../coverage/grid/CoordinateOperationFinder.java   |   43 +-
 .../apache/sis/coverage/grid/GridDerivation.java   |   53 +-
 .../org/apache/sis/coverage/grid/GridExtent.java   |    9 +-
 .../apache/sis/coverage/grid/SliceGeometry.java    |    2 +-
 .../main/org/apache/sis/coverage/package-info.java |    2 +-
 .../org/apache/sis/feature/DefaultFeatureType.java |    2 +-
 .../main/org/apache/sis/feature/Features.java      |    4 +-
 .../main/org/apache/sis/filter/Optimization.java   |    6 +-
 .../main/org/apache/sis/filter/PropertyValue.java  |    2 +-
 .../main/org/apache/sis/filter/TemporalFilter.java |    2 +-
 .../main/org/apache/sis/image/PixelIterator.java   |    2 +-
 .../main/org/apache/sis/image/TransferType.java    |    6 +-
 .../main/org/apache/sis/image/Transferer.java      |    2 +-
 .../sis/coverage/grid/GridDerivationTest.java      |   49 +
 .../org/apache/sis/feature/FeatureTestCase.java    |    6 +-
 .../sis/filter/privy/ValueReferenceMock.java       |    2 +-
 .../org/apache/sis/metadata/MetadataStandard.java  |    2 +-
 .../org/apache/sis/metadata/MetadataVisitor.java   |    2 +-
 .../org/apache/sis/metadata/TreeTableView.java     |    2 +-
 .../sis/metadata/internal/CitationConstant.java    |    2 +-
 .../sis/metadata/iso/citation/Citations.java       |    2 +-
 .../metadata/iso/extent/DefaultVerticalExtent.java |   18 +-
 .../apache/sis/metadata/iso/extent/Extents.java    |   14 +-
 .../DefaultRepresentativeFraction.java             |    4 +-
 .../iso/maintenance/DefaultScopeDescription.java   |    6 +-
 .../org/apache/sis/metadata/sql/Dispatcher.java    |    2 +-
 .../org/apache/sis/temporal/LenientDateFormat.java |    4 +-
 .../apache/sis/util/iso/DefaultNameFactory.java    |    6 +-
 .../main/org/apache/sis/util/iso/Types.java        |    2 +-
 .../apache/sis/temporal/LenientDateFormatTest.java |    4 +
 .../apache/sis/profile/japan/netcdf/GCOM_C.java    |    4 +-
 .../sis/geometry/AbstractDirectPosition.java       |    2 +-
 .../org/apache/sis/geometry/AbstractEnvelope.java  |    2 +-
 .../main/org/apache/sis/geometry/Envelopes.java    |  102 +-
 .../apache/sis/geometry/WraparoundInEnvelope.java  |  171 +-
 .../main/org/apache/sis/io/wkt/Formatter.java      |    2 +-
 .../apache/sis/io/wkt/GeodeticObjectParser.java    |   11 +-
 .../sis/parameter/DefaultParameterDescriptor.java  |    2 +
 .../sis/parameter/DefaultParameterValue.java       |    4 +-
 .../main/org/apache/sis/parameter/Parameters.java  |    4 +-
 .../main/org/apache/sis/parameter/Verifier.java    |   81 +-
 .../sis/referencing/AbstractIdentifiedObject.java  |    2 +-
 .../main/org/apache/sis/referencing/Builder.java   |    2 +-
 .../main/org/apache/sis/referencing/CRS.java       |   22 +-
 .../apache/sis/referencing/NamedIdentifier.java    |    2 +-
 .../sis/referencing/crs/DefaultGeodeticCRS.java    |   24 +-
 .../referencing/datum/DefaultDatumEnsemble.java    |  122 +-
 .../referencing/datum/DefaultGeodeticDatum.java    |   16 +-
 .../referencing/datum/DefaultVerticalDatum.java    |    6 +-
 .../referencing/factory/AuthorityFactoryProxy.java |   11 +
 .../factory/ConcurrentAuthorityFactory.java        |   28 +-
 .../factory/GeodeticAuthorityFactory.java          |  143 +-
 .../referencing/factory/GeodeticObjectFactory.java |    3 -
 .../factory/IdentifiedObjectFinder.java            |    2 +-
 .../referencing/factory/IdentifiedObjectSet.java   |   77 +-
 .../referencing/factory/sql/AuthorityCodes.java    |    6 +-
 .../sis/referencing/factory/sql/AxisName.java      |   18 +-
 .../sis/referencing/factory/sql/BursaWolfInfo.java |  210 --
 .../factory/sql/CoordinateOperationSet.java        |   21 +-
 .../referencing/factory/sql/EPSGCodeFinder.java    |   20 +-
 .../referencing/factory/sql/EPSGDataAccess.java    | 2601 +++++++++++---------
 .../sis/referencing/factory/sql/EPSGFactory.java   |    4 +-
 .../sis/referencing/factory/sql/EPSG_Finish.sql    |    2 +-
 .../sis/referencing/factory/sql/EPSG_Prepare.sql   |   18 +-
 .../referencing/factory/sql/ObjectPertinence.java  |  154 ++
 .../sis/referencing/factory/sql/SQLTranslator.java |  424 ++--
 .../sis/referencing/factory/sql/TableInfo.java     |   61 +-
 .../org/apache/sis/referencing/internal/Epoch.java |    2 -
 .../internal/ParameterizedTransformBuilder.java    |    9 +
 .../internal/PositionalAccuracyConstant.java       |   40 +-
 .../referencing/internal/VerticalDatumTypes.java   |   80 +-
 .../operation/CoordinateOperationContext.java      |   28 +-
 .../operation/CoordinateOperationFinder.java       |   27 +-
 .../operation/CoordinateOperationRegistry.java     |    2 +-
 .../DefaultCoordinateOperationFactory.java         |   31 +-
 .../referencing/operation/SubOperationInfo.java    |   13 +-
 .../referencing/operation/gridded/LoadedGrid.java  |    2 +-
 .../operation/matrix/AffineTransforms2D.java       |    6 +-
 .../sis/referencing/operation/matrix/Matrix1.java  |    2 +-
 .../sis/referencing/operation/matrix/Matrix2.java  |    2 +-
 .../sis/referencing/operation/matrix/Matrix3.java  |    2 +-
 .../sis/referencing/operation/matrix/Matrix4.java  |    2 +-
 .../referencing/operation/matrix/MatrixSIS.java    |    2 +-
 .../referencing/operation/provider/Wraparound.java |    2 +-
 .../operation/transform/MolodenskyTransform.java   |    2 +-
 .../operation/transform/WraparoundTransform.java   |    4 +-
 .../referencing/privy/CoordinateOperations.java    |    5 -
 .../org/apache/sis/geometry/EnvelopesTest.java     |   12 +-
 .../datum/DefaultGeodeticDatumTest.java            |    2 +-
 .../referencing/factory/sql/EPSGFactoryTest.java   |   36 +-
 .../sis/referencing/factory/sql/TableInfoTest.java |   10 +-
 .../internal/VerticalDatumTypesTest.java           |   33 +-
 .../InterpolatedGeocentricTransformTest.java       |    2 +-
 .../storage/landsat/LandsatStoreProviderTest.java  |    2 +-
 .../apache/sis/storage/geotiff/GeoTiffStore.java   |    4 +-
 .../org/apache/sis/storage/geotiff/Reader.java     |    2 +-
 .../org/apache/sis/storage/geotiff/writer/ZIP.java |   28 +-
 .../org/apache/sis/storage/geotiff/WriterTest.java |   41 +-
 .../apache/sis/storage/netcdf/base/Convention.java |   30 +-
 .../sis/storage/netcdf/base/GridMapping.java       |  135 +-
 .../org/apache/sis/storage/netcdf/base/Node.java   |    4 +-
 .../apache/sis/io/stream/HyperRectangleWriter.java |   54 +-
 .../sis/io/stream/SubsampledRectangleWriter.java   |   26 +-
 .../org/apache/sis/io/stream/UpdatableWrite.java   |    2 +-
 .../org/apache/sis/storage/StorageConnector.java   |    8 +-
 .../aggregate/BandAggregateGridResource.java       |    2 +-
 .../aggregate/ConcatenatedGridResource.java        |    2 +-
 .../sis/storage/aggregate/CoverageAggregator.java  |    2 +-
 .../sis/storage/base/MemoryGridResource.java       |   29 +-
 .../storage/image/WritableSingleImageStore.java    |    2 +-
 .../org/apache/sis/storage/CoverageSubsetTest.java |    2 +-
 .../aggregate/BandAggregateGridResourceTest.java   |    2 +-
 .../sis/storage/aggregate/OpaqueGridResource.java  |    2 +-
 .../sis/storage/base/MemoryGridResourceTest.java   |    2 +-
 .../apache/sis/storage/csv/StoreProviderTest.java  |    2 +-
 .../sis/storage/esri/AsciiGridStoreTest.java       |    2 +-
 .../sis/storage/image/WorldFileStoreTest.java      |    2 +-
 .../apache/sis/storage/wkt/StoreProviderTest.java  |    2 +-
 .../test/org/apache/sis/storage/wkt/StoreTest.java |    2 +-
 .../apache/sis/storage/xml/StoreProviderTest.java  |    2 +-
 .../test/org/apache/sis/storage/xml/StoreTest.java |    2 +-
 .../main/org/apache/sis/math/ArrayVector.java      |    4 +-
 .../main/org/apache/sis/math/DecimalFunctions.java |    2 +-
 .../main/org/apache/sis/math/Vector.java           |    6 +-
 .../main/org/apache/sis/measure/DerivedScalar.java |    4 +-
 .../org/apache/sis/measure/MeasurementRange.java   |    6 +-
 .../main/org/apache/sis/measure/NumberRange.java   |   14 +-
 .../main/org/apache/sis/measure/Scalar.java        |   10 +-
 .../main/org/apache/sis/setup/GeometryLibrary.java |   18 +
 .../main/org/apache/sis/system/Semaphores.java     |    2 +-
 .../main/org/apache/sis/util/ArgumentChecks.java   |    2 +-
 .../main/org/apache/sis/util/ArraysExt.java        |   20 +-
 .../main/org/apache/sis/util/Numbers.java          |    6 +-
 .../main/org/apache/sis/util/collection/Cache.java |   11 +-
 .../org/apache/sis/util/collection/Containers.java |    8 +-
 .../sis/util/collection/DefaultTreeTable.java      |    2 +-
 .../main/org/apache/sis/util/privy/Constants.java  |   10 +-
 .../main/org/apache/sis/util/privy/Numerics.java   |    2 +-
 .../org/apache/sis/util/resources/Vocabulary.java  |    5 +
 .../sis/util/resources/Vocabulary.properties       |    1 +
 .../sis/util/resources/Vocabulary_fr.properties    |    1 +
 .../test/org/apache/sis/math/VectorTest.java       |    2 +-
 .../org/apache/sis/measure/SystemUnitTest.java     |    2 +-
 .../geometries/{Polygon.java => CurvePolygon.java} |   25 +-
 .../org/apache/sis/geometries/GeometryFactory.java |  160 +-
 .../org/apache/sis/geometries/MultiPolygon.java    |    2 +-
 .../main/org/apache/sis/geometries/Polygon.java    |    9 +-
 .../main/org/apache/sis/geometries/Triangle.java   |    2 +-
 .../main/org/apache/sis/geometries/Wrapper.java    |  469 ++++
 .../org/apache/sis/geometries/math/Matrix2D.java   |    2 +-
 .../org/apache/sis/geometries/math/Matrix3D.java   |    2 +-
 .../org/apache/sis/geometries/math/Matrix4D.java   |    2 +-
 .../main/org/apache/sis/geometries/math/Tuple.java |    8 +-
 .../org/apache/sis/geometries/math/TupleArray.java |   20 +-
 .../sis/geometries/privy/DefaultPolygon.java       |    8 +-
 .../processor/spatialedition/Transform.java        |    8 +-
 .../processor/spatialrelations2d/Contains.java     |   11 +-
 .../sis/geometries/triangulate/EarClipping.java    |   14 +-
 .../coveragejson/CoverageJsonStoreTest.java        |    2 +-
 .../apache/sis/gui/coverage/CoverageCanvas.java    |   10 +-
 .../referencing/factory/sql/epsg/DebugTools.sql    |    2 +-
 .../sis/referencing/factory/sql/epsg/README.md     |    1 +
 166 files changed, 4142 insertions(+), 2191 deletions(-)

diff --cc 
endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java
index 9e61cd69a9,c3237e3320..f6653ddeee
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java
@@@ -215,29 -203,28 +215,30 @@@ public class DefaultScopeDescription ex
      }
  
      /**
-      * Returns the given value casted to a {@code Set} of elements of the 
given type.
 -     * Returns the given value cast to a {@code Set<CharSequence>}.
++     * Returns the given value cast to a {@code Set} of elements of the given 
type.
 +     * It is caller responsibility to ensure that the cast is valid, as 
element type
 +     * is verified only when assertions are enabled.
       */
      @SuppressWarnings("unchecked")
 -    private static Set<CharSequence> cast(final Object value) {
 +    private static <E> Set<E> cast(final Object value, final Class<E> type) {
          assert !(value instanceof CheckedContainer<?>) ||
 -                ((CheckedContainer<?>) value).getElementType() == 
CharSequence.class;
 -        return (Set<CharSequence>) value;
 +                ((CheckedContainer<?>) value).getElementType() == type;
 +        return (Set<E>) value;
      }
  
      /**
       * Returns the set of properties identified by the {@code code} argument,
       * or an unmodifiable empty set if another value is defined.
       */
 -    private Set<CharSequence> getProperty(final byte code) {
 +    private <E> Set<E> getProperty(final Class<E> type, final byte code) {
+         @SuppressWarnings("LocalVariableHidesMemberVariable")
          final Object value = this.value;
          if (value != null) {
              if (property == code) {
 -                return cast(value);
 +                return cast(value, type);
              } else if (!(value instanceof Set) || !((Set<?>) 
value).isEmpty()) {
                  return Semaphores.query(Semaphores.NULL_COLLECTION)
-                        ? null : new ExcludedSet<E>(NAMES[code-1], 
NAMES[property-1]);
+                        ? null : new ExcludedSet<>(NAMES[code-1], 
NAMES[property-1]);
              }
          }
          /*
@@@ -562,6 -509,6 +563,7 @@@
       *
       * @since 1.0
       */
++    @SuppressWarnings("deprecation")
      public void setLevelDescription(final ScopeCode level, final Set<? 
extends CharSequence> newValues) {
          if (level == ScopeCode.DATASET) {
              String description = null;
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java
index ab1f8c95bf,796b7abe65..e473ae0c0f
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java
@@@ -1443,12 -1445,13 +1444,12 @@@ class GeodeticObjectParser extends Math
              return null;
          }
          final String name = element.pullString("name");
 -        @SuppressWarnings("deprecation")
          RealizationMethod method = null;
          if (isWKT1) {
-             method = 
VerticalDatumTypes.fromLegacy(element.pullInteger("datum"));
+             method = 
VerticalDatumTypes.fromLegacyCode(element.pullInteger("datum"));
          }
          if (method == null) {
-             method = VerticalDatumTypes.guess(name, null, null);
+             method = VerticalDatumTypes.fromDatum(name, null, null);
          }
          final DatumFactory datumFactory = factories.getDatumFactory();
          try {
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultVerticalDatum.java
index d5da02669e,0d27307af2..8ba7eb177d
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultVerticalDatum.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultVerticalDatum.java
@@@ -428,7 -368,7 +430,7 @@@ public class DefaultVerticalDatum exten
      protected String formatTo(final Formatter formatter) {
          super.formatTo(formatter);
          if (formatter.getConvention().majorVersion() == 1) {
-             
formatter.append(VerticalDatumTypes.toLegacy(getVerticalDatumType()));
 -            formatter.append(VerticalDatumTypes.toLegacyCode(method));
++            
formatter.append(VerticalDatumTypes.toLegacyCode(getVerticalDatumType()));
              return WKTKeywords.Vert_Datum;
          }
          return formatter.shortOrLong(WKTKeywords.VDatum, 
WKTKeywords.VerticalDatum);
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java
index e1eeacb925,5f8fd800ea..955389f63f
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java
@@@ -1115,35 -1092,34 +1115,61 @@@ public abstract class ConcurrentAuthori
          return create(AuthorityFactoryProxy.ENGINEERING_CRS, code);
      }
  
 +    /**
 +     * Returns a 2-dimensional engineering coordinate reference system 
applied to locations in images.
 +     * The default implementation performs the following steps:
 +     * <ul>
 +     *   <li>Return the cached instance for the given code if such instance 
already exists.</li>
 +     *   <li>Otherwise if the Data Access Object (DAO) overrides the {@code 
createImageCRS(String)}
 +     *       method, invoke that method and cache the result for future 
use.</li>
 +     *   <li>Otherwise delegate to the {@link 
GeodeticAuthorityFactory#createImageCRS(String)}
 +     *       method in the parent class. This allows to check if the more 
generic
 +     *       {@link #createCoordinateReferenceSystem(String)} method cached a 
value before to try that method.</li>
 +     * </ul>
 +     *
 +     * @return the coordinate reference system for the given code.
 +     * @throws FactoryException if the object creation failed.
 +     *
 +     * @deprecated The {@code ImageCRS} class has been removed in ISO 
19111:2019.
 +     *             It is replaced by {@code EngineeringCRS}.
 +     */
 +    @Override
 +    @Deprecated(since = "1.5")
 +    public ImageCRS createImageCRS(final String code) throws FactoryException 
{
 +        if (isDefault(ImageCRS.class)) {
 +            return super.createImageCRS(code);
 +        }
 +        return create(AuthorityFactoryProxy.IMAGE_CRS, code);
 +    }
 +
      /**
-      * Returns an arbitrary datum from a code. The returned object will 
typically be an
+      * Returns an arbitrary datum ensemble from a code.
+      * The default implementation performs the following steps:
+      * <ul>
+      *   <li>Return the cached instance for the given code if such instance 
already exists.</li>
+      *   <li>Otherwise if the Data Access Object (DAO) overrides the {@code 
createDatumEnsemble(String)}
+      *       method, invoke that method and cache the result for future 
use.</li>
+      *   <li>Otherwise delegate to the {@link 
GeodeticAuthorityFactory#createDatumEnsemble(String)}
+      *       method in the parent class. This allows to check if the more 
generic
+      *       {@link #createObject(String)} method cached a value before to 
try that method.</li>
+      * </ul>
+      *
+      * @return the datum for the given code.
+      * @throws FactoryException if the object creation failed.
+      *
+      * @since 1.5
+      */
+     @Override
+     public DatumEnsemble<?> createDatumEnsemble(final String code) throws 
FactoryException {
+         if (isDefault(DatumEnsemble.class)) {
+             return super.createDatumEnsemble(code);
+         }
+         return create(AuthorityFactoryProxy.ENSEMBLE, code);
+     }
+ 
+     /**
+      * Returns an arbitrary datum from a code. The returned object will 
typically be a
+      * {@link GeodeticDatum}, {@link VerticalDatum}, {@link TemporalDatum} or 
{@link EngineeringDatum}.
       * The default implementation performs the following steps:
       * <ul>
       *   <li>Return the cached instance for the given code if such instance 
already exists.</li>
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
index 8185386ed5,09cd80a83e..c684889ab8
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
@@@ -541,30 -526,46 +543,70 @@@ public abstract class GeodeticAuthority
          return cast(EngineeringCRS.class, 
createCoordinateReferenceSystem(code), code);
      }
  
 +    /**
 +     * Creates a 2-dimensional engineering coordinate reference system 
applied to locations in images.
 +     * Image coordinate reference systems are treated as a separate sub-type 
because a separate
 +     * user community exists for images with its own terms of reference.
 +     *
 +     * <h4>Default implementation</h4>
 +     * The default implementation delegates to {@link 
#createCoordinateReferenceSystem(String)} and casts the result.
-      * If the result cannot be casted, then a {@link 
NoSuchAuthorityCodeException} is thrown.
++     * If the result cannot be cast, then a {@link 
NoSuchAuthorityCodeException} is thrown.
 +     *
 +     * @param  code  value allocated by authority.
 +     * @return the coordinate reference system for the given code.
 +     * @throws NoSuchAuthorityCodeException if the specified {@code code} was 
not found.
 +     * @throws FactoryException if the object creation failed for some other 
reason.
 +     *
 +     * @see org.apache.sis.referencing.crs.DefaultImageCRS
 +     *
 +     * @deprecated The {@code ImageCRS} class has been removed in ISO 
19111:2019.
 +     *             It is replaced by {@code EngineeringCRS}.
 +     */
 +    @Deprecated(since = "1.5")
 +    public ImageCRS createImageCRS(final String code) throws 
NoSuchAuthorityCodeException, FactoryException {
 +        return cast(ImageCRS.class, createCoordinateReferenceSystem(code), 
code);
 +    }
 +
+     /**
+      * Creates an arbitrary datum ensemble from a code.
+      * A datum ensemble is a collection of datums which for low accuracy 
requirements
+      * may be considered to be insignificantly different from each other.
+      *
+      * <h4>Examples</h4>
+      * The {@linkplain #getAuthorityCodes(Class) set of available codes} 
depends on the defining
+      * {@linkplain #getAuthority() authority} and the {@code 
GeodeticAuthorityFactory} subclass in use.
+      * A frequently used authority is "EPSG", which includes the following 
codes:
+      *
+      * <table class="sis">
+      * <caption>Authority codes examples</caption>
+      *   <tr><th>Code</th>      <th>Description</th></tr>
+      *   <tr><td>EPSG:6326</td> <td>World Geodetic System 1984</td></tr>
+      *   <tr><td>EPSG:6258</td> <td>European Terrestrial Reference System 
1989</td></tr>
+      * </table>
+      *
+      * <h4>Default implementation</h4>
+      * The default implementation delegates to {@link #createDatum(String)} 
and casts the result.
+      * If the result cannot be cast, then a {@link 
NoSuchAuthorityCodeException} is thrown.
+      * This approach assumes that the datum ensemble implements also the 
{@link Datum} interface.
+      * It is the case of the {@link 
org.apache.sis.referencing.datum.DefaultDatumEnsemble} class.
+      *
+      * <p>This default implementation is unusual, but is convenient for the 
implementation strategy
+      * of Apache <abbr>SIS</abbr> and for the structure of the 
<abbr>EPSG</abbr> geodetic dataset,
+      * which uses the same {@code "Datum"} table for storing the properties 
of the two kinds of object.</p>
+      *
+      * @param  code  value allocated by authority.
+      * @return the datum ensemble for the given code.
+      * @throws NoSuchAuthorityCodeException if the specified {@code code} was 
not found.
+      * @throws FactoryException if the object creation failed for some other 
reason.
+      *
+      * @see org.apache.sis.referencing.datum.DefaultDatumEnsemble
+      *
+      * @since 1.5
+      */
+     public DatumEnsemble<?> createDatumEnsemble(final String code) throws 
NoSuchAuthorityCodeException, FactoryException {
+         return cast(DatumEnsemble.class, createDatum(code), code);
+     }
+ 
      /**
       * Creates an arbitrary datum from a code. The returned object will 
typically be an
       * instance of {@link GeodeticDatum}, {@link VerticalDatum} or {@link 
TemporalDatum}.
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java
index a67aad7de8,f289b0f33e..be28e30680
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java
@@@ -109,10 -110,9 +110,10 @@@ final class CoordinateOperationSet exte
      }
  
      /**
-      * Creates a coordinate operation for the specified EPSG code.
+      * Creates a coordinate operation for the specified <abbr>EPSG</abbr> 
code.
       */
      @Override
 +    @SuppressWarnings("deprecation")
      protected CoordinateOperation createObject(final String code) throws 
FactoryException {
          final Integer base = projections.get(code);
          if (base != null) {
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
index 55553fc50f,47975c6b37..f250ecf703
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
@@@ -318,8 -319,8 +319,8 @@@ crs:    if (isInstance(CoordinateRefere
               *     ORDER BY COORD_REF_SYS_CODE
               */
              final Condition filter;
 -            if (object instanceof DerivedCRS) {              // No need to 
use isInstance(Class, Object) from here.
 -                filter = dependencies("BASE_CRS_CODE", SingleCRS.class, 
((DerivedCRS) object).getBaseCRS(), true);
 +            if (object instanceof GeneralDerivedCRS) {              // No 
need to use isInstance(Class, Object) from here.
-                 filter = dependencies("SOURCE_GEOGCRS_CODE", 
CoordinateReferenceSystem.class, ((GeneralDerivedCRS) object).getBaseCRS(), 
true);
++                filter = dependencies("BASE_CRS_CODE", 
CoordinateReferenceSystem.class, ((GeneralDerivedCRS) object).getBaseCRS(), 
true);
              } else if (object instanceof GeodeticCRS) {
                  filter = dependencies("DATUM_CODE", GeodeticDatum.class, 
((GeodeticCRS) object).getDatum(), true);
              } else if (object instanceof VerticalCRS) {
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index 34ca685020,59997d0496..cf8ecff2c0
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@@ -1477,47 -1714,74 +1715,74 @@@ search: try (ResultSet result = execute
                                   * We need to check if EPSG database 10+ has 
more specific information.
                                   * See 
https://issues.apache.org/jira/browse/SIS-518
                                   */
-                                 
@SuppressWarnings("LocalVariableHidesMemberVariable")
-                                 final Map<String,Object> properties = 
createProperties("Coordinate Reference System",
-                                                                         name, 
epsg, area, scope, remarks, deprecated);
 -                                if (baseCRS instanceof GeodeticCRS) {
 -                                    return 
factory.createProjectedCRS(metadata, (GeodeticCRS) baseCRS, fromBase, cs);
 +                                if (baseCRS instanceof GeographicCRS) {
-                                     crs = 
crsFactory.createProjectedCRS(properties, (GeographicCRS) baseCRS, op, cs);
++                                    return 
factory.createProjectedCRS(metadata, (GeographicCRS) baseCRS, fromBase, cs);
                                  } else {
-                                     crs = 
crsFactory.createDerivedCRS(properties, baseCRS, op, cs);
+                                     return factory.createDerivedCRS(metadata, 
baseCRS, fromBase, cs);
                                  }
                              } finally {
-                                 
Semaphores.clear(Semaphores.SUSPEND_PARAMETER_CHECK, suspendParamChecks);
+                                 
Semaphores.clearIfFalse(Semaphores.SUSPEND_PARAMETER_CHECK, old);
                              }
-                         } finally {
-                             endOfRecursion(ProjectedCRS.class, epsg);
-                         }
+                         };
                          break;
                      }
-                     /* 
----------------------------------------------------------------------
+                     /* 
──────────────────────────────────────────────────────────────────────
                       *   VERTICAL CRS
-                      * 
---------------------------------------------------------------------- */
+                      * 
────────────────────────────────────────────────────────────────────── */
                      case "vertical": {
-                         final VerticalCS    cs    = owner.createVerticalCS   
(getString(code, result, 8));
-                         final VerticalDatum datum = 
owner.createVerticalDatum(getString(code, result, 9));
-                         crs = 
crsFactory.createVerticalCRS(createProperties("Coordinate Reference System",
-                                 name, epsg, area, scope, remarks, 
deprecated), datum, cs);
+                         final String csCode    = getString(code, result, 8);
+                         final String datumCode = getString(code, result, 9);
+                         final VerticalCS cs = owner.createVerticalCS(csCode); 
  // Do not inline the `getString(…)` calls.
+                         final VerticalDatum datumOrEnsemble = 
owner.createVerticalDatum(datumCode);
+                         final DatumEnsemble<VerticalDatum> ensemble = 
wasDatumEnsemble(datumOrEnsemble, VerticalDatum.class);
+                         final VerticalDatum datum = (ensemble == null) ? 
datumOrEnsemble : null;
+                         constructor = (factory, metadata) -> 
factory.createVerticalCRS(metadata, datum, ensemble, cs);
                          break;
                      }
-                     /* 
----------------------------------------------------------------------
+                     /* 
──────────────────────────────────────────────────────────────────────
                       *   TEMPORAL CRS
                       *
-                      *   NOTE : The original EPSG database does not define 
any temporal CRS.
-                      *          This block is a SIS-specific extension.
-                      * 
---------------------------------------------------------------------- */
+                      *   NOTE : As of version 12, the EPSG database does not 
define temporal CRS.
+                      *          This block is a SIS─specific extension.
+                      * 
────────────────────────────────────────────────────────────────────── */
                      case "time":
                      case "temporal": {
-                         final TimeCS        cs    = owner.createTimeCS       
(getString(code, result, 8));
-                         final TemporalDatum datum = 
owner.createTemporalDatum(getString(code, result, 9));
-                         crs = 
crsFactory.createTemporalCRS(createProperties("Coordinate Reference System",
-                                 name, epsg, area, scope, remarks, 
deprecated), datum, cs);
+                         final String csCode    = getString(code, result, 8);
+                         final String datumCode = getString(code, result, 9);
+                         final TimeCS cs = owner.createTimeCS(csCode);    // 
Do not inline the `getString(…)` calls.
+                         final TemporalDatum datumOrEnsemble = 
owner.createTemporalDatum(datumCode);
+                         final DatumEnsemble<TemporalDatum> ensemble = 
wasDatumEnsemble(datumOrEnsemble, TemporalDatum.class);
+                         final TemporalDatum datum = (ensemble == null) ? 
datumOrEnsemble : null;
+                         constructor = (factory, metadata) -> 
factory.createTemporalCRS(metadata, datum, ensemble, cs);
+                         break;
+                     }
+                     /* 
──────────────────────────────────────────────────────────────────────
+                      *   ENGINEERING CRS
+                      * 
────────────────────────────────────────────────────────────────────── */
+                     case "engineering": {
+                         final String csCode    = getString(code, result, 8);
+                         final String datumCode = getString(code, result, 9);
+                         final CoordinateSystem cs = 
owner.createCoordinateSystem(csCode);    // Do not inline the `getString(…)` 
calls.
+                         final EngineeringDatum datumOrEnsemble = 
owner.createEngineeringDatum(datumCode);
+                         final DatumEnsemble<EngineeringDatum> ensemble = 
wasDatumEnsemble(datumOrEnsemble, EngineeringDatum.class);
+                         final EngineeringDatum datum = (ensemble == null) ? 
datumOrEnsemble : null;
+                         constructor = (factory, metadata) -> 
factory.createEngineeringCRS(metadata, datum, ensemble, cs);
                          break;
                      }
-                     /* 
----------------------------------------------------------------------
+                     /* 
──────────────────────────────────────────────────────────────────────
+                      *   PARAMETRIC CRS
+                      * 
────────────────────────────────────────────────────────────────────── */
+                     case "parametric": {
+                         final String csCode    = getString(code, result, 8);
+                         final String datumCode = getString(code, result, 9);
+                         final ParametricCS cs = 
owner.createParametricCS(csCode);    // Do not inline the `getString(…)` calls.
+                         final ParametricDatum datumOrEnsemble = 
owner.createParametricDatum(datumCode);
+                         final DatumEnsemble<ParametricDatum> ensemble = 
wasDatumEnsemble(datumOrEnsemble, ParametricDatum.class);
+                         final ParametricDatum datum = (ensemble == null) ? 
datumOrEnsemble : null;
+                         constructor = (factory, metadata) -> 
factory.createParametricCRS(metadata, datum, ensemble, cs);
+                         break;
+                     }
+                     /* 
──────────────────────────────────────────────────────────────────────
                       *   COMPOUND CRS
                       *
                       *   NOTE: This method invokes itself recursively.
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/VerticalDatumTypes.java
index b28513be42,ecea0315c6..8eef7854ae
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/VerticalDatumTypes.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/VerticalDatumTypes.java
@@@ -24,18 -24,16 +24,19 @@@ import org.opengis.referencing.cs.Coord
  import org.opengis.referencing.cs.AxisDirection;
  import org.apache.sis.util.Characters;
  import org.apache.sis.util.CharSequences;
+ import org.apache.sis.util.privy.CodeLists;
  import org.apache.sis.measure.Units;
  
 +// Specific to the main and geoapi-3.1 branches:
 +import org.opengis.referencing.datum.VerticalDatumType;
 +
  // Specific to the geoapi-3.1 and geoapi-4.0 branches:
  import org.opengis.referencing.datum.RealizationMethod;
  
  
  /**
-  * Extensions to the standard set of {@link RealizationEpoch}.
+  * Extensions to the standard set of {@link RealizationMethod}.
 - * Some of those constants are derived from a legacy {@code 
VerticalDatumType} code list.
 + * Some of those constants are derived from a legacy {@link 
VerticalDatumType} code list.
   * Those constants are not in public API because they were intentionally 
omitted from ISO 19111,
   * and the ISO experts said that they should really not be public.
   *
@@@ -132,13 -139,12 +138,13 @@@ public final class VerticalDatumTypes 
       * Returns the legacy code for the datum type, or 2000 (other surface) if 
unknown.
       * This method is used for WKT 1 formatting.
       *
-      * @param  type  the vertical datum type, or {@code null} if unknown.
 -     * @param  method  the realization method, or {@code null} if unknown.
++     * @param  method  the vertical datum type, or {@code null} if unknown.
       * @return the legacy code for the given datum type, or 0 if unknown.
       */
 -    public static int toLegacyCode(final RealizationMethod method) {
 +    @SuppressWarnings("deprecation")
-     public static int toLegacy(final VerticalDatumType type) {
-         if (type != null) {
-             switch (type.name().toUpperCase(Locale.US)) {
++    public static int toLegacyCode(final VerticalDatumType method) {
+         if (method != null) {
+             switch (method.name().toUpperCase(Locale.US)) {
                  case ORTHOMETRIC: return 2001;      // CS_VD_Orthometric
                  case ELLIPSOIDAL: return 2002;      // CS_VD_Ellipsoidal
                  case BAROMETRIC:  return 2003;      // 
CS_VD_AltitudeBarometric
@@@ -155,38 -161,55 +161,74 @@@
       * This is because the vertical datum type was a mandatory property in 
legacy OGC/ISO standards.
       * This method is used for writing GML documents older than GML 3.2.
       *
++     * <p>Note: this is renamed {@code toLegacyName(RealizationMethod)} on 
the GeoAPI 4.0 branch.</p>
++     *
       * @param  method  the realization method, or {@code null}.
 -     * @return the vertical datum type name (never null).
 +     * @return the vertical datum type (never null).
       */
 -    public static String toLegacyName(final RealizationMethod method) {
 -        if (method == RealizationMethod.GEOID) return "geoidal";
 -        if (method == RealizationMethod.TIDAL) return "depth";
 +    @SuppressWarnings("deprecation")
 +    public static VerticalDatumType fromMethod(final RealizationMethod 
method) {
 +        if (method == RealizationMethod.GEOID) return 
VerticalDatumType.GEOIDAL;
 +        if (method == RealizationMethod.TIDAL) return VerticalDatumType.DEPTH;
          if (method != null) {
 -            return method.name().toLowerCase(Locale.US);
 +            return 
VerticalDatumType.valueOf(method.name().toUpperCase(Locale.US));
          }
 -        return "other surface";
 +        return VerticalDatumType.OTHER_SURFACE;
 +    }
 +
 +    /**
 +     * Returns the realization method from a vertical datum type.
 +     * This method is used for reading GML documents older than GML 3.2.
 +     *
++     * <p>Note: this is renamed {@code fromLegacyName(String)} on the GeoAPI 
4.0 branch.</p>
++     *
 +     * @param  type  the vertical datum type, or {@code null}.
 +     * @return the realization method, or {@code null} if none.
 +     */
 +    @SuppressWarnings("deprecation")
 +    public static RealizationMethod toMethod(final VerticalDatumType type) {
-         if (type != null) {
-             if (type == VerticalDatumType.GEOIDAL)         return 
RealizationMethod.GEOID;
-             if (type == VerticalDatumType.DEPTH)           return 
RealizationMethod.TIDAL;
-             if (type == VerticalDatumType.BAROMETRIC)      return 
RealizationMethod.valueOf(BAROMETRIC);
-             if (ORTHOMETRIC.equalsIgnoreCase(type.name())) return 
RealizationMethod.valueOf(ORTHOMETRIC);
-             if (ELLIPSOIDAL.equalsIgnoreCase(type.name())) return 
ellipsoidal();
-         }
++        return (type != null) ? fromLegacyName(type.name()) : null;
+     }
+ 
+     /**
+      * Returns the realization method from a vertical datum type.
+      * This method is used for reading GML documents older than GML 3.2.
+      *
+      * @param  type  the vertical datum type, or {@code null}.
+      * @return the realization method, or {@code null} if none.
+      */
+     public static RealizationMethod fromLegacyName(final String type) {
+         if ("geoidal"  .equalsIgnoreCase(type)) return 
RealizationMethod.GEOID;
+         if ("depth"    .equalsIgnoreCase(type)) return 
RealizationMethod.TIDAL;
+         if (LOCAL      .equalsIgnoreCase(type)) return 
RealizationMethod.valueOf(LOCAL);
+         if (BAROMETRIC .equalsIgnoreCase(type)) return 
RealizationMethod.valueOf(BAROMETRIC);
+         if (ORTHOMETRIC.equalsIgnoreCase(type)) return 
RealizationMethod.valueOf(ORTHOMETRIC);
+         if (ELLIPSOIDAL.equalsIgnoreCase(type)) return ellipsoidal();
          return null;
      }
  
+     /**
+      * Returns the realization method from heuristic rules applied on the 
name.
+      *
++     * <p>Note: this is {@code fromMethod(String)} on the GeoAPI 4.0 
branch.</p>
++     *
+      * @param  name  the realization method name, or {@code null}.
+      * @return the realization method, or {@code null} if the given name was 
null.
+      */
+     public static RealizationMethod fromMethod(final String name) {
+         RealizationMethod method = fromLegacyName(name);
+         if (method == null && name != null && !name.isBlank()) {
+             final int s = name.lastIndexOf('-');
+             if (s >= 0 && 
name.substring(s+1).strip().equalsIgnoreCase("based")) {
+                 method = CodeLists.forCodeName(RealizationMethod.class, 
name.substring(0, s));
+             }
+             if (method == null) {
+                 method = RealizationMethod.valueOf(name);
+             }
+         }
+         return method;
+     }
+ 
      /**
       * Guesses the realization method of a datum from its name, aliases or a 
given vertical axis.
       * This is sometimes needed after XML unmarshalling or WKT parsing, 
because GML 3.2 and ISO 19162
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
index 2d6ae5666e,e127c1d49f..1bd5e387f4
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
@@@ -1193,8 -1182,15 +1206,16 @@@ public class CoordinateOperationFinder 
       * @param  crs  the CRS having a conversion that cannot be inverted.
       * @return a default error message.
       */
 -    private String canNotInvert(final DerivedCRS crs) {
 +    @SuppressWarnings("deprecation")
 +    private String canNotInvert(final GeneralDerivedCRS crs) {
          return resources().getString(Resources.Keys.NonInvertibleOperation_1, 
label(crs.getConversionFromBase()));
      }
+ 
+     /**
+      * Returns whether the operation can be cached. This is {@code false} if
+      * the operation depends on parameters that may vary between two 
executions.
+      */
+     final boolean canStoreInCache() {
+         return canStoreInCache;
+     }
  }
diff --cc 
endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/internal/VerticalDatumTypesTest.java
index a9be269f6a,b5fe441aec..0a167b5be6
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/internal/VerticalDatumTypesTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/internal/VerticalDatumTypesTest.java
@@@ -66,13 -62,25 +66,26 @@@ public final class VerticalDatumTypesTe
      }
  
      /**
-      * Tests the {@link VerticalDatumTypes#toLegacy(VerticalDatumType)} 
method.
 -     * Tests the {@link VerticalDatumTypes#toLegacyCode(RealizationMethod)} 
method.
++     * Tests the {@link VerticalDatumTypes#toLegacyCode(VerticalDatumType)} 
method.
       */
      @Test
-     public void testToLegacy() {
-         assertEquals(2002, 
VerticalDatumTypes.toLegacy(VerticalDatumType.valueOf("ELLIPSOIDAL")));
-         assertEquals(2005, 
VerticalDatumTypes.toLegacy(VerticalDatumType.GEOIDAL));
-         assertEquals(2006, 
VerticalDatumTypes.toLegacy(VerticalDatumType.DEPTH));
++    @SuppressWarnings("deprecation")
+     public void testToLegacyCode() {
 -        assertEquals(2002, 
VerticalDatumTypes.toLegacyCode(VerticalDatumTypes.ellipsoidal()));
 -        assertEquals(2005, VerticalDatumTypes.toLegacyCode(RealizationMethod 
.GEOID));
 -        assertEquals(2006, VerticalDatumTypes.toLegacyCode(RealizationMethod 
.TIDAL));
++        assertEquals(2002, 
VerticalDatumTypes.toLegacyCode(VerticalDatumType.valueOf("ELLIPSOIDAL")));
++        assertEquals(2005, 
VerticalDatumTypes.toLegacyCode(VerticalDatumType.GEOIDAL));
++        assertEquals(2006, 
VerticalDatumTypes.toLegacyCode(VerticalDatumType.DEPTH));
+     }
+ 
+     /**
+      * Tests the {@link VerticalDatumTypes#fromMethod(String)} method
+      * with names from the <abbr>EPSG</abbr> database.
+      */
+     @Test
+     public void testFromMethod() {
+         assertEquals(RealizationMethod .LEVELLING, 
VerticalDatumTypes.fromMethod("Levelling-based"));
+         assertEquals(RealizationMethod .GEOID,     
VerticalDatumTypes.fromMethod("Geoid-based"));
+         assertEquals(RealizationMethod .TIDAL,     
VerticalDatumTypes.fromMethod("Tidal"));
+         assertEquals(VerticalDatumTypes.LOCAL,     
VerticalDatumTypes.fromMethod("Local").name());
      }
  
      /**


Reply via email to