This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/sis.git
commit 96a055335c04097aa10a2411687ee0efbb1425fb Merge: 48705908fc c4eceb3ef1 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Fri Jul 12 15:19:44 2024 +0200 Merge branch 'geoapi-3.1': initial implementation of `DatumEnsemble`. .../apache/sis/coverage/grid/GridCoverage2D.java | 1 + .../sis/feature/builder/FeatureTypeBuilder.java | 1 + .../main/org/apache/sis/image/ComputedImage.java | 1 + .../apache/sis/metadata/ModifiableMetadata.java | 102 +++-- .../apache/sis/metadata/iso/DefaultMetadata.java | 1 - .../sis/metadata/iso/acquisition/DefaultEvent.java | 1 - .../iso/acquisition/DefaultRequirement.java | 1 - .../DefaultDigitalTransferOptions.java | 1 - .../sis/metadata/iso/extent/DefaultExtent.java | 2 - .../iso/identification/AbstractIdentification.java | 16 +- .../identification/DefaultDataIdentification.java | 5 +- .../metadata/iso/identification/DefaultUsage.java | 2 - .../metadata/iso/lineage/DefaultProcessStep.java | 1 - .../maintenance/DefaultMaintenanceInformation.java | 1 - .../org/apache/sis/util/iso/DefaultTypeName.java | 15 +- .../main/org/apache/sis/util/iso/Names.java | 36 +- .../main/org/apache/sis/util/iso/TypeNames.java | 8 - .../main/org/apache/sis/io/wkt/Colors.java | 3 +- .../main/org/apache/sis/io/wkt/Convention.java | 33 +- .../main/org/apache/sis/io/wkt/ElementKind.java | 16 +- .../sis/parameter/DefaultParameterDescriptor.java | 2 +- .../pending/geoapi/referencing/MissingMethods.java | 96 +++++ .../main/org/apache/sis/referencing/CRS.java | 9 +- .../main/org/apache/sis/referencing/CommonCRS.java | 13 +- .../apache/sis/referencing/NamedIdentifier.java | 1 + .../sis/referencing/StandardDefinitions.java | 4 +- .../apache/sis/referencing/crs/AbstractCRS.java | 45 +++ .../sis/referencing/crs/AbstractDerivedCRS.java | 18 +- .../sis/referencing/crs/DefaultDerivedCRS.java | 50 +-- .../sis/referencing/crs/DefaultEngineeringCRS.java | 75 +++- .../sis/referencing/crs/DefaultGeocentricCRS.java | 76 +++- .../sis/referencing/crs/DefaultGeodeticCRS.java | 54 ++- .../sis/referencing/crs/DefaultGeographicCRS.java | 48 ++- .../sis/referencing/crs/DefaultParametricCRS.java | 71 +++- .../sis/referencing/crs/DefaultProjectedCRS.java | 16 +- .../sis/referencing/crs/DefaultTemporalCRS.java | 75 +++- .../sis/referencing/crs/DefaultVerticalCRS.java | 77 +++- .../sis/referencing/datum/AbstractDatum.java | 91 ++++- .../referencing/datum/DefaultDatumEnsemble.java | 213 +++++++++++ .../referencing/factory/GeodeticObjectFactory.java | 420 +++++++++++++++++---- .../sis/referencing/factory/sql/EPSGFactory.java | 4 +- .../apache/sis/referencing/internal/Resources.java | 10 + .../sis/referencing/internal/Resources.properties | 2 + .../referencing/internal/Resources_fr.properties | 2 + .../transform/DefaultMathTransformFactory.java | 1 + .../operation/transform/InterpolatedTransform.java | 2 +- .../sis/referencing/privy/AffineTransform2D.java | 4 + .../referencing/privy/ReferencingUtilities.java | 4 +- .../apache/sis/referencing/privy/WKTKeywords.java | 1 + .../sis/referencing/ImmutableIdentifierTest.java | 4 +- .../referencing/crs/DefaultEngineeringCRSTest.java | 4 +- .../referencing/crs/DefaultGeocentricCRSTest.java | 2 +- .../referencing/crs/DefaultTemporalCRSTest.java | 2 +- .../apache/sis/referencing/crs/HardCodedCRS.java | 40 +- .../factory/IdentifiedObjectFinderTest.java | 5 +- .../operation/CoordinateOperationFinderTest.java | 2 +- .../operation/DefaultConversionTest.java | 12 +- .../operation/DefaultTransformationTest.java | 2 +- .../transform/CoordinateSystemTransformTest.java | 2 +- .../referencing/privy/DefinitionVerifierTest.java | 2 +- .../apache/sis/test/integration/MetadataTest.java | 2 +- .../apache/sis/storage/landsat/LandsatStore.java | 1 + .../apache/sis/storage/geotiff/GeoTiffStore.java | 1 + .../org/apache/sis/storage/netcdf/NetcdfStore.java | 1 + .../org/apache/sis/io/stream/ChannelDataInput.java | 1 + .../apache/sis/storage/CanNotProbeException.java | 1 + .../main/org/apache/sis/storage/DataStore.java | 3 + .../src/org.apache.sis.util/main/module-info.java | 3 +- .../main/org/apache/sis/pending/jdk/JDK19.java | 21 ++ .../org/apache/sis/system/OptionalDependency.java | 1 + .../test/org/apache/sis/util/LocalesTest.java | 17 +- .../apache/sis/gui/coverage/BandRangeTable.java | 1 + .../apache/sis/gui/coverage/GridSliceSelector.java | 1 + .../main/org/apache/sis/gui/coverage/GridView.java | 1 + .../sis/gui/coverage/ImagePropertyExplorer.java | 3 +- .../org/apache/sis/gui/dataset/FeatureTable.java | 3 + .../main/org/apache/sis/gui/dataset/LogViewer.java | 1 + .../apache/sis/gui/dataset/ResourceExplorer.java | 1 + .../org/apache/sis/gui/dataset/ResourceTree.java | 8 +- .../org/apache/sis/gui/internal/LogHandler.java | 2 +- .../apache/sis/gui/internal/io/FileAccessView.java | 1 + .../org/apache/sis/gui/map/GestureFollower.java | 1 + .../main/org/apache/sis/gui/map/StatusBar.java | 1 + .../apache/sis/gui/metadata/MetadataSummary.java | 1 + .../sis/gui/metadata/StandardMetadataTree.java | 1 + .../gui/referencing/RecentReferenceSystems.java | 1 + 86 files changed, 1527 insertions(+), 360 deletions(-) diff --cc endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/builder/FeatureTypeBuilder.java index e095cccb43,575b5d72ed..75fd60b37e --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/builder/FeatureTypeBuilder.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/builder/FeatureTypeBuilder.java @@@ -204,13 -206,12 +204,14 @@@ public class FeatureTypeBuilder extend * to values inferred from the given template. The properties list will contain properties * declared explicitly in the given template, not including properties inherited from super types. * - * @param template an existing feature type to use as a template, or {@code null} if none. + * <div class="warning"><b>Warning:</b> + * The {@code template} argument type will be changed to {@code FeatureType} if and when such interface + * will be defined in GeoAPI.</div> * - * @see #setAll(FeatureType) + * @param template an existing feature type to use as a template, or {@code null} if none. */ + @SuppressWarnings("this-escape") // The invoked method does not store `this` and is not overrideable. - public FeatureTypeBuilder(final FeatureType template) { + public FeatureTypeBuilder(final DefaultFeatureType template) { this(null, null, null); if (template != null) { initialize(template); diff --cc endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/Names.java index 79eda67aec,50ee62a5b4..e6015be4fc --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/Names.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/Names.java @@@ -330,9 -331,9 +331,9 @@@ public final class Names extends Stati public static MemberName createMemberName(final CharSequence namespace, final String separator, final CharSequence localPart, final TypeName attributeType) { - ensureNonNull("localPart", localPart); - ensureNonNull("attributeType", attributeType); + ArgumentChecks.ensureNonNull("localPart", localPart); + ArgumentChecks.ensureNonNull("attributeType", attributeType); - final NameFactory factory = DefaultNameFactory.provider(); + final DefaultNameFactory factory = DefaultNameFactory.provider(); return factory.createMemberName(createNameSpace(factory, namespace, separator), localPart, attributeType); } @@@ -421,22 -422,21 +422,23 @@@ if (type == null) { return null; } - final Type t = type.toJavaType().orElse(null); - if (t instanceof Class<?>) { - return (Class<?>) t; + if (type instanceof DefaultTypeName) { + final Type t = ((DefaultTypeName) type).toJavaType().orElse(null); + if (t instanceof Class<?>) { + return (Class<?>) t; + } } - final Class<?> c; + ClassNotFoundException cause; try { - c = TypeNames.toClass(TypeNames.namespace(type.scope()), type.toString()); + final Class<?> c = TypeNames.toClass(TypeNames.namespace(type.scope()), type.toString()); + if (c != Void.TYPE) { + return c; + } + cause = null; } catch (ClassNotFoundException e) { - throw new UnknownNameException(TypeNames.unknown(type), e); - } - if (c == Void.TYPE) { - throw new UnknownNameException(TypeNames.unknown(type)); + cause = e; } - return c; + throw new UnknownNameException(Errors.format(Errors.Keys.UnknownType_1, type.toFullyQualifiedName()), cause); } /** diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/ElementKind.java index 1e00e8b74a,6979e1d209..6c5649aaf1 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/ElementKind.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/ElementKind.java @@@ -27,6 -28,6 +27,9 @@@ import org.opengis.referencing.operatio import org.opengis.parameter.GeneralParameterValue; import org.apache.sis.util.Numbers; ++// Specific to the main branch: ++import org.apache.sis.referencing.datum.DefaultDatumEnsemble; ++ /** * Kind of an element in a <i>Well Known Text</i>. @@@ -145,6 -155,7 +157,7 @@@ public enum ElementKind * <caption>Mapping from Java type to WKT element</caption> * <tr><th>Base type</th> <th>Kind</th></tr> * <tr><td>{@link Datum}</td> <td>{@link #DATUM}</td></tr> - * <tr><td>{@link DatumEnsemble}</td> <td>{@link #ENSEMBLE}</td></tr> ++ * <tr><td>{@link DefaultDatumEnsemble}</td> <td>{@link #ENSEMBLE}</td></tr> * <tr><td>{@link OperationMethod}</td> <td>{@link #METHOD}</td></tr> * <tr><td>{@link GeneralParameterValue}</td> <td>{@link #PARAMETER}</td></tr> * <tr><td>{@link CoordinateSystemAxis}</td> <td>{@link #AXIS}</td></tr> @@@ -165,6 -176,7 +178,7 @@@ public static ElementKind forType(final Class<?> type) { if (type != null) { if (Datum .class.isAssignableFrom(type)) return DATUM; - if (DatumEnsemble .class.isAssignableFrom(type)) return ENSEMBLE; ++ if (DefaultDatumEnsemble .class.isAssignableFrom(type)) return ENSEMBLE; if (OperationMethod .class.isAssignableFrom(type)) return METHOD; if (GeneralParameterValue.class.isAssignableFrom(type)) return PARAMETER; if (CoordinateSystemAxis .class.isAssignableFrom(type)) return AXIS; diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/pending/geoapi/referencing/MissingMethods.java index 0000000000,0000000000..a84e462276 new file mode 100644 --- /dev/null +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/pending/geoapi/referencing/MissingMethods.java @@@ -1,0 -1,0 +1,96 @@@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.sis.pending.geoapi.referencing; ++ ++import java.util.function.Function; ++import org.opengis.referencing.crs.*; ++import org.opengis.referencing.datum.*; ++import org.apache.sis.referencing.crs.DefaultVerticalCRS; ++import org.apache.sis.referencing.crs.DefaultTemporalCRS; ++import org.apache.sis.referencing.crs.DefaultEngineeringCRS; ++import org.apache.sis.referencing.datum.DefaultDatumEnsemble; ++ ++ ++/** ++ * Placeholder for methods missing in the GeoAPI 3.0 interface. ++ */ ++public final class MissingMethods { ++ /** ++ * To be set by static {@code AbstractCRS} initializer. ++ */ ++ public static volatile Function<CoordinateReferenceSystem, DefaultDatumEnsemble<?>> datumEnsemble; ++ ++ /** ++ * To be set by static {@code DefaultGeodeticCRS} initializer. ++ */ ++ public static volatile Function<GeodeticCRS, DefaultDatumEnsemble<GeodeticDatum>> geodeticDatumEnsemble; ++ ++ private MissingMethods() { ++ } ++ ++ /** ++ * Returns the datum ensemble of an arbitrary CRS. ++ * ++ * @param datum the CRS from which to get a datum ensemble, or {@code null} if none. ++ * @return the datum ensemble, or {@code null} if none. ++ */ ++ public static DefaultDatumEnsemble<?> getDatumEnsemble(final CoordinateReferenceSystem crs) { ++ final var m = datumEnsemble; ++ return (m != null) ? m.apply(crs) : null; ++ } ++ ++ /** ++ * Returns the datum ensemble of an arbitrary geodetic CRS. ++ * ++ * @param datum the CRS from which to get a datum ensemble, or {@code null} if none. ++ * @return the datum ensemble, or {@code null} if none. ++ */ ++ public static DefaultDatumEnsemble<GeodeticDatum> getDatumEnsemble(final GeodeticCRS crs) { ++ final var m = geodeticDatumEnsemble; ++ return (m != null) ? m.apply(crs) : null; ++ } ++ ++ /** ++ * Returns the datum ensemble of an arbitrary vertical CRS. ++ * ++ * @param datum the CRS from which to get a datum ensemble, or {@code null} if none. ++ * @return the datum ensemble, or {@code null} if none. ++ */ ++ public static DefaultDatumEnsemble<VerticalDatum> getDatumEnsemble(final VerticalCRS crs) { ++ return (crs instanceof DefaultVerticalCRS) ? ((DefaultVerticalCRS) crs).getDatumEnsemble() : null; ++ } ++ ++ /** ++ * Returns the datum ensemble of an arbitrary temporal CRS. ++ * ++ * @param datum the CRS from which to get a datum ensemble, or {@code null} if none. ++ * @return the datum ensemble, or {@code null} if none. ++ */ ++ public static DefaultDatumEnsemble<TemporalDatum> getDatumEnsemble(final TemporalCRS crs) { ++ return (crs instanceof DefaultTemporalCRS) ? ((DefaultTemporalCRS) crs).getDatumEnsemble() : null; ++ } ++ ++ /** ++ * Returns the datum ensemble of an arbitrary engineering CRS. ++ * ++ * @param datum the CRS from which to get a datum ensemble, or {@code null} if none. ++ * @return the datum ensemble, or {@code null} if none. ++ */ ++ public static DefaultDatumEnsemble<EngineeringDatum> getDatumEnsemble(final EngineeringCRS crs) { ++ return (crs instanceof DefaultEngineeringCRS) ? ((DefaultEngineeringCRS) crs).getDatumEnsemble() : null; ++ } ++} diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CRS.java index 3022a83648,2cdf0dc587..b38190d740 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CRS.java @@@ -93,9 -93,14 +93,10 @@@ import org.apache.sis.util.logging.Logg // Specific to the main and geoapi-3.1 branches: import org.opengis.referencing.crs.GeneralDerivedCRS; -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import org.opengis.geometry.Geometry; -import org.opengis.referencing.ObjectDomain; -import org.opengis.referencing.crs.DerivedCRS; -import org.opengis.referencing.datum.DynamicReferenceFrame; -import org.opengis.metadata.extent.BoundingPolygon; -import org.opengis.metadata.extent.GeographicExtent; -import org.opengis.coordinate.CoordinateMetadata; +// Specific to the main branch: +import org.apache.sis.pending.geoapi.referencing.DynamicReferenceFrame; +import org.apache.sis.coordinate.DefaultCoordinateMetadata; ++import static org.apache.sis.pending.geoapi.referencing.MissingMethods.getDatumEnsemble; /** @@@ -1246,7 -1293,8 +1247,8 @@@ public final class CRS extends Static */ final Map<String, ?> properties = ReferencingUtilities.getPropertiesForModifiedCRS(crs); if (crs instanceof GeodeticCRS) { - return new DefaultGeographicCRS(properties, ((GeodeticCRS) crs).getDatum(), (EllipsoidalCS) cs); + final var source = (GeodeticCRS) crs; - return new DefaultGeographicCRS(properties, source.getDatum(), source.getDatumEnsemble(), (EllipsoidalCS) cs); ++ return new DefaultGeographicCRS(properties, source.getDatum(), getDatumEnsemble(source), (EllipsoidalCS) cs); } /* * In Apache SIS implementation, the Conversion contains the source and target CRS together with @@@ -1264,7 -1312,8 +1266,8 @@@ /* * If the CRS is neither geographic or projected, then it is engineering. */ - return new DefaultEngineeringCRS(properties, ((EngineeringCRS) crs).getDatum(), cs); + final var source = (EngineeringCRS) crs; - return new DefaultEngineeringCRS(properties, source.getDatum(), source.getDatumEnsemble(), cs); ++ return new DefaultEngineeringCRS(properties, source.getDatum(), getDatumEnsemble(source), cs); } } if (crs instanceof CompoundCRS) { @@@ -1335,7 -1384,7 +1338,7 @@@ VerticalCRS c = CommonCRS.Vertical.ELLIPSOIDAL.crs(); if (!c.getCoordinateSystem().getAxis(0).equals(axis)) { final Map<String,?> properties = IdentifiedObjects.getProperties(c); - c = new DefaultVerticalCRS(properties, c.getDatum(), new DefaultVerticalCS(properties, axis)); - c = new DefaultVerticalCRS(properties, c.getDatum(), c.getDatumEnsemble(), new DefaultVerticalCS(properties, axis)); ++ c = new DefaultVerticalCRS(properties, c.getDatum(), getDatumEnsemble(c), new DefaultVerticalCS(properties, axis)); } return c; } diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java index 62c37c6d07,5f54b5e9d5..f3d219197f --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java @@@ -86,9 -86,8 +86,10 @@@ import org.apache.sis.measure.Latitude import org.apache.sis.measure.Units; import static org.apache.sis.util.privy.Constants.SECONDS_PER_DAY; -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import org.opengis.referencing.datum.RealizationMethod; +// Specific to the main branch: +import org.opengis.referencing.crs.GeocentricCRS; +import org.opengis.referencing.datum.VerticalDatumType; ++import static org.apache.sis.pending.geoapi.referencing.MissingMethods.getDatumEnsemble; /** @@@ -717,7 -716,7 +718,7 @@@ public enum CommonCRS cs = (EllipsoidalCS) StandardDefinitions.createCoordinateSystem(StandardDefinitions.ELLIPSOIDAL_3D, true); } // Use same name and datum than the geographic CRS. - object = new DefaultGeographicCRS(properties(base, geo3D), base.getDatum(), cs); - object = new DefaultGeographicCRS(properties(base, geo3D), base.getDatum(), base.getDatumEnsemble(), cs); ++ object = new DefaultGeographicCRS(properties(base, geo3D), base.getDatum(), getDatumEnsemble(base), cs); cachedGeo3D = object; } } @@@ -782,7 -777,7 +783,7 @@@ if (cs == null) { cs = (CartesianCS) StandardDefinitions.createCoordinateSystem(StandardDefinitions.EARTH_CENTRED, true); } - object = new DefaultGeocentricCRS(properties(base, geocentric), base.getDatum(), cs); - object = new DefaultGeocentricCRS(properties(base, geocentric), base.getDatum(), base.getDatumEnsemble(), cs); ++ object = new DefaultGeocentricCRS(properties(base, geocentric), base.getDatum(), getDatumEnsemble(base), cs); cachedGeocentric = object; } } @@@ -837,7 -828,7 +838,7 @@@ if (cs == null) { cs = (SphericalCS) StandardDefinitions.createCoordinateSystem(StandardDefinitions.SPHERICAL, true); } - object = new DefaultGeocentricCRS(IdentifiedObjects.getProperties(base, exclude()), base.getDatum(), cs); - object = new DefaultGeocentricCRS(IdentifiedObjects.getProperties(base, exclude()), base.getDatum(), base.getDatumEnsemble(), cs); ++ object = new DefaultGeocentricCRS(IdentifiedObjects.getProperties(base, exclude()), base.getDatum(), getDatumEnsemble(base), cs); cachedSpherical = object; } } diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/AbstractCRS.java index 013953fcb6,9fafafbdc2..c47378a318 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/AbstractCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/AbstractCRS.java @@@ -38,6 -40,7 +40,8 @@@ import org.apache.sis.referencing.privy import org.apache.sis.metadata.privy.ImplementationHelper; import org.apache.sis.io.wkt.Convention; import org.apache.sis.io.wkt.Formatter; ++import org.apache.sis.pending.geoapi.referencing.MissingMethods; + import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.Utilities; import org.apache.sis.util.ComparisonMode; import org.apache.sis.util.resources.Errors; @@@ -46,8 -49,9 +50,9 @@@ import org.opengis.referencing.crs.GeneralDerivedCRS; import org.opengis.geometry.MismatchedDimensionException; -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import org.opengis.metadata.Identifier; -import org.opengis.referencing.datum.DatumEnsemble; +// Specific to the main branch: +import org.opengis.referencing.ReferenceIdentifier; ++import org.apache.sis.referencing.datum.DefaultDatumEnsemble; /** @@@ -207,6 -211,30 +212,30 @@@ public class AbstractCRS extends Abstra Errors.Keys.MismatchedDimension_3, "cs", expected, actual)); } + /** + * Verifies the consistency between the datum and the ensemble. + * At least one of the {@code datum} and {@code ensemble} arguments shall be non-null. + * + * @param datum the datum, or {@code null} if the CRS is associated only to a datum ensemble. + * @param ensemble collection of reference frames which for low accuracy requirements may be considered to be + * insignificantly different from each other, or {@code null} if there is no such ensemble. + * @throws NullPointerException if both arguments are null. + * @throws IllegalArgumentException + */ - static <D extends Datum> void checkDatum(final D datum, final DatumEnsemble<D> ensemble) { ++ static <D extends Datum> void checkDatum(final D datum, final DefaultDatumEnsemble<D> ensemble) { + if (ensemble == null) { + ArgumentChecks.ensureNonNull("datum", datum); + } else if (datum != null) { + for (final D member : ensemble.getMembers()) { + if (Utilities.equalsIgnoreMetadata(datum, member)) { + return; + } + } + throw new IllegalArgumentException(Resources.format(Resources.Keys.NotAMemberOfDatumEnsemble_2, + IdentifiedObjects.getDisplayName(ensemble), IdentifiedObjects.getDisplayName(datum))); + } + } + /** * Creates a new CRS derived from the specified one, but with different axis order or unit. * @@@ -305,6 -332,6 +334,22 @@@ return (this instanceof SingleCRS) ? ((SingleCRS) this).getDatum() : null; } ++ /** ++ * Returns the datum ensemble. ++ * ++ * @return the datum ensemble, or {@code null} if none. ++ */ ++ DefaultDatumEnsemble<?> getDatumEnsemble() { ++ return null; ++ } ++ ++ /** ++ * Initializes the handler for getting datum ensemble of an arbitrary CRS. ++ */ ++ static { ++ MissingMethods.datumEnsemble = (crs) -> (crs instanceof AbstractCRS) ? ((AbstractCRS) crs).getDatumEnsemble() : null; ++ } ++ /** * Returns the coordinate system. * diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultDerivedCRS.java index 7551b8a41f,87123736ca..3c475877ed --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultDerivedCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultDerivedCRS.java @@@ -282,10 -284,10 +282,10 @@@ public class DefaultDerivedCRS extends if (baseCRS != null && derivedCS != null) { final String type = getTypeKeyword(properties, baseCRS, derivedCS); if (type != null) switch (type) { - case WKTKeywords.GeodeticCRS: return new Geodetic (properties, (GeodeticCRS) baseCRS, conversion, derivedCS); - case WKTKeywords.VerticalCRS: return new Vertical (properties, (VerticalCRS) baseCRS, conversion, (VerticalCS) derivedCS); - case WKTKeywords.TimeCRS: return new Temporal (properties, (TemporalCRS) baseCRS, conversion, (TimeCS) derivedCS); - case WKTKeywords.ParametricCRS: return new Parametric(properties, (ParametricCRS) baseCRS, conversion, (DefaultParametricCS) derivedCS); + case WKTKeywords.GeodeticCRS: return new Geodetic (properties, (GeodeticCRS) baseCRS, baseToDerived, derivedCS); + case WKTKeywords.VerticalCRS: return new Vertical (properties, (VerticalCRS) baseCRS, baseToDerived, (VerticalCS) derivedCS); + case WKTKeywords.TimeCRS: return new Temporal (properties, (TemporalCRS) baseCRS, baseToDerived, (TimeCS) derivedCS); - case WKTKeywords.ParametricCRS: return new Parametric(properties, (ParametricCRS) baseCRS, baseToDerived, (ParametricCS) derivedCS); ++ case WKTKeywords.ParametricCRS: return new Parametric(properties, (ParametricCRS) baseCRS, baseToDerived, (DefaultParametricCS) derivedCS); case WKTKeywords.EngineeringCRS: { /* * This case may happen for baseCRS of kind GeodeticCRS, ProjectedCRS or EngineeringCRS. @@@ -810,8 -827,8 +810,8 @@@ } /** Creates a new parametric CRS from the given properties. */ - Parametric(Map<String,?> properties, ParametricCRS baseCRS, Conversion conversion, DefaultParametricCS derivedCS) { - super(properties, baseCRS, conversion, derivedCS); - Parametric(Map<String,?> properties, ParametricCRS baseCRS, Conversion baseToDerived, ParametricCS derivedCS) { ++ Parametric(Map<String,?> properties, ParametricCRS baseCRS, Conversion baseToDerived, DefaultParametricCS derivedCS) { + super(properties, baseCRS, baseToDerived, derivedCS); } /** Creates a new parametric CRS from the given properties. */ diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java index bb2cc2743a,0366a81529..ee0410f016 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java @@@ -32,6 -31,9 +31,9 @@@ import org.apache.sis.referencing.privy import org.apache.sis.xml.bind.referencing.CS_CoordinateSystem; import org.apache.sis.io.wkt.Formatter; -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import org.opengis.referencing.datum.DatumEnsemble; ++// Specific to the main branch: ++import org.apache.sis.referencing.datum.DefaultDatumEnsemble; + /** * A 1-, 2- or 3-dimensional contextually local coordinate reference system. @@@ -96,8 -98,18 +98,18 @@@ public class DefaultEngineeringCRS exte @SuppressWarnings("serial") // Most SIS implementations are serializable. private EngineeringDatum datum; + /** + * Collection of reference frames which for low accuracy requirements may be considered to be + * insignificantly different from each other. May be {@code null} if there is no such ensemble. + * + * @see #getDatumEnsemble() + */ + @SuppressWarnings("serial") // Most SIS implementations are serializable. - private final DatumEnsemble<EngineeringDatum> ensemble; ++ private final DefaultDatumEnsemble<EngineeringDatum> ensemble; + /** * Creates a coordinate reference system from the given properties, datum and coordinate system. + * At least one of the {@code datum} and {@code ensemble} arguments shall be non-null. * The properties given in argument follow the same rules as for the * {@linkplain AbstractReferenceSystem#AbstractReferenceSystem(Map) super-class constructor}. * The following table is a reminder of main (not all) properties: @@@ -139,10 -155,24 +155,24 @@@ */ public DefaultEngineeringCRS(final Map<String,?> properties, final EngineeringDatum datum, - final DatumEnsemble<EngineeringDatum> ensemble, ++ final DefaultDatumEnsemble<EngineeringDatum> ensemble, final CoordinateSystem cs) { super(properties, cs); - this.datum = Objects.requireNonNull(datum); + this.datum = datum; + this.ensemble = ensemble; + checkDatum(datum, ensemble); + } + + /** - * @deprecated A {@code DatumEnsemble} argument has been added. ++ * @deprecated A {@code DefaultDatumEnsemble} argument has been added. + */ + @Deprecated(since="1.5", forRemoval=true) + public DefaultEngineeringCRS(final Map<String,?> properties, + final EngineeringDatum datum, + final CoordinateSystem cs) + { + this(properties, datum, null, cs); } /** @@@ -167,7 -198,9 +198,9 @@@ */ protected DefaultEngineeringCRS(final EngineeringCRS crs) { super(crs); - datum = crs.getDatum(); + datum = crs.getDatum(); - ensemble = crs.getDatumEnsemble(); ++ ensemble = (crs instanceof DefaultEngineeringCRS) ? ((DefaultEngineeringCRS) crs).getDatumEnsemble() : null; + checkDatum(datum, ensemble); } /** @@@ -212,6 -248,22 +248,26 @@@ return datum; } + /** + * Returns a collection of datums which, for low accuracy requirements, + * may be considered to be insignificantly different from each other. + * This property may be null if this <abbr>CRS</abbr> is related to an object + * identified only by a single {@linkplain #getDatum() datum}. + * ++ * <div class="warning"><b>Warning:</b> in a future SIS version, the return type may ++ * be changed to the {@code org.opengis.referencing.datum.DatumEnsemble} interface. ++ * This change is pending GeoAPI revision.</div> ++ * + * @return the datum ensemble, or {@code null} if this <abbr>CRS</abbr> is related + * to an object identified only by a single {@linkplain #getDatum() datum}. + * + * @since 1.5 + */ + @Override - public DatumEnsemble<EngineeringDatum> getDatumEnsemble() { ++ public DefaultDatumEnsemble<EngineeringDatum> getDatumEnsemble() { + return ensemble; + } + /** * {@inheritDoc} * @@@ -354,7 -408,7 +411,7 @@@ /** * Returns the coordinate system if it is not an instance of any of the types handled by specialized methods. -- * It is the case of {@link EllipsoidalCS}, {@link VerticalCS}, {@link TimeCS} and {@link ParametricCS}. ++ * It is the case of {@link EllipsoidalCS}, {@link VerticalCS}, {@link TimeCS} and {@link DefaultParametricCS}. */ @XmlElement(name = "coordinateSystem", required = true) @XmlJavaTypeAdapter(CS_CoordinateSystem.class) diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java index 96abe6b511,376505ba97..bed6a0eb05 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java @@@ -29,6 -29,6 +29,9 @@@ import org.apache.sis.referencing.cs.Ab import org.apache.sis.util.ArgumentChecks; import org.apache.sis.io.wkt.Formatter; ++// Specific to the main branch: ++import org.apache.sis.referencing.datum.DefaultDatumEnsemble; ++ // Specific to the main and geoapi-3.1 branches: import org.opengis.referencing.crs.GeocentricCRS; @@@ -123,16 -128,21 +127,21 @@@ public class DefaultGeocentricCRS exten * </table> * * @param properties the properties to be given to the coordinate reference system. - * @param datum the datum. + * @param datum the datum, or {@code null} if the CRS is associated only to a datum ensemble. + * @param ensemble collection of reference frames which for low accuracy requirements may be considered to be + * insignificantly different from each other, or {@code null} if there is no such ensemble. * @param cs the coordinate system, which must be three-dimensional. * - * @see org.apache.sis.referencing.factory.GeodeticObjectFactory#createGeodeticCRS(Map, GeodeticDatum, CartesianCS) + * @see org.apache.sis.referencing.factory.GeodeticObjectFactory#createGeocentricCRS(Map, GeodeticDatum, CartesianCS) + * + * @since 1.5 */ public DefaultGeocentricCRS(final Map<String,?> properties, final GeodeticDatum datum, - final CartesianCS cs) - final DatumEnsemble<GeodeticDatum> ensemble, ++ final DefaultDatumEnsemble<GeodeticDatum> ensemble, + final CartesianCS cs) { - super(properties, datum, cs); + super(properties, datum, ensemble, cs); checkDimension(3, 3, cs); } @@@ -142,19 -153,46 +152,46 @@@ * {@linkplain #DefaultGeocentricCRS(Map, GeodeticDatum, CartesianCS) above constructor}. * * @param properties the properties to be given to the coordinate reference system. - * @param datum the datum. + * @param datum the datum, or {@code null} if the CRS is associated only to a datum ensemble. + * @param ensemble collection of reference frames which for low accuracy requirements may be considered to be + * insignificantly different from each other, or {@code null} if there is no such ensemble. * @param cs the coordinate system. * - * @see org.apache.sis.referencing.factory.GeodeticObjectFactory#createGeodeticCRS(Map, GeodeticDatum, SphericalCS) + * @see org.apache.sis.referencing.factory.GeodeticObjectFactory#createGeocentricCRS(Map, GeodeticDatum, SphericalCS) + * + * @since 1.5 */ public DefaultGeocentricCRS(final Map<String,?> properties, final GeodeticDatum datum, - final SphericalCS cs) - final DatumEnsemble<GeodeticDatum> ensemble, ++ final DefaultDatumEnsemble<GeodeticDatum> ensemble, + final SphericalCS cs) { - super(properties, datum, cs); + super(properties, datum, ensemble, cs); checkDimension(2, 3, cs); } + /** - * @deprecated A {@code DatumEnsemble} argument has been added. ++ * @deprecated A {@code DefaultDatumEnsemble} argument has been added. + */ + @Deprecated(since="1.5", forRemoval=true) + public DefaultGeocentricCRS(final Map<String,?> properties, + final GeodeticDatum datum, + final CartesianCS cs) + { + this(properties, datum, null, cs); + } + + /** - * @deprecated A {@code DatumEnsemble} argument has been added. ++ * @deprecated A {@code DefaultDatumEnsemble} argument has been added. + */ + @Deprecated(since="1.5", forRemoval=true) + public DefaultGeocentricCRS(final Map<String,?> properties, + final GeodeticDatum datum, + final SphericalCS cs) + { + this(properties, datum, null, cs); + } + /** * Creates a new CRS derived from the specified one, but with different axis order or unit. * This is for implementing the {@link #createSameType(AbstractCS)} method only. @@@ -230,6 -266,22 +270,26 @@@ return super.getDatum(); } + /** + * Returns a collection of datums which, for low accuracy requirements, + * may be considered to be insignificantly different from each other. + * This property may be null if this <abbr>CRS</abbr> is related to an object + * identified only by a single {@linkplain #getDatum() datum}. + * ++ * <div class="warning"><b>Warning:</b> in a future SIS version, the return type may ++ * be changed to the {@code org.opengis.referencing.datum.DatumEnsemble} interface. ++ * This change is pending GeoAPI revision.</div> ++ * + * @return the datum ensemble, or {@code null} if this <abbr>CRS</abbr> is related + * to an object identified only by a single {@linkplain #getDatum() datum}. + * + * @since 1.5 + */ + @Override - public DatumEnsemble<GeodeticDatum> getDatumEnsemble() { ++ public DefaultDatumEnsemble<GeodeticDatum> getDatumEnsemble() { + return ensemble; + } + /** * {@inheritDoc} * diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java index ae28b165c8,7f706ab223..b1f79eb8e8 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java @@@ -31,7 -30,7 +30,6 @@@ import org.opengis.referencing.crs.Geod import org.opengis.referencing.crs.SingleCRS; import org.opengis.referencing.datum.GeodeticDatum; import org.opengis.referencing.datum.PrimeMeridian; --import org.opengis.metadata.Identifier; import org.apache.sis.referencing.AbstractReferenceSystem; import org.apache.sis.referencing.CRS; import org.apache.sis.referencing.cs.AbstractCS; @@@ -46,8 -45,8 +44,10 @@@ import org.apache.sis.io.wkt.Convention import org.apache.sis.io.wkt.Formatter; import org.apache.sis.measure.Units; -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import org.opengis.referencing.datum.DatumEnsemble; +// Specific to the main branch: +import org.opengis.referencing.ReferenceIdentifier; ++import org.apache.sis.pending.geoapi.referencing.MissingMethods; ++import org.apache.sis.referencing.datum.DefaultDatumEnsemble; /** @@@ -89,6 -88,15 +89,15 @@@ class DefaultGeodeticCRS extends Abstra @SuppressWarnings("serial") // Most SIS implementations are serializable. private GeodeticDatum datum; + /** + * Collection of reference frames which for low accuracy requirements may be considered to be + * insignificantly different from each other. May be {@code null} if there is no such ensemble. + * + * @see #getDatumEnsemble() + */ + @SuppressWarnings("serial") // Most SIS implementations are serializable. - final DatumEnsemble<GeodeticDatum> ensemble; ++ final DefaultDatumEnsemble<GeodeticDatum> ensemble; + /** * Creates a coordinate reference system from the given properties, datum and coordinate system. * The properties given in argument follow the same rules as for the @@@ -102,6 -112,7 +113,7 @@@ */ DefaultGeodeticCRS(final Map<String,?> properties, final GeodeticDatum datum, - final DatumEnsemble<GeodeticDatum> ensemble, ++ final DefaultDatumEnsemble<GeodeticDatum> ensemble, final CoordinateSystem cs) { super(properties, cs); @@@ -112,9 -125,10 +126,10 @@@ * Creates a new CRS derived from the specified one, but with different axis order or unit. * This is for implementing the {@link #createSameType(AbstractCS)} method only. */ - DefaultGeodeticCRS(final DefaultGeodeticCRS original, final Identifier id, final AbstractCS cs) { + DefaultGeodeticCRS(final DefaultGeodeticCRS original, final ReferenceIdentifier id, final AbstractCS cs) { super(original, id, cs); - datum = original.datum; + datum = original.datum; + ensemble = original.ensemble; } /** @@@ -128,7 -142,9 +143,9 @@@ */ protected DefaultGeodeticCRS(final GeodeticCRS crs) { super(crs); - datum = crs.getDatum(); + datum = crs.getDatum(); - ensemble = crs.getDatumEnsemble(); ++ ensemble = (crs instanceof DefaultGeodeticCRS) ? ((DefaultGeodeticCRS) crs).getDatumEnsemble() : null; + checkDatum(datum, ensemble); } /** @@@ -171,6 -187,6 +188,24 @@@ return datum; } ++ /** ++ * Returns the datum ensemble. ++ * ++ * @return the datum ensemble, or {@code null} if none. ++ */ ++ @Override ++ DefaultDatumEnsemble<GeodeticDatum> getDatumEnsemble() { ++ return ensemble; ++ } ++ ++ /** ++ * Initializes the handler for getting datum ensemble of an arbitrary CRS. ++ */ ++ static { ++ MissingMethods.geodeticDatumEnsemble = (crs) -> ++ (crs instanceof DefaultGeodeticCRS) ? ((DefaultGeodeticCRS) crs).getDatumEnsemble() : null; ++ } ++ /** * Returns a coordinate reference system of the same type as this CRS but with different axes. * This method shall be overridden by all {@code DefaultGeodeticCRS} subclasses in this package. diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultGeographicCRS.java index 98c88f661c,e8b4027634..9dfa6615ef --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultGeographicCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultGeographicCRS.java @@@ -38,8 -38,9 +38,9 @@@ import static org.apache.sis.util.privy import static org.apache.sis.util.privy.Constants.CRS83; import static org.apache.sis.util.privy.Constants.CRS84; -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import org.opengis.metadata.Identifier; -import org.opengis.referencing.datum.DatumEnsemble; +// Specific to the main branch: +import org.opengis.referencing.ReferenceIdentifier; ++import org.apache.sis.referencing.datum.DefaultDatumEnsemble; /** @@@ -151,12 -157,24 +157,24 @@@ public class DefaultGeographicCRS exten */ public DefaultGeographicCRS(final Map<String,?> properties, final GeodeticDatum datum, - final DatumEnsemble<GeodeticDatum> ensemble, ++ final DefaultDatumEnsemble<GeodeticDatum> ensemble, final EllipsoidalCS cs) { - super(properties, datum, cs); + super(properties, datum, ensemble, cs); checkDimension(2, 3, cs); } + /** - * @deprecated A {@code DatumEnsemble} argument has been added. ++ * @deprecated A {@code DefaultDatumEnsemble} argument has been added. + */ + @Deprecated(since="1.5", forRemoval=true) + public DefaultGeographicCRS(final Map<String,?> properties, + final GeodeticDatum datum, + final EllipsoidalCS cs) + { + this(properties, datum, null, cs); + } + /** * Creates a new CRS derived from the specified one, but with different axis order or unit. * This is for implementing the {@link #createSameType(AbstractCS)} method only. @@@ -237,6 -257,22 +257,26 @@@ return super.getDatum(); } + /** + * Returns a collection of datums which, for low accuracy requirements, + * may be considered to be insignificantly different from each other. + * This property may be null if this <abbr>CRS</abbr> is related to an object + * identified only by a single {@linkplain #getDatum() datum}. + * ++ * <div class="warning"><b>Warning:</b> in a future SIS version, the return type may ++ * be changed to the {@code org.opengis.referencing.datum.DatumEnsemble} interface. ++ * This change is pending GeoAPI revision.</div> ++ * + * @return the datum ensemble, or {@code null} if this <abbr>CRS</abbr> is related + * to an object identified only by a single {@linkplain #getDatum() datum}. + * + * @since 1.5 + */ + @Override - public DatumEnsemble<GeodeticDatum> getDatumEnsemble() { ++ public DefaultDatumEnsemble<GeodeticDatum> getDatumEnsemble() { + return ensemble; + } + /** * Returns the coordinate system. * diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultParametricCRS.java index b0da7ed38a,e55064a583..7d63756418 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultParametricCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultParametricCRS.java @@@ -27,9 -26,11 +26,10 @@@ import org.apache.sis.referencing.cs.Ax import org.apache.sis.referencing.cs.AbstractCS; import org.apache.sis.io.wkt.Formatter; -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import org.opengis.referencing.cs.ParametricCS; -import org.opengis.referencing.crs.ParametricCRS; -import org.opengis.referencing.datum.ParametricDatum; -import org.opengis.referencing.datum.DatumEnsemble; +// Specific to the main branch: +import org.apache.sis.referencing.cs.DefaultParametricCS; +import org.apache.sis.referencing.datum.DefaultParametricDatum; ++import org.apache.sis.referencing.datum.DefaultDatumEnsemble; /** @@@ -69,17 -70,28 +69,27 @@@ public class DefaultParametricCRS exten private static final long serialVersionUID = 4013698133331342649L; /** - * The datum. + * The datum, or {@code null} if the CRS is associated only to a datum ensemble. * * <p><b>Consider this field as final!</b> - * This field is modified only at unmarshalling time by {@link #setDatum(ParametricDatum)}</p> + * This field is modified only at unmarshalling time by {@code setDatum(ParametricDatum)}</p> * * @see #getDatum() */ - @SuppressWarnings("serial") // Most SIS implementations are serializable. - private ParametricDatum datum; + private DefaultParametricDatum datum; + /** + * Collection of reference frames which for low accuracy requirements may be considered to be + * insignificantly different from each other. May be {@code null} if there is no such ensemble. + * + * @see #getDatumEnsemble() + */ + @SuppressWarnings("serial") // Most SIS implementations are serializable. - private final DatumEnsemble<ParametricDatum> ensemble; ++ private final DefaultDatumEnsemble<DefaultParametricDatum> ensemble; + /** * Creates a coordinate reference system from the given properties, datum and coordinate system. + * At least one of the {@code datum} and {@code ensemble} arguments shall be non-null. * The properties given in argument follow the same rules as for the * {@linkplain org.apache.sis.referencing.AbstractReferenceSystem#AbstractReferenceSystem(Map) * super-class constructor}. The following table is a reminder of main (not all) properties: @@@ -113,23 -125,39 +123,41 @@@ * </tr> * </table> * + * <div class="warning"><b>Warning:</b> in a future SIS version, the parameter types may be changed to + * {@code org.opengis.referencing.datum.ParametricDatum} and {@code org.opengis.referencing.cs.ParametricCS} + * Those change are pending GeoAPI revision.</div> + * * @param properties the properties to be given to the coordinate reference system. - * @param datum the datum. + * @param datum the datum, or {@code null} if the CRS is associated only to a datum ensemble. + * @param ensemble collection of reference frames which for low accuracy requirements may be considered to be + * insignificantly different from each other, or {@code null} if there is no such ensemble. * @param cs the coordinate system. + * - * @see org.apache.sis.referencing.factory.GeodeticObjectFactory#createParametricCRS(Map, ParametricDatum, ParametricCS) - * + * @since 1.5 */ public DefaultParametricCRS(final Map<String,?> properties, - final ParametricDatum datum, - final DatumEnsemble<ParametricDatum> ensemble, - final ParametricCS cs) + final DefaultParametricDatum datum, ++ final DefaultDatumEnsemble<DefaultParametricDatum> ensemble, + final DefaultParametricCS cs) { super(properties, cs); - this.datum = Objects.requireNonNull(datum); + this.datum = datum; + this.ensemble = ensemble; + checkDatum(datum, ensemble); checkDimension(1, 1, cs); } + /** - * @deprecated A {@code DatumEnsemble} argument has been added. ++ * @deprecated A {@code DefaultDatumEnsemble} argument has been added. + */ + @Deprecated(since="1.5", forRemoval=true) + public DefaultParametricCRS(final Map<String,?> properties, - final ParametricDatum datum, - final ParametricCS cs) ++ final DefaultParametricDatum datum, ++ final DefaultParametricCS cs) + { + this(properties, datum, null, cs); + } + /** * Creates a new CRS derived from the specified one, but with different axis order or unit. * This is for implementing the {@link #createSameType(AbstractCS)} method only. @@@ -146,20 -175,55 +175,25 @@@ * * <p>This constructor performs a shallow copy, i.e. the properties are not cloned.</p> * - * @param crs the coordinate reference system to copy. + * <div class="warning"><b>Warning:</b> in a future SIS version, the parameter type may be changed + * to {@code org.opengis.referencing.crs.ParametricCRS}. This change is pending GeoAPI revision.</div> * - * @see #castOrCopy(ParametricCRS) + * @param crs the coordinate reference system to copy. */ - protected DefaultParametricCRS(final ParametricCRS crs) { + protected DefaultParametricCRS(final DefaultParametricCRS crs) { super(crs); - datum = crs.getDatum(); + datum = crs.getDatum(); + ensemble = crs.getDatumEnsemble(); + checkDatum(datum, ensemble); } - /** - * Returns a SIS coordinate reference system implementation with the same values as the given - * arbitrary implementation. If the given object is {@code null}, then this method returns {@code null}. - * Otherwise if the given object is already a SIS implementation, then the given object is returned unchanged. - * Otherwise a new SIS implementation is created and initialized to the attribute values of the given object. - * - * @param object the object to get as a SIS implementation, or {@code null} if none. - * @return a SIS implementation containing the values of the given object (may be the - * given object itself), or {@code null} if the argument was null. - */ - public static DefaultParametricCRS castOrCopy(final ParametricCRS object) { - return (object == null || object instanceof DefaultParametricCRS) - ? (DefaultParametricCRS) object : new DefaultParametricCRS(object); - } - - /** - * Returns the GeoAPI interface implemented by this class. - * The SIS implementation returns {@code ParametricCRS.class}. - * - * <h4>Note for implementers</h4> - * Subclasses usually do not need to override this method since GeoAPI does not define {@code ParametricCRS} - * sub-interface. Overriding possibility is left mostly for implementers who wish to extend GeoAPI with their - * own set of interfaces. - * - * @return {@code ParametricCRS.class} or a user-defined sub-interface. - */ - @Override - public Class<? extends ParametricCRS> getInterface() { - return ParametricCRS.class; - } - /** - * Returns the datum. + * Returns the reference surface used as the origin of this <abbr>CRS</abbr>. + * This property may be null if this <abbr>CRS</abbr> is related to an object + * identified only by a {@linkplain #getDatumEnsemble() datum ensemble}. * - * @return the datum. + * @return the parametric datum, or {@code null} if this <abbr>CRS</abbr> is related to + * an object identified only by a {@linkplain #getDatumEnsemble() datum ensemble}. */ @Override @XmlElement(name = "parametricDatum", required = true) @@@ -167,6 -231,22 +201,26 @@@ return datum; } + /** + * Returns a collection of datums which, for low accuracy requirements, + * may be considered to be insignificantly different from each other. + * This property may be null if this <abbr>CRS</abbr> is related to an object + * identified only by a single {@linkplain #getDatum() datum}. + * ++ * <div class="warning"><b>Warning:</b> in a future SIS version, the return type may ++ * be changed to the {@code org.opengis.referencing.datum.DatumEnsemble} interface. ++ * This change is pending GeoAPI revision.</div> ++ * + * @return the datum ensemble, or {@code null} if this <abbr>CRS</abbr> is related + * to an object identified only by a single {@linkplain #getDatum() datum}. + * + * @since 1.5 + */ + @Override - public DatumEnsemble<ParametricDatum> getDatumEnsemble() { ++ public DefaultDatumEnsemble<DefaultParametricDatum> getDatumEnsemble() { + return ensemble; + } + /** * Returns the coordinate system. * diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultTemporalCRS.java index 59c3fef550,625064eddc..957e0076a9 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultTemporalCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultTemporalCRS.java @@@ -45,6 -44,6 +44,9 @@@ import org.apache.sis.math.Fraction import static org.apache.sis.util.privy.Constants.NANOS_PER_SECOND; import static org.apache.sis.util.privy.Constants.MILLIS_PER_SECOND; ++// Specific to the main branch: ++import org.apache.sis.referencing.datum.DefaultDatumEnsemble; ++ // Specific to the main and geoapi-3.1 branches: import org.apache.sis.temporal.TemporalDate; @@@ -100,6 -102,15 +102,15 @@@ public class DefaultTemporalCRS extend @SuppressWarnings("serial") // Most SIS implementations are serializable. private TemporalDatum datum; + /** + * Collection of reference frames which for low accuracy requirements may be considered to be + * insignificantly different from each other. May be {@code null} if there is no such ensemble. + * + * @see #getDatumEnsemble() + */ + @SuppressWarnings("serial") // Most SIS implementations are serializable. - private final DatumEnsemble<TemporalDatum> ensemble; ++ private final DefaultDatumEnsemble<TemporalDatum> ensemble; + /** * Conversion factor from values in this CRS to values in seconds. We use {@link UnitConverter} * instead of {@code double} because the SIS implementation of {@code UnitConverter} performs @@@ -160,14 -176,28 +176,28 @@@ @SuppressWarnings("this-escape") public DefaultTemporalCRS(final Map<String,?> properties, final TemporalDatum datum, - final TimeCS cs) - final DatumEnsemble<TemporalDatum> ensemble, ++ final DefaultDatumEnsemble<TemporalDatum> ensemble, + final TimeCS cs) { super(properties, cs); - this.datum = Objects.requireNonNull(datum); + this.datum = datum; + this.ensemble = ensemble; + checkDatum(datum, ensemble); checkDimension(1, 1, cs); initializeConverter(); } + /** - * @deprecated A {@code DatumEnsemble} argument has been added. ++ * @deprecated A {@code DefaultDatumEnsemble} argument has been added. + */ + @Deprecated(since="1.5", forRemoval=true) + public DefaultTemporalCRS(final Map<String,?> properties, + final TemporalDatum datum, + final TimeCS cs) + { + this(properties, datum, null, cs); + } + /** * Creates a new CRS derived from the specified one, but with different axis order or unit. * This is for implementing the {@link #createSameType(AbstractCS)} method only. @@@ -192,7 -223,9 +223,9 @@@ @SuppressWarnings("this-escape") protected DefaultTemporalCRS(final TemporalCRS crs) { super(crs); - datum = crs.getDatum(); + datum = crs.getDatum(); - ensemble = crs.getDatumEnsemble(); ++ ensemble = (crs instanceof DefaultTemporalCRS) ? ((DefaultTemporalCRS) crs).getDatumEnsemble() : null; + checkDatum(datum, ensemble); initializeConverter(); } @@@ -269,6 -305,22 +305,26 @@@ return datum; } + /** + * Returns a collection of datums which, for low accuracy requirements, + * may be considered to be insignificantly different from each other. + * This property may be null if this <abbr>CRS</abbr> is related to an object + * identified only by a single {@linkplain #getDatum() datum}. + * ++ * <div class="warning"><b>Warning:</b> in a future SIS version, the return type may ++ * be changed to the {@code org.opengis.referencing.datum.DatumEnsemble} interface. ++ * This change is pending GeoAPI revision.</div> ++ * + * @return the datum ensemble, or {@code null} if this <abbr>CRS</abbr> is related + * to an object identified only by a single {@linkplain #getDatum() datum}. + * + * @since 1.5 + */ + @Override - public DatumEnsemble<TemporalDatum> getDatumEnsemble() { ++ public DefaultDatumEnsemble<TemporalDatum> getDatumEnsemble() { + return ensemble; + } + /** * Returns the coordinate system. * diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultVerticalCRS.java index 3442f719b6,e5be3b1c7d..2fc9133ede --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultVerticalCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultVerticalCRS.java @@@ -31,6 -30,9 +30,9 @@@ import org.apache.sis.referencing.privy import org.apache.sis.metadata.privy.ImplementationHelper; import org.apache.sis.io.wkt.Formatter; -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import org.opengis.referencing.datum.DatumEnsemble; ++// Specific to the main branch: ++import org.apache.sis.referencing.datum.DefaultDatumEnsemble; + /** * A 1-dimensional coordinate reference system used for recording heights or depths. @@@ -79,8 -81,18 +81,18 @@@ public class DefaultVerticalCRS extend @SuppressWarnings("serial") // Most SIS implementations are serializable. private VerticalDatum datum; + /** + * Collection of reference frames which for low accuracy requirements may be considered to be + * insignificantly different from each other. May be {@code null} if there is no such ensemble. + * + * @see #getDatumEnsemble() + */ + @SuppressWarnings("serial") // Most SIS implementations are serializable. - private final DatumEnsemble<VerticalDatum> ensemble; ++ private final DefaultDatumEnsemble<VerticalDatum> ensemble; + /** * Creates a coordinate reference system from the given properties, datum and coordinate system. + * At least one of the {@code datum} and {@code ensemble} arguments shall be non-null. * The properties given in argument follow the same rules as for the * {@linkplain AbstractReferenceSystem#AbstractReferenceSystem(Map) super-class constructor}. * The following table is a reminder of main (not all) properties: @@@ -122,13 -138,27 +138,27 @@@ */ public DefaultVerticalCRS(final Map<String,?> properties, final VerticalDatum datum, - final VerticalCS cs) - final DatumEnsemble<VerticalDatum> ensemble, ++ final DefaultDatumEnsemble<VerticalDatum> ensemble, + final VerticalCS cs) { super(properties, cs); - this.datum = Objects.requireNonNull(datum); + this.datum = datum; + this.ensemble = ensemble; + checkDatum(datum, ensemble); checkDimension(1, 1, cs); } + /** - * @deprecated A {@code DatumEnsemble} argument has been added. ++ * @deprecated A {@code DefaultDatumEnsemble} argument has been added. + */ + @Deprecated(since="1.5", forRemoval=true) + public DefaultVerticalCRS(final Map<String,?> properties, + final VerticalDatum datum, + final VerticalCS cs) + { + this(properties, datum, null, cs); + } + /** * Creates a new CRS derived from the specified one, but with different axis order or unit. * This is for implementing the {@link #createSameType(AbstractCS)} method only. @@@ -151,7 -182,9 +182,9 @@@ */ protected DefaultVerticalCRS(final VerticalCRS crs) { super(crs); - datum = crs.getDatum(); + datum = crs.getDatum(); - ensemble = crs.getDatumEnsemble(); ++ ensemble = (crs instanceof DefaultVerticalCRS) ? ((DefaultVerticalCRS) crs).getDatumEnsemble() : null; + checkDatum(datum, ensemble); } /** @@@ -196,6 -232,22 +232,26 @@@ return datum; } + /** + * Returns a collection of datums which, for low accuracy requirements, + * may be considered to be insignificantly different from each other. + * This property may be null if this <abbr>CRS</abbr> is related to an object + * identified only by a single {@linkplain #getDatum() datum}. + * ++ * <div class="warning"><b>Warning:</b> in a future SIS version, the return type may ++ * be changed to the {@code org.opengis.referencing.datum.DatumEnsemble} interface. ++ * This change is pending GeoAPI revision.</div> ++ * + * @return the datum ensemble, or {@code null} if this <abbr>CRS</abbr> is related + * to an object identified only by a single {@linkplain #getDatum() datum}. + * + * @since 1.5 + */ + @Override - public DatumEnsemble<VerticalDatum> getDatumEnsemble() { ++ public DefaultDatumEnsemble<VerticalDatum> getDatumEnsemble() { + return ensemble; + } + /** * Returns the coordinate system. * diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/AbstractDatum.java index 5538212f17,e0f39c219d..3cd29c850f --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/AbstractDatum.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/AbstractDatum.java @@@ -95,6 -94,6 +96,24 @@@ public class AbstractDatum extends Abst */ private static final long serialVersionUID = 5380816794438838309L; ++ /** ++ * Key for the <code>{@value}</code> property to be given to the ++ * {@code DatumFactory.createFoo(Map, ...)} methods. ++ * This is used for setting the value to be returned by {@link #getPublicationDate()}. ++ * ++ * @since 1.5 ++ */ ++ public static final String PUBLICATION_DATE_KEY = "publicationDate"; ++ ++ /** ++ * Key for the <code>{@value}</code> property to be given to the ++ * {@code DatumFactory.createFoo(Map, ...)} methods. ++ * This is used for setting the value to be returned by {@link #getConventionalRS()}. ++ * ++ * @since 1.5 ++ */ ++ public static final String CONVENTIONAL_RS_KEY = "conventionalRS"; ++ /** * Description, possibly including coordinates, of the point or points used to anchor the datum to the Earth. * Also known as the "origin", especially for Engineering and Image Datums. @@@ -140,6 -155,14 +175,14 @@@ * <td>{@link Temporal}</td> * <td>{@link #getAnchorEpoch()}</td> * </tr><tr> - * <td>{@value org.opengis.referencing.datum.Datum#PUBLICATION_DATE_KEY}</td> ++ * <td>{@value #PUBLICATION_DATE_KEY}</td> + * <td>{@link Temporal}</td> + * <td>{@link #getPublicationDate()}</td> + * </tr><tr> - * <td>{@value org.opengis.referencing.datum.Datum#CONVENTIONAL_RS_KEY}</td> ++ * <td>{@value #CONVENTIONAL_RS_KEY}</td> + * <td>{@link IdentifiedObject}</td> + * <td>{@link #getConventionalRS()}</td> + * </tr><tr> * <th colspan="3" class="hsep">Defined in parent class (reminder)</th> * </tr><tr> * <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td> @@@ -192,11 -218,10 +237,19 @@@ */ protected AbstractDatum(final Datum datum) { super(datum); - anchorEpoch = datum.getAnchorEpoch().orElse(null); - anchorDefinition = datum.getAnchorDefinition().orElse(null); - publicationDate = datum.getPublicationDate().orElse(null); - conventionalRS = datum.getConventionalRS().orElse(null); + Date date = datum.getRealizationEpoch(); + if (date != null) { + anchorEpoch = date.toInstant(); + } + anchorDefinition = datum.getAnchorPoint(); ++ if (datum instanceof AbstractDatum) { ++ final var cd = (AbstractDatum) datum; ++ publicationDate = cd.getPublicationDate().orElse(null); ++ conventionalRS = cd.getConventionalRS().orElse(null); ++ } else { ++ publicationDate = null; ++ conventionalRS = null; ++ } } /** @@@ -307,35 -334,35 +360,59 @@@ @XmlSchemaType(name = "date") @XmlElement(name = "realizationEpoch") public Date getRealizationEpoch() { - return Datum.super.getRealizationEpoch(); + return getAnchorEpoch().map(Legacy::toDate).orElse(null); + } + + /** + * Returns the region or timeframe in which this datum is valid, or {@code null} if unspecified. + * + * @return area or region or timeframe in which this datum is valid, or {@code null}. + * + * @deprecated Replaced by {@link #getDomains()} as of ISO 19111:2019. + */ + @Override + @Deprecated(since = "1.4") + public Extent getDomainOfValidity() { + return Legacy.getDomainOfValidity(getDomains()); + } + + /** + * Returns the domain or limitations of usage, or {@code null} if unspecified. + * + * @return description of domain of usage, or limitations of usage, for which this datum object is valid. + * + * @deprecated Replaced by {@link #getDomains()} as of ISO 19111:2019. + */ + @Override + @Deprecated(since = "1.4") + public InternationalString getScope() { + return Legacy.getScope(getDomains()); } + /** + * Returns the date on which the datum definition was published. + * + * @return date on which the datum definition was published. + * + * @since 1.5 + */ - @Override + public Optional<Temporal> getPublicationDate() { + return Optional.ofNullable(publicationDate); + } + + /** + * Returns the name, identifier, alias and remarks for the reference system realized by this reference frame. + * All datums that are members of a {@linkplain DefaultDatumEnsemble datum ensemble} shall have the same + * conventional reference system. + * + * @return reference system realized by this reference frame. + * + * @since 1.5 + */ - @Override + public Optional<IdentifiedObject> getConventionalRS() { + return Optional.ofNullable(conventionalRS); + } + /** * Returns {@code true} if either the {@linkplain #getName() primary name} or at least * one {@linkplain #getAlias() alias} matches the given string according heuristic rules. diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultDatumEnsemble.java index 0000000000,9210e22176..fbade17b6d mode 000000,100644..100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultDatumEnsemble.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultDatumEnsemble.java @@@ -1,0 -1,273 +1,213 @@@ + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.sis.referencing.datum; + + import java.util.Map; + import java.util.List; + import java.util.Collection; -import java.util.Objects; + import org.apache.sis.io.wkt.Formatter; + import org.apache.sis.io.wkt.Convention; + import org.opengis.referencing.IdentifiedObject; + import org.opengis.referencing.datum.Datum; -import org.opengis.referencing.datum.DatumEnsemble; + import org.opengis.metadata.quality.PositionalAccuracy; + import org.apache.sis.referencing.AbstractIdentifiedObject; + import org.apache.sis.referencing.internal.Resources; + import org.apache.sis.referencing.privy.WKTKeywords; + import org.apache.sis.util.ArgumentChecks; + import org.apache.sis.util.ComparisonMode; + import org.apache.sis.util.Utilities; + + + /** + * Collection of datums which for low accuracy requirements may be considered + * to be insignificantly different from each other. + * + * @author OGC Topic 2 (for abstract model and documentation) + * @author Martin Desruisseaux (IRD, Geomatys) + * @version 1.5 + * + * @param <D> the type of datum contained in this ensemble. + * + * @since 1.5 + */ -public class DefaultDatumEnsemble<D extends Datum> extends AbstractIdentifiedObject implements DatumEnsemble<D> { ++public class DefaultDatumEnsemble<D extends Datum> extends AbstractIdentifiedObject { + /** + * Serial number for inter-operability with different versions. + */ + private static final long serialVersionUID = -2757133322734036975L; + + /** + * Datum or reference frames which are members of this ensemble. + */ + @SuppressWarnings("serial") // Standard Java implementations are serializable. + private final List<D> members; + + /** + * Inaccuracy introduced through use of this ensemble. + * This property is mandatory. + */ + @SuppressWarnings("serial") // Most SIS implementations are serializable. + private final PositionalAccuracy ensembleAccuracy; + + /** + * Creates a datum ensemble from the given properties. + * The properties given in argument follow the same rules as for the + * {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map) super-class constructor}. + * + * <table class="sis"> + * <caption>Recognized properties (non exhaustive list)</caption> + * <tr> + * <th>Property name</th> + * <th>Value type</th> + * <th>Returned by</th> + * </tr><tr> + * <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td> + * <td>{@link Identifier} or {@link String}</td> + * <td>{@link #getName()}</td> + * </tr><tr> + * <td>{@value org.opengis.referencing.IdentifiedObject#ALIAS_KEY}</td> + * <td>{@link GenericName} or {@link CharSequence} (optionally as array)</td> + * <td>{@link #getAlias()}</td> + * </tr><tr> + * <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td> + * <td>{@link Identifier} (optionally as array)</td> + * <td>{@link #getIdentifiers()}</td> + * </tr><tr> + * <td>{@value org.opengis.referencing.IdentifiedObject#DOMAINS_KEY}</td> + * <td>{@link org.opengis.referencing.ObjectDomain} (optionally as array)</td> + * <td>{@link #getDomains()}</td> + * </tr><tr> + * <td>{@value org.opengis.referencing.IdentifiedObject#REMARKS_KEY}</td> + * <td>{@link InternationalString} or {@link String}</td> + * <td>{@link #getRemarks()}</td> + * </tr> + * </table> + * + * @param properties the properties to be given to the identified object. + * @param members datum or reference frames which are members of this ensemble. + * @param accuracy inaccuracy introduced through use of this ensemble (mandatory). + * @throws IllegalArgumentException if at least two different + * {@linkplain AbstractDatum#getConventionalRS() conventional reference systems} are found. + */ + public DefaultDatumEnsemble(Map<String,?> properties, Collection<? extends D> members, PositionalAccuracy accuracy) { + super(properties); + ArgumentChecks.ensureNonNull("accuracy", accuracy); + ensembleAccuracy = accuracy; + this.members = List.copyOf(members); + validate(); + } + - /** - * Creates a new ensemble with the same values as the specified one. - * This copy constructor provides a way to convert an arbitrary implementation into a SIS one - * or a user-defined one (as a subclass), usually in order to leverage some implementation-specific API. - * - * <p>This constructor performs a shallow copy, i.e. the properties are not cloned.</p> - * - * @param ensemble the ensemble to copy. - */ - protected DefaultDatumEnsemble(final DatumEnsemble<? extends D> ensemble) { - super(ensemble); - members = List.copyOf(ensemble.getMembers()); - ensembleAccuracy = Objects.requireNonNull(ensemble.getEnsembleAccuracy()); - validate(); - } - - /** - * Returns a SIS ensemble implementation with the values of the given arbitrary implementation. - * This method performs the first applicable action in the following choices: - * - * <ul> - * <li>If the given object is {@code null}, then this method returns {@code null}.</li> - * <li>Otherwise if the given object is already an instance of - * {@code DefaultDatumEnsemble}, then it is returned unchanged.</li> - * <li>Otherwise a new {@code DefaultDatumEnsemble} instance is created using the - * {@linkplain #DefaultDatumEnsemble(DatumEnsemble) copy constructor} and returned. - * Note that this is a <em>shallow</em> copy operation, - * because the other properties contained in the given object are not recursively copied.</li> - * </ul> - * - * @param <D> the type of datum contained in the ensemble. - * @param object the object to get as a SIS implementation, or {@code null} if none. - * @return a SIS implementation containing the values of the given object (may be the - * given object itself), or {@code null} if the argument was null. - */ - public static <D extends Datum> DefaultDatumEnsemble<D> castOrCopy(final DatumEnsemble<D> object) { - if (object == null || object instanceof DefaultDatumEnsemble<?>) { - return (DefaultDatumEnsemble<D>) object; - } else { - return new DefaultDatumEnsemble<>(object); - } - } - + /** + * Verifies this ensemble. All members shall have the same conventional reference system. + */ + private void validate() { + IdentifiedObject rs = null; + for (final D datum : members) { - final IdentifiedObject dr = datum.getConventionalRS().orElse(null); ++ if (!(datum instanceof AbstractDatum)) continue; ++ final IdentifiedObject dr = ((AbstractDatum) datum).getConventionalRS().orElse(null); + if (dr != null) { + if (rs == null) { + rs = dr; + } else if (!rs.equals(dr)) { + throw new IllegalArgumentException(Resources.format(Resources.Keys.ShallHaveSameConventionalRS)); + } + } + } + } + - /** - * Returns the GeoAPI interface implemented by this class. - * The SIS implementation returns {@code DatumEnsemble.class}. - * - * <h4>Note for implementers</h4> - * Subclasses usually do not need to override this method since GeoAPI does not define {@code DatumEnsemble} - * sub-interface. Overriding possibility is left mostly for implementers who wish to extend GeoAPI with their - * own set of interfaces. - * - * @return the datum interface implemented by this class. - */ - @Override - @SuppressWarnings("unchecked") - public Class<? extends DatumEnsemble<D>> getInterface() { - return (Class) DatumEnsemble.class; - } - + /** + * Returns the datum or reference frames which are members of this ensemble. + * + * @return datum or reference frames which are members of this ensemble. + */ - @Override + @SuppressWarnings("ReturnOfCollectionOrArrayField") // Collection is unmodifiable. + public Collection<D> getMembers() { + return members; + } + + /** + * Returns the inaccuracy introduced through use of this ensemble. + * + * @return inaccuracy introduced through use of this ensemble. + */ - @Override + public PositionalAccuracy getEnsembleAccuracy() { + return ensembleAccuracy; + } + + /** + * Compares the specified object with this ensemble for equality. + * If the {@code mode} argument value is {@link ComparisonMode#STRICT STRICT} or + * {@link ComparisonMode#BY_CONTRACT BY_CONTRACT}, then all available properties are compared including the + * {@linkplain #getDomains() domains}. + * + * @param object the object to compare to {@code this}. + * @param mode {@link ComparisonMode#STRICT STRICT} for performing a strict comparison, or + * {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} for comparing only + * properties relevant to coordinate transformations. + * @return {@code true} if both objects are equal. + */ + @Override + public boolean equals(final Object object, final ComparisonMode mode) { + if (!super.equals(object, mode)) { + return false; + } + switch (mode) { + case STRICT: { + final var that = (DefaultDatumEnsemble) object; + return members.equals(that.members) && ensembleAccuracy.equals(that.ensembleAccuracy); + } + default: { - final var that = (DatumEnsemble) object; ++ if (!(object instanceof DefaultDatumEnsemble<?>)) { ++ return false; ++ } ++ final var that = (DefaultDatumEnsemble<?>) object; + return Utilities.deepEquals(getMembers(), that.getMembers(), mode) && + Utilities.deepEquals(getEnsembleAccuracy(), that.getEnsembleAccuracy(), mode); + } + } + } + + /** + * Invoked by {@code hashCode()} for computing the hash code when first needed. + * See {@link org.apache.sis.referencing.AbstractIdentifiedObject#computeHashCode()} + * for more information. + * + * @return the hash code value. This value may change in any future Apache SIS version. + * @hidden because not useful. + */ + @Override + protected long computeHashCode() { + return super.computeHashCode() + 7*members.hashCode() + 37*ensembleAccuracy.hashCode(); + } + + /** + * Formats the inner part of the <i>Well Known Text</i> (WKT) representation for this ensemble. + * See {@link AbstractIdentifiedObject#formatTo(Formatter)} for more information. + * + * @param formatter the formatter where to format the inner content of this WKT element. + * @return the {@linkplain org.apache.sis.io.wkt.KeywordCase#CAMEL_CASE CamelCase} keyword + * for the WKT element, or {@code null} if unknown. + */ + @Override + protected String formatTo(final Formatter formatter) { + super.formatTo(formatter); + if (Convention.WKT2_2015.compareTo(formatter.getConvention()) >= 0) { + formatter.setInvalidWKT(this, null); + } + return WKTKeywords.Ensemble; + } + } diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java index 10d288dde1,6401dbf97e..9e88d79f05 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java @@@ -57,10 -59,13 +59,13 @@@ import org.apache.sis.util.collection.W import org.apache.sis.util.iso.AbstractFactory; import org.apache.sis.util.resources.Messages; import org.apache.sis.util.resources.Errors; - import org.apache.sis.io.wkt.Parser; import org.apache.sis.util.logging.Logging; + import org.apache.sis.io.wkt.Parser; import org.apache.sis.xml.XML; -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import java.time.temporal.Temporal; ++// Specific to the main branch: ++import org.apache.sis.referencing.datum.DefaultDatumEnsemble; + /** * Creates {@linkplain org.apache.sis.referencing.crs.AbstractCRS Coordinate Reference System} (CRS) implementations, @@@ -315,15 -320,11 +320,15 @@@ public class GeodeticObjectFactory exte } /** - * Creates a geocentric coordinate reference system from a {@linkplain CartesianCS Cartesian coordinate system}. + * Creates a geocentric coordinate reference system from a Cartesian coordinate system. * Geocentric CRS have their origin at the approximate centre of mass of the earth. - * An {@linkplain #createGeodeticCRS(Map, GeodeticDatum, SphericalCS) alternate method} allows creation of the + * An {@linkplain #createGeocentricCRS(Map, GeodeticDatum, SphericalCS) alternate method} allows creation of the * same kind of CRS with spherical coordinate system instead of a Cartesian one. * + * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed to the + * {@link GeodeticCRS} parent interface. This is because ISO 19111 does not defines specific interface + * for the geocentric case. Users should assign the return value to a {@code GeodeticCRS} type.</div> + * * <h4>Dependencies</h4> * The components needed by this method can be created by the following methods: * <ol> @@@ -340,7 -343,38 +347,37 @@@ * The default implementation creates a {@link DefaultGeocentricCRS} instance. * * @param properties name and other properties to give to the new object. - * @param datum the geodetic reference frame to use in created CRS. + * @param datum geodetic reference frame, or {@code null} if the CRS is associated only to a datum ensemble. + * @param ensemble collection of reference frames which for low accuracy requirements may be considered to be + * insignificantly different from each other, or {@code null} if there is no such ensemble. + * @param cs the three-dimensional Cartesian coordinate system for the created CRS. + * @throws FactoryException if the object creation failed. + * + * @see GeodeticAuthorityFactory#createGeodeticCRS(String) + * @see DefaultGeocentricCRS#DefaultGeocentricCRS(Map, GeodeticDatum, CartesianCS) + * + * @since 1.5 + */ - @Override + public GeodeticCRS createGeodeticCRS(final Map<String,?> properties, + final GeodeticDatum datum, - final DatumEnsemble<GeodeticDatum> ensemble, ++ final DefaultDatumEnsemble<GeodeticDatum> ensemble, + final CartesianCS cs) + throws FactoryException + { + final DefaultGeocentricCRS crs; + try { + crs = new DefaultGeocentricCRS(complete(properties), datum, ensemble, cs); + } catch (IllegalArgumentException exception) { + throw new InvalidGeodeticParameterException(exception); + } + return unique("createGeodeticCRS", crs); + } + + /** + * Creates a geocentric coordinate reference system from a Cartesian coordinate system. + * + * @param properties name and other properties to give to the new object. + * @param datum the geodetic datum to use in created CRS. * @param cs the three-dimensional Cartesian coordinate system for the created CRS. * @throws FactoryException if the object creation failed. * @@@ -397,15 -433,11 +435,15 @@@ } /** - * Creates a geocentric coordinate reference system from a {@linkplain SphericalCS spherical coordinate system}. + * Creates a geocentric coordinate reference system from a spherical coordinate system. * Geocentric CRS have their origin at the approximate centre of mass of the earth. - * An {@linkplain #createGeodeticCRS(Map, GeodeticDatum, CartesianCS) alternate method} allows creation of the + * An {@linkplain #createGeocentricCRS(Map, GeodeticDatum, CartesianCS) alternate method} allows creation of the * same kind of CRS with Cartesian coordinate system instead of a spherical one. * + * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed to the + * {@link GeodeticCRS} parent interface. This is because ISO 19111 does not defines specific interface + * for the geocentric case. Users should assign the return value to a {@code GeodeticCRS} type.</div> + * * <h4>Dependencies</h4> * The components needed by this method can be created by the following methods: * <ol> @@@ -427,9 -463,39 +469,38 @@@ * @throws FactoryException if the object creation failed. * * @see DefaultGeocentricCRS#DefaultGeocentricCRS(Map, GeodeticDatum, SphericalCS) - * @see GeodeticAuthorityFactory#createGeodeticCRS(String) + * @see GeodeticAuthorityFactory#createGeocentricCRS(String) + * + * @since 1.5 + */ - @Override + public GeodeticCRS createGeodeticCRS(final Map<String,?> properties, + final GeodeticDatum datum, - final DatumEnsemble<GeodeticDatum> ensemble, ++ final DefaultDatumEnsemble<GeodeticDatum> ensemble, + final SphericalCS cs) + throws FactoryException + { + final DefaultGeocentricCRS crs; + try { + crs = new DefaultGeocentricCRS(complete(properties), datum, ensemble, cs); + } catch (IllegalArgumentException exception) { + throw new InvalidGeodeticParameterException(exception); + } + return unique("createGeodeticCRS", crs); + } + + /** + * Creates a geocentric coordinate reference system from a spherical coordinate system. + * + * @param properties name and other properties to give to the new object. + * @param datum the geodetic datum to use in created CRS. + * @param cs the three-dimensional Cartesian coordinate system for the created CRS. + * @throws FactoryException if the object creation failed. + * + * @deprecated ISO 19111:2019 does not define an explicit class for geocentric CRS. + * Use {@link #createGeodeticCRS(Map, GeodeticDatum, SphericalCS)} instead. */ @Override - @Deprecated(since = "2.0") // Temporary version number until this branch is released. ++ @Deprecated public GeocentricCRS createGeocentricCRS(final Map<String,?> properties, final GeodeticDatum datum, final SphericalCS cs) throws FactoryException { @@@ -499,9 -566,11 +571,10 @@@ * * @since 1.4 */ - @Override public SphericalCS createSphericalCS(final Map<String,?> properties, - final CoordinateSystemAxis axis0, - final CoordinateSystemAxis axis1) throws FactoryException + final CoordinateSystemAxis axis0, + final CoordinateSystemAxis axis1) + throws FactoryException { final DefaultSphericalCS cs; try { @@@ -541,10 -614,15 +618,14 @@@ * * @see DefaultGeographicCRS#DefaultGeographicCRS(Map, GeodeticDatum, EllipsoidalCS) * @see GeodeticAuthorityFactory#createGeographicCRS(String) + * + * @since 1.5 */ -- @Override public GeographicCRS createGeographicCRS(final Map<String,?> properties, - final GeodeticDatum datum, final EllipsoidalCS cs) throws FactoryException + final GeodeticDatum datum, - final DatumEnsemble<GeodeticDatum> ensemble, ++ final DefaultDatumEnsemble<GeodeticDatum> ensemble, + final EllipsoidalCS cs) + throws FactoryException { final DefaultGeographicCRS crs; try { @@@ -555,6 -633,33 +636,51 @@@ return unique("createGeographicCRS", crs); } ++ /** ++ * Creates a geographic <abbr>CRS</abbr> from a reference frame. ++ * This is a shortcut for the {@linkplain #createGeographicCRS(Map, GeodeticDatum, DefaultDatumEnsemble, EllipsoidalCS) ++ * more generic method} without datum ensemble. ++ * ++ * @param properties name and other properties to give to the new object. ++ * Available properties are {@linkplain ObjectFactory listed there}. ++ * @param datum geodetic reference frame to use in created CRS. ++ * @param cs the ellipsoidal coordinate system for the created CRS. ++ * @return the coordinate reference system for the given properties. ++ * @throws FactoryException if the object creation failed. ++ */ ++ @Override ++ public GeographicCRS createGeographicCRS(Map<String, ?> properties, GeodeticDatum datum, EllipsoidalCS cs) ++ throws FactoryException ++ { ++ return createGeographicCRS(properties, datum, null, cs); ++ } ++ + /** + * Creates a datum ensemble from a collection of members and an ensemble accuracy. + * + * @param <D> the type of datum contained in the ensemble. + * @param properties name and other properties to give to the new object. + * @param members datum or reference frames which are members of the datum ensemble. + * @param accuracy inaccuracy introduced through use of the given collection of datums. + * @return the datum ensemble for the given properties. + * @throws FactoryException if the object creation failed. + * + * @since 1.5 + */ - @Override - public <D extends Datum> DatumEnsemble<D> createDatumEnsemble(final Map<String,?> properties, ++ public <D extends Datum> DefaultDatumEnsemble<D> createDatumEnsemble(final Map<String,?> properties, + final Collection<? extends D> members, + final PositionalAccuracy accuracy) + throws FactoryException + { + final DefaultDatumEnsemble<D> ensemble; + try { + ensemble = new DefaultDatumEnsemble<>(complete(properties), members, accuracy); + } catch (IllegalArgumentException exception) { + throw new InvalidGeodeticParameterException(exception); + } + return unique("createDatumEnsemble", ensemble); + } + /** * Creates a geodetic reference frame from ellipsoid and (optionally) Bursa-Wolf parameters. * Geodetic reference frame defines the location and orientation of an ellipsoid that approximates the shape of the earth. @@@ -894,9 -1012,11 +1033,11 @@@ * <ol> * <li>{@link #createCoordinateSystemAxis(Map, String, AxisDirection, Unit)}</li> * <li>{@link #createVerticalCS(Map, CoordinateSystemAxis)}</li> - * <li>{@link #createVerticalDatum(Map, RealizationMethod)}</li> + * <li>{@link #createVerticalDatum(Map, VerticalDatumType)}</li> + * <li>{@link #createDatumEnsemble(Map, Collection, PositionalAccuracy)} (optional)</li> * </ol> * + * At least one of the {@code datum} and {@code ensemble} arguments shall be non-null. * The default implementation creates a {@link DefaultVerticalCRS} instance. * * @param properties name and other properties to give to the new object. @@@ -906,10 -1028,15 +1049,14 @@@ * * @see DefaultVerticalCRS#DefaultVerticalCRS(Map, VerticalDatum, VerticalCS) * @see GeodeticAuthorityFactory#createVerticalCRS(String) + * + * @since 1.5 */ -- @Override public VerticalCRS createVerticalCRS(final Map<String,?> properties, - final VerticalDatum datum, final VerticalCS cs) throws FactoryException + final VerticalDatum datum, - final DatumEnsemble<VerticalDatum> ensemble, ++ final DefaultDatumEnsemble<VerticalDatum> ensemble, + final VerticalCS cs) + throws FactoryException { final DefaultVerticalCRS crs; try { @@@ -920,6 -1047,33 +1067,25 @@@ return unique("createVerticalCRS", crs); } + /** - * Creates a vertical datum from a realization method. - * The default implementation creates a {@link DefaultVerticalDatum} instance. ++ * Creates a vertical <abbr>CRS</abbr> from a reference frame. ++ * This is a shortcut for the {@linkplain #createVerticalCRS(Map, VerticalDatum, DefaultDatumEnsemble, VerticalCS) ++ * more generic method} without datum ensemble. + * + * @param properties name and other properties to give to the new object. - * @param method the realization method of the vertical datum, or {@code null} if none. ++ * Available properties are {@linkplain ObjectFactory listed there}. ++ * @param datum vertical datum to use in created CRS. ++ * @param cs the vertical coordinate system for the created CRS. ++ * @return the coordinate reference system for the given properties. + * @throws FactoryException if the object creation failed. - * - * @see DefaultVerticalDatum#DefaultVerticalDatum(Map, RealizationMethod) - * @see GeodeticAuthorityFactory#createVerticalDatum(String) - * - * @since 2.0 (temporary version number until this branch is released) + */ + @Override - public VerticalDatum createVerticalDatum(final Map<String,?> properties, - final RealizationMethod method) ++ public VerticalCRS createVerticalCRS(Map<String, ?> properties, VerticalDatum datum, VerticalCS cs) + throws FactoryException + { - final DefaultVerticalDatum datum; - try { - datum = new DefaultVerticalDatum(complete(properties), method); - } catch (IllegalArgumentException exception) { - throw new InvalidGeodeticParameterException(exception); - } - return unique("createVerticalDatum", datum); ++ return createVerticalCRS(properties, datum, null, cs); + } + /** * Creates a vertical datum from an enumerated type value. * The default implementation creates a {@link DefaultVerticalDatum} instance. @@@ -996,10 -1158,14 +1167,13 @@@ * * @see DefaultTemporalCRS#DefaultTemporalCRS(Map, TemporalDatum, TimeCS) * @see GeodeticAuthorityFactory#createTemporalCRS(String) + * + * @since 1.5 */ -- @Override public TemporalCRS createTemporalCRS(final Map<String,?> properties, - final TemporalDatum datum, final TimeCS cs) throws FactoryException + final TemporalDatum datum, - final DatumEnsemble<TemporalDatum> ensemble, ++ final DefaultDatumEnsemble<TemporalDatum> ensemble, + final TimeCS cs) throws FactoryException { final DefaultTemporalCRS crs; try { @@@ -1010,6 -1176,6 +1184,25 @@@ return unique("createTemporalCRS", crs); } ++ /** ++ * Creates a temporal <abbr>CRS</abbr> from a datum. ++ * This is a shortcut for the {@linkplain #createTemporalCRS(Map, TemporalDatum, DefaultDatumEnsemble, TimeCS) ++ * more generic method} without datum ensemble. ++ * ++ * @param properties name and other properties to give to the new object. ++ * Available properties are {@linkplain ObjectFactory listed there}. ++ * @param datum temporal datum to use in created CRS. ++ * @param cs the temporal coordinate system for the created CRS. ++ * @return the coordinate reference system for the given properties. ++ * @throws FactoryException if the object creation failed. ++ */ ++ @Override ++ public TemporalCRS createTemporalCRS(Map<String, ?> properties, TemporalDatum datum, TimeCS cs) ++ throws FactoryException ++ { ++ return createTemporalCRS(properties, datum, null, cs); ++ } ++ /** * Creates a temporal datum from an enumerated type value. * The default implementation creates a {@link DefaultTemporalDatum} instance. @@@ -1023,7 -1189,8 +1216,8 @@@ */ @Override public TemporalDatum createTemporalDatum(final Map<String,?> properties, - final Date origin) throws FactoryException - final Temporal origin) ++ final Date origin) + throws FactoryException { final DefaultTemporalDatum datum; try { @@@ -1077,25 -1245,30 +1272,34 @@@ * <li>{@link #createCoordinateSystemAxis(Map, String, AxisDirection, Unit)}</li> * <li>{@link #createParametricCS(Map, CoordinateSystemAxis)}</li> * <li>{@link #createParametricDatum(Map)}</li> + * <li>{@link #createDatumEnsemble(Map, Collection, PositionalAccuracy)} (optional)</li> * </ol> * + * At least one of the {@code datum} and {@code ensemble} arguments shall be non-null. * The default implementation creates a {@link DefaultParametricCRS} instance. * + * <div class="warning"><b>Warning:</b> in a future SIS version, the parameter types may be changed to + * {@code org.opengis.referencing.datum.ParametricDatum} and {@code org.opengis.referencing.cs.ParametricCS}, + * and the return type may be changed to {@code org.opengis.referencing.crs.ParametricCRS}. + * Those change are pending GeoAPI revision.</div> + * * @param properties name and other properties to give to the new object. - * @param datum the parametric datum to use in created CRS. + * @param datum parametric datum, or {@code null} if the CRS is associated only to a datum ensemble. + * @param ensemble collection of datum which for low accuracy requirements may be considered to be + * insignificantly different from each other, or {@code null} if there is no such ensemble. * @param cs the parametric coordinate system for the created CRS. * @throws FactoryException if the object creation failed. * - * @see DefaultParametricCRS#DefaultParametricCRS(Map, ParametricDatum, ParametricCS) + * @see DefaultParametricCRS#DefaultParametricCRS(Map, DefaultParametricDatum, DefaultParametricCS) * @see GeodeticAuthorityFactory#createParametricCRS(String) + * + * @since 1.5 */ - @Override - public ParametricCRS createParametricCRS(final Map<String,?> properties, - final ParametricDatum datum, - final DatumEnsemble<ParametricDatum> ensemble, - final ParametricCS cs) + public DefaultParametricCRS createParametricCRS(final Map<String,?> properties, - final DefaultParametricDatum datum, final DefaultParametricCS cs) throws FactoryException ++ final DefaultParametricDatum datum, ++ final DefaultDatumEnsemble<DefaultParametricDatum> ensemble, ++ final DefaultParametricCS cs) + throws FactoryException { final DefaultParametricCRS crs; try { @@@ -1106,6 -1279,6 +1310,26 @@@ return unique("createParametricCRS", crs); } ++ /** ++ * Creates a parametric <abbr>CRS</abbr> from a datum. ++ * This is a shortcut for the {@linkplain #createParametricCRS(Map, ParametricDatum, DatumEnsemble, ParametricCS) ++ * more generic method} without datum ensemble. ++ * ++ * @param properties name and other properties to give to the new object. ++ * Available properties are {@linkplain ObjectFactory listed there}. ++ * @param datum temporal datum to use in created CRS. ++ * @param cs the temporal coordinate system for the created CRS. ++ * @return the coordinate reference system for the given properties. ++ * @throws FactoryException if the object creation failed. ++ */ ++ public DefaultParametricCRS createParametricCRS(final Map<String,?> properties, ++ final DefaultParametricDatum datum, ++ final DefaultParametricCS cs) ++ throws FactoryException ++ { ++ return createParametricCRS(properties, datum, null, cs); ++ } ++ /** * Creates a parametric datum. * The default implementation creates a {@link DefaultParametricDatum} instance. @@@ -1153,7 -1321,11 +1377,10 @@@ * @see DefaultParametricCS#DefaultParametricCS(Map, CoordinateSystemAxis) * @see GeodeticAuthorityFactory#createParametricCS(String) */ - public DefaultParametricCS createParametricCS(Map<String, ?> properties, CoordinateSystemAxis axis) throws FactoryException { - @Override - public ParametricCS createParametricCS(final Map<String, ?> properties, ++ public DefaultParametricCS createParametricCS(final Map<String, ?> properties, + final CoordinateSystemAxis axis) + throws FactoryException + { final DefaultParametricCS cs; try { cs = new DefaultParametricCS(complete(properties), axis); @@@ -1313,10 -1491,15 +1546,14 @@@ * * @see DefaultEngineeringCRS#DefaultEngineeringCRS(Map, EngineeringDatum, CoordinateSystem) * @see GeodeticAuthorityFactory#createEngineeringCRS(String) + * + * @since 1.5 */ -- @Override public EngineeringCRS createEngineeringCRS(final Map<String,?> properties, - final EngineeringDatum datum, final CoordinateSystem cs) throws FactoryException + final EngineeringDatum datum, - final DatumEnsemble<EngineeringDatum> ensemble, ++ final DefaultDatumEnsemble<EngineeringDatum> ensemble, + final CoordinateSystem cs) + throws FactoryException { final DefaultEngineeringCRS crs; try { @@@ -1327,6 -1510,6 +1564,25 @@@ return unique("createEngineeringCRS", crs); } ++ /** ++ * Creates a engineering <abbr>CRS</abbr> from a datum. ++ * This is a shortcut for the {@linkplain #createEngineeringCRS(Map, EngineeringDatum, DefaultDatumEnsemble, CoordinateSystem) ++ * more generic method} without datum ensemble. ++ * ++ * @param properties name and other properties to give to the new object. ++ * Available properties are {@linkplain ObjectFactory listed there}. ++ * @param datum engineering datum to use in created CRS. ++ * @param cs the coordinate system for the created CRS. ++ * @return the coordinate reference system for the given properties. ++ * @throws FactoryException if the object creation failed. ++ */ ++ @Override ++ public EngineeringCRS createEngineeringCRS(Map<String, ?> properties, EngineeringDatum datum, CoordinateSystem cs) ++ throws FactoryException ++ { ++ return createEngineeringCRS(properties, datum, null, cs); ++ } ++ /** * Creates an engineering datum. * The default implementation creates a {@link DefaultEngineeringDatum} instance. diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ReferencingUtilities.java index 886673f8e5,1b312740a4..54e8ba460e --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ReferencingUtilities.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ReferencingUtilities.java @@@ -52,13 -52,6 +52,14 @@@ import org.apache.sis.referencing.cs.De import org.apache.sis.referencing.internal.VerticalDatumTypes; import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory; +// Specific to the main branch: +import java.util.Collection; +import java.util.NoSuchElementException; +import org.opengis.referencing.ReferenceIdentifier; ++import org.apache.sis.pending.geoapi.referencing.MissingMethods; +import org.apache.sis.metadata.privy.Identifiers; +import org.apache.sis.xml.NilObject; + /** * A set of static methods working on GeoAPI referencing objects. @@@ -395,9 -344,10 +396,10 @@@ public final class ReferencingUtilitie if (crs instanceof GeographicCRS && Utilities.equalsIgnoreMetadata(normalizedCS, cs)) { return (GeographicCRS) crs; } + final var source = (GeodeticCRS) crs; return new DefaultGeographicCRS( Map.of(DefaultGeographicCRS.NAME_KEY, NilReferencingObject.UNNAMED), - ((GeodeticCRS) crs).getDatum(), normalizedCS); - source.getDatum(), source.getDatumEnsemble(), normalizedCS); ++ source.getDatum(), MissingMethods.getDatumEnsemble(source), normalizedCS); } if (crs instanceof CompoundCRS) { for (final CoordinateReferenceSystem e : ((CompoundCRS) crs).getComponents()) { diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java index 4aba0eb1e7,eb7371b579..a9e651991e --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java @@@ -30,6 -30,6 +30,9 @@@ import static org.junit.jupiter.api.Ass import org.apache.sis.test.TestCase; import static org.apache.sis.test.Assertions.assertEqualsIgnoreMetadata; ++// Specific to the main branch: ++import static org.apache.sis.pending.geoapi.referencing.MissingMethods.getDatumEnsemble; ++ /** * Tests {@link IdentifiedObjectFinder}. @@@ -75,7 -75,7 +78,7 @@@ public final class IdentifiedObjectFind */ final CoordinateReferenceSystem search = new DefaultGeographicCRS( Map.of(DefaultGeographicCRS.NAME_KEY, CRS84.getName()), - CRS84.getDatum(), CRS84.getCoordinateSystem()); - CRS84.getDatum(), CRS84.getDatumEnsemble(), CRS84.getCoordinateSystem()); ++ CRS84.getDatum(), getDatumEnsemble(CRS84), CRS84.getCoordinateSystem()); assertEqualsIgnoreMetadata(CRS84, search); // Required condition for next test. finder.setSearchDomain(IdentifiedObjectFinder.Domain.DECLARATION); diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/DefaultConversionTest.java index 5f535526c4,8f4124dbd8..2ea4268ce1 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/DefaultConversionTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/DefaultConversionTest.java @@@ -50,8 -50,8 +50,9 @@@ import org.apache.sis.parameter.Default import static org.apache.sis.test.Assertions.assertMessageContains; import static org.apache.sis.test.Assertions.assertSerializedEquals; -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import static org.opengis.test.Assertions.assertMatrixEquals; +// Specific to the main branch: +import static org.apache.sis.test.GeoapiAssert.assertMatrixEquals; ++import static org.apache.sis.pending.geoapi.referencing.MissingMethods.getDatumEnsemble; /** @@@ -97,8 -98,10 +99,10 @@@ public final class DefaultConversionTes * Changes only the coordinate system of the given CRS, which is supposed geographic. */ private static GeographicCRS changeCS(final CoordinateReferenceSystem crs, final EllipsoidalCS cs) { - return new DefaultGeographicCRS(Map.of(DefaultGeographicCRS.NAME_KEY, crs.getName()), - ((GeodeticCRS) crs).getDatum(), cs); + final var source = (GeodeticCRS) crs; + return new DefaultGeographicCRS( + Map.of(DefaultGeographicCRS.NAME_KEY, crs.getName()), - source.getDatum(), source.getDatumEnsemble(), cs); ++ source.getDatum(), getDatumEnsemble(source), cs); } /** diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/MetadataTest.java index 7505b27228,36338f1c75..998643870f --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/MetadataTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/MetadataTest.java @@@ -238,10 -230,10 +238,10 @@@ public final class MetadataTest extend nameAndIdentifier("depth", "Depth", null), axis); final var datum = new DefaultVerticalDatum( - nameAndIdentifier("D28", "Depth below D28", "For testing purpose"), (RealizationMethod) null); + nameAndIdentifier("D28", "Depth below D28", "For testing purpose"), VerticalDatumType.OTHER_SURFACE); final var vcrs = new DefaultVerticalCRS( - nameAndIdentifier("D28", "Depth below D28", "CRS for testing purpose"), datum, cs); + nameAndIdentifier("D28", "Depth below D28", "CRS for testing purpose"), datum, null, cs); final var temporal = new DefaultTemporalExtent( OffsetDateTime.parse("1990-06-05T00:00Z"),