This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-3.1 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 90b66dd6adaf489e8feb543f89bbdb1e1e688a7f Merge: 56fa4c52ad 7997e9f006 Author: Martin Desruisseaux <[email protected]> AuthorDate: Sat Oct 4 12:45:44 2025 +0200 Merge branch 'geoapi-4.0' into geoapi-3.1. This merge is all about removal of deprecated methods. .../main/org/apache/sis/console/SIS.java | 3 +- .../org/apache/sis/console/TransformCommand.java | 4 +- .../apache/sis/coverage/grid/GridDerivation.java | 34 -- .../org/apache/sis/coverage/grid/GridExtent.java | 34 -- .../org/apache/sis/coverage/grid/GridGeometry.java | 17 - .../apache/sis/coverage/grid/PixelTranslation.java | 3 +- .../org/apache/sis/feature/FeatureOperations.java | 3 +- .../main/org/apache/sis/feature/Features.java | 3 +- .../main/org/apache/sis/image/ImageProcessor.java | 75 +--- .../main/org/apache/sis/image/package-info.java | 2 +- .../apache/sis/metadata/ModifiableMetadata.java | 66 +--- .../metadata/internal/shared/RecordSchemaSIS.java | 108 ------ .../apache/sis/metadata/iso/DefaultMetadata.java | 19 +- .../sis/metadata/iso/citation/Citations.java | 3 +- .../metadata/iso/citation/DefaultCitationDate.java | 17 +- .../iso/extent/DefaultGeographicDescription.java | 41 +- .../metadata/iso/extent/DefaultTemporalExtent.java | 46 +-- .../apache/sis/metadata/iso/extent/Extents.java | 22 +- .../sis/metadata/iso/extent/package-info.java | 6 +- .../maintenance/DefaultMaintenanceInformation.java | 4 +- .../org/apache/sis/metadata/iso/package-info.java | 2 +- .../org/apache/sis/temporal/LenientDateFormat.java | 8 +- .../org/apache/sis/util/iso/DefaultNameSpace.java | 6 +- .../org/apache/sis/util/iso/DefaultRecord.java | 26 +- .../apache/sis/util/iso/DefaultRecordSchema.java | 128 +++--- .../org/apache/sis/util/iso/DefaultRecordType.java | 86 +++-- .../main/org/apache/sis/util/iso/Names.java | 3 +- .../main/org/apache/sis/util/iso/Types.java | 63 +-- .../main/org/apache/sis/util/iso/package-info.java | 9 +- .../main/org/apache/sis/xml/Namespaces.java | 3 +- .../main/org/apache/sis/xml/XML.java | 3 +- .../sis/metadata/iso/DefaultMetadataTest.java | 105 +++-- .../iso/quality/DefaultQuantitativeResultTest.java | 23 +- .../sis/util/iso/DefaultRecordSchemaTest.java | 21 +- .../org/apache/sis/util/iso/DefaultRecordTest.java | 13 +- .../apache/sis/util/iso/DefaultRecordTypeTest.java | 10 +- .../sis/util/iso/SerializableRecordSchema.java | 81 ---- .../test/org/apache/sis/util/iso/TypesTest.java | 17 +- .../apache/sis/profile/france/FrenchProfile.java | 3 +- .../apache/sis/profile/japan/JapaneseProfile.java | 4 +- .../main/module-info.java | 1 + .../main/org/apache/sis/geometry/Envelopes.java | 25 +- .../apache/sis/geometry/GeneralDirectPosition.java | 12 +- .../main/org/apache/sis/geometry/Shapes2D.java | 3 +- .../main/org/apache/sis/geometry/package-info.java | 2 +- .../main/org/apache/sis/io/wkt/Formatter.java | 25 +- .../apache/sis/io/wkt/GeodeticObjectParser.java | 4 +- .../main/org/apache/sis/io/wkt/package-info.java | 2 +- .../org/apache/sis/parameter/TensorParameters.java | 89 ----- .../main/org/apache/sis/referencing/CRS.java | 3 +- .../main/org/apache/sis/referencing/CommonCRS.java | 12 +- .../apache/sis/referencing/IdentifiedObjects.java | 3 +- .../apache/sis/referencing/crs/AbstractCRS.java | 4 +- .../sis/referencing/crs/AbstractSingleCRS.java | 3 +- .../sis/referencing/crs/DefaultEngineeringCRS.java | 15 +- .../sis/referencing/crs/DefaultGeocentricCRS.java | 24 +- .../sis/referencing/crs/DefaultGeographicCRS.java | 13 +- .../sis/referencing/crs/DefaultParametricCRS.java | 13 +- .../sis/referencing/crs/DefaultTemporalCRS.java | 13 +- .../sis/referencing/crs/DefaultVerticalCRS.java | 13 +- .../org/apache/sis/referencing/crs/SubTypes.java | 1 + .../apache/sis/referencing/crs/package-info.java | 3 +- .../org/apache/sis/referencing/cs/AbstractCS.java | 1 + .../sis/referencing/cs/CoordinateSystems.java | 3 +- .../org/apache/sis/referencing/cs/SubTypes.java | 1 + .../sis/referencing/datum/AbstractDatum.java | 7 +- .../sis/referencing/datum/DatumOrEnsemble.java | 3 +- .../sis/referencing/datum/DefaultEllipsoid.java | 15 +- .../referencing/datum/DefaultGeodeticDatum.java | 2 +- .../sis/referencing/datum/TimeDependentBWP.java | 13 +- .../apache/sis/referencing/datum/package-info.java | 8 +- .../factory/GeodeticAuthorityFactory.java | 2 +- .../referencing/factory/GeodeticObjectFactory.java | 9 +- .../factory/MultiAuthoritiesFactory.java | 10 +- .../referencing/factory/sql/EPSGDataAccess.java | 3 +- .../factory/sql/InstallationScriptProvider.java | 22 -- .../internal/ParameterizedTransformBuilder.java | 17 + .../internal/PositionalAccuracyConstant.java | 4 +- .../{crs => legacy}/DefaultImageCRS.java | 153 +++++--- .../{datum => legacy}/DefaultImageDatum.java | 20 +- .../{cs => legacy}/DefaultUserDefinedCS.java | 46 +-- .../sis/referencing/legacy/package-info.java | 64 +++ .../operation/CoordinateOperationFinder.java | 4 +- .../operation/CoordinateOperationRegistry.java | 5 +- .../referencing/operation/DefaultConversion.java | 6 +- .../DefaultCoordinateOperationFactory.java | 59 +-- .../operation/InverseOperationMethod.java | 4 +- .../operation/matrix/AffineTransforms2D.java | 3 +- .../sis/referencing/operation/matrix/Matrices.java | 3 +- .../operation/projection/package-info.java | 15 +- .../GeocentricAffineBetweenGeographic.java | 15 +- .../operation/provider/MapProjection.java | 8 +- .../operation/transform/AbstractMathTransform.java | 51 +-- .../transform/DefaultMathTransformFactory.java | 429 +-------------------- .../transform/EllipsoidToCentricTransform.java | 45 +-- .../operation/transform/MathTransformProvider.java | 26 +- .../operation/transform/MathTransforms.java | 3 +- .../operation/transform/package-info.java | 2 +- .../org/apache/sis/referencing/package-info.java | 2 +- .../xml/bind/referencing/CC_OperationMethod.java | 4 +- .../sis/xml/bind/referencing/CD_ImageDatum.java | 2 +- .../sis/xml/bind/referencing/CS_UserDefinedCS.java | 2 +- .../apache/sis/referencing/crs/HardCodedCRS.java | 3 +- .../sis/referencing/datum/HardCodedDatum.java | 3 +- .../{crs => legacy}/DefaultImageCRSTest.java | 6 +- .../operation/CoordinateOperationFinderTest.java | 5 +- .../DefaultCoordinateOperationFactoryTest.java | 13 - .../transform/MathTransformFactoryMock.java | 2 - .../sis/storage/geotiff/base/GeoCodesTest.java | 4 +- .../main/org/apache/sis/storage/gpx/Metadata.java | 5 +- .../main/org/apache/sis/storage/DataStores.java | 3 +- .../main/org/apache/sis/storage/FeatureQuery.java | 19 +- .../main/org/apache/sis/storage/package-info.java | 2 +- .../main/org/apache/sis/io/IO.java | 3 +- .../main/org/apache/sis/math/DecimalFunctions.java | 3 +- .../main/org/apache/sis/math/MathFunctions.java | 3 +- .../main/org/apache/sis/measure/Quantities.java | 3 +- .../main/org/apache/sis/measure/Units.java | 3 +- .../main/org/apache/sis/system/Environment.java | 3 +- .../main/org/apache/sis/system/Loggers.java | 3 +- .../main/org/apache/sis/system/Threads.java | 3 +- .../main/org/apache/sis/util/ArgumentChecks.java | 51 +-- .../main/org/apache/sis/util/ArraysExt.java | 2 +- .../main/org/apache/sis/util/CharSequences.java | 2 +- .../main/org/apache/sis/util/Characters.java | 2 +- .../main/org/apache/sis/util/Classes.java | 2 +- .../main/org/apache/sis/util/Exceptions.java | 2 +- .../main/org/apache/sis/util/Locales.java | 2 +- .../main/org/apache/sis/util/Numbers.java | 2 +- .../main/org/apache/sis/util/ObjectConverters.java | 2 +- .../main/org/apache/sis/util/Static.java | 119 ------ .../main/org/apache/sis/util/StringBuilders.java | 31 +- .../main/org/apache/sis/util/Utilities.java | 2 +- .../org/apache/sis/util/collection/Containers.java | 3 +- .../org/apache/sis/util/collection/TreeTables.java | 3 +- .../main/org/apache/sis/util/logging/Logging.java | 3 +- .../main/org/apache/sis/util/package-info.java | 2 +- .../test/org/apache/sis/test/TestCase.java | 1 + geoapi/snapshot | 2 +- .../main/org/apache/sis/geometries/Geometries.java | 6 +- 140 files changed, 669 insertions(+), 2157 deletions(-) diff --cc endorsed/src/org.apache.sis.console/main/org/apache/sis/console/TransformCommand.java index ab2ebf406d,033046b050..9cc6be132a --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/TransformCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/TransformCommand.java @@@ -336,7 -336,10 +336,9 @@@ final class TransformCommand extends Fo if (steps.size() > 1) { var factory = DefaultCoordinateOperationFactory.provider(); var properties = IdentifiedObjects.getProperties(operation, CoordinateOperation.IDENTIFIERS_KEY); - operation = factory.createConcatenatedOperation(properties, steps.toArray(CoordinateOperation[]::new)); + operation = factory.createConcatenatedOperation( + properties, - null, null, // Infer source and target CRS from the first and last steps. + steps.toArray(CoordinateOperation[]::new)); } } /* diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java index 4650bf6ee5,c3bf681961..36cb145e84 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java @@@ -1767,8 -1768,7 +1767,8 @@@ class GeodeticObjectParser extends Math * @return the {@code "ImageDatum"} element. * @throws ParseException if the {@code "ImageDatum"} element cannot be parsed. */ - @SuppressWarnings("removal") - private DefaultImageDatum parseImageDatum(final int mode, final Element parent) throws ParseException { ++ @SuppressWarnings("deprecation") + private ImageDatum parseImageDatum(final int mode, final Element parent) throws ParseException { final Element element = parent.pullElement(mode, WKTKeywords.ImageDatum, WKTKeywords.IDatum); if (element == null) { return null; @@@ -1875,8 -1869,7 +1875,8 @@@ * @return the {@code "ImageCRS"} element as an {@link ImageCRS} object. * @throws ParseException if the {@code "ImageCRS"} element cannot be parsed. */ - @SuppressWarnings("removal") - private DefaultImageCRS parseImageCRS(final int mode, final Element parent) throws ParseException { ++ @SuppressWarnings("deprecation") + private ImageCRS parseImageCRS(final int mode, final Element parent) throws ParseException { final Element element = parent.pullElement(mode, WKTKeywords.ImageCRS); if (element == null) { return null; diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/SubTypes.java index 3e82a452fa,e02e655b75..6c4bf5ccee --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/SubTypes.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/SubTypes.java @@@ -31,9 -31,6 +31,10 @@@ import org.opengis.referencing.cs.Ellip import org.opengis.referencing.cs.SphericalCS; import org.apache.sis.referencing.cs.AxesConvention; +// Specific to the main and geoapi-3.1 branches: +import org.opengis.referencing.crs.ImageCRS; ++import org.apache.sis.referencing.legacy.DefaultImageCRS; + /** * Implementation of {@link AbstractCRS} methods that require knowledge about subclasses. diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/SubTypes.java index 7b3175687f,af854c09a0..45cb1dfb1e --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/SubTypes.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/SubTypes.java @@@ -30,9 -30,6 +30,10 @@@ import org.opengis.referencing.cs.TimeC import org.opengis.referencing.cs.VerticalCS; import org.apache.sis.referencing.internal.shared.AxisDirections; +// Specific to the main and geoapi-3.1 branches: +import org.opengis.referencing.cs.UserDefinedCS; ++import org.apache.sis.referencing.legacy.DefaultUserDefinedCS; + /** * Implementation of {@link AbstractCS} methods that require knowledge about subclasses. diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/AbstractDatum.java index 9cda8728df,6bbe6a10ce..c1694057e5 --- 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 @@@ -210,10 -212,8 +211,8 @@@ public class AbstractDatum extends Abst } anchorEpoch = Containers.property(properties, ANCHOR_EPOCH_KEY, Temporal.class); if (anchorEpoch == null) { - Date date = Containers.property(properties, REALIZATION_EPOCH_KEY, Date.class); - if (date != null) { - anchorEpoch = date.toInstant(); - } + anchorEpoch = TemporalDate.toTemporal( - Containers.property(properties, "realizationEpoch", Date.class)); // Legacy name. ++ Containers.property(properties, REALIZATION_EPOCH_KEY, Date.class)); } publicationDate = Containers.property(properties, PUBLICATION_DATE_KEY, Temporal.class); conventionalRS = Containers.property(properties, CONVENTIONAL_RS_KEY, IdentifiedObject.class); diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/package-info.java index e5b9f5e459,57bb360e1d..0da2635703 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/package-info.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/package-info.java @@@ -69,11 -68,9 +68,10 @@@ @XmlJavaTypeAdapter(EX_Extent.class), @XmlJavaTypeAdapter(CD_Ellipsoid.class), @XmlJavaTypeAdapter(CD_PrimeMeridian.class), + @XmlJavaTypeAdapter(CD_VerticalDatumType.class), - @XmlJavaTypeAdapter(CD_PixelInCell.class), @XmlJavaTypeAdapter(StringAdapter.class), @XmlJavaTypeAdapter(InternationalStringConverter.class), - @XmlJavaTypeAdapter(DateAdapter.class), + @XmlJavaTypeAdapter(DateAdapter.class) }) package org.apache.sis.referencing.datum; diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java index 1502f29759,f59f109dc8..733b76ce23 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java @@@ -810,30 -750,6 +810,30 @@@ public abstract class GeodeticAuthority return cast(EngineeringDatum.class, createDatum(code), code); } + /** + * Creates a datum defining the origin of an image coordinate reference system. + * An image datum is used in a local context only. + * For an image datum, the anchor point is usually either the centre of the image or the corner of the image. + * + * <h4>Default implementation</h4> + * The default implementation delegates to {@link #createDatum(String)} and casts the result. + * If the result cannot be casted, then a {@link NoSuchAuthorityCodeException} is thrown. + * + * @param code value allocated by authority. + * @return the datum for the given code. + * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found. + * @throws FactoryException if the object creation failed for some other reason. + * - * @see org.apache.sis.referencing.datum.DefaultImageDatum ++ * @see org.apache.sis.referencing.legacy.DefaultImageDatum + * + * @deprecated The {@code ImageDatum} class has been removed in ISO 19111:2019. + * It is replaced by {@code EngineeringDatum}. + */ + @Deprecated(since = "1.5") + public ImageDatum createImageDatum(final String code) throws NoSuchAuthorityCodeException, FactoryException { + return cast(ImageDatum.class, createDatum(code), code); + } + /** * Creates a geometric figure that can be used to describe the approximate shape of the earth. * In mathematical terms, it is a surface formed by the rotation of an ellipse about its minor axis. diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java index 308dda420a,c6210c1a8c..64593b9891 --- 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 @@@ -64,6 -64,6 +64,11 @@@ import org.apache.sis.util.logging.Logg import org.apache.sis.io.wkt.Parser; import org.apache.sis.xml.XML; ++// Specific the the main and geoapi-3.1 branches: ++import org.apache.sis.referencing.legacy.DefaultImageCRS; ++import org.apache.sis.referencing.legacy.DefaultImageDatum; ++import org.apache.sis.referencing.legacy.DefaultUserDefinedCS; ++ /** * Creates Coordinate Reference System (CRS) implementations, with their Coordinate System (CS) and Datum components. @@@ -366,31 -366,6 +371,31 @@@ public class GeodeticObjectFactory exte 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. + * + * @deprecated ISO 19111:2019 does not define an explicit class for geocentric CRS. + * Use {@link #createGeodeticCRS(Map, GeodeticDatum, CartesianCS)} instead. + */ + @Override + @Deprecated(since = "2.0") // Temporary version number until this branch is released. + public GeocentricCRS createGeocentricCRS(final Map<String,?> properties, + final GeodeticDatum datum, final CartesianCS cs) throws FactoryException + { + final DefaultGeocentricCRS crs; + try { - crs = new DefaultGeocentricCRS(complete(properties), datum, cs); ++ crs = new DefaultGeocentricCRS(complete(properties), datum, null, cs); + } catch (IllegalArgumentException exception) { + throw new InvalidGeodeticParameterException(exception); + } + return unique("createGeocentricCRS", crs); + } + /** * Creates a three-dimensional Cartesian coordinate system from the given set of axis. * This coordinate system can be used with geocentric, engineering and derived CRS. @@@ -479,31 -454,6 +484,31 @@@ 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. + public GeocentricCRS createGeocentricCRS(final Map<String,?> properties, + final GeodeticDatum datum, final SphericalCS cs) throws FactoryException + { + final DefaultGeocentricCRS crs; + try { - crs = new DefaultGeocentricCRS(complete(properties), datum, cs); ++ crs = new DefaultGeocentricCRS(complete(properties), datum, null, cs); + } catch (IllegalArgumentException exception) { + throw new InvalidGeodeticParameterException(exception); + } + return unique("createGeocentricCRS", crs); + } + /** * Creates a spherical coordinate system from the given set of axis. * This coordinate system can be used with geocentric, engineering and derived CRS. diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java index 7bc525f03f,b6dd73c42d..2fb3afd587 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java @@@ -1665,11 -1601,14 +1665,13 @@@ public class MultiAuthoritiesFactory ex * yet support swapping roles of source and target CRS if an implied-reverse coordinate * operation is included. */ - final CoordinateOperation[] ops = (CoordinateOperation[]) components; - String name = IdentifiedObjects.getIdentifierOrName(ops[0]) + " ⟶ " - + IdentifiedObjects.getIdentifierOrName(ops[ops.length - 1]); + final CoordinateOperation[] steps = (CoordinateOperation[]) components; + String name = IdentifiedObjects.getIdentifierOrName(steps[0]) + " ⟶ " + + IdentifiedObjects.getIdentifierOrName(steps[steps.length - 1]); combined = DefaultCoordinateOperationFactory.provider() - .createConcatenatedOperation(Map.of(CoordinateOperation.NAME_KEY, name), ops); + .createConcatenatedOperation( + Map.of(CoordinateOperation.NAME_KEY, name), - null, null, // Infer source and target CRS from the first and last steps. + steps); } break; } diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/DefaultImageCRS.java index df5b3187c0,0b2aee0320..4034b5a263 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/DefaultImageCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/DefaultImageCRS.java @@@ -22,16 -24,18 +24,22 @@@ import jakarta.xml.bind.annotation.XmlE import jakarta.xml.bind.annotation.XmlRootElement; import org.opengis.referencing.cs.AffineCS; import org.opengis.referencing.cs.CartesianCS; + import org.opengis.referencing.crs.SingleCRS; + import org.apache.sis.referencing.CommonCRS; import org.apache.sis.referencing.AbstractReferenceSystem; import org.apache.sis.referencing.internal.shared.WKTKeywords; - import org.apache.sis.referencing.cs.AxesConvention; - import org.apache.sis.referencing.cs.AbstractCS; + import org.apache.sis.referencing.internal.shared.NilReferencingObject; + import org.apache.sis.referencing.crs.AbstractCRS; + import org.apache.sis.metadata.internal.shared.ImplementationHelper; import org.apache.sis.io.wkt.Formatter; + import org.apache.sis.util.ComparisonMode; + import org.apache.sis.util.Utilities; + import org.apache.sis.util.collection.BackingStoreException; +// Specific to the main and geoapi-3.1 branches: +import org.opengis.referencing.crs.ImageCRS; +import org.opengis.referencing.datum.ImageDatum; + /** * A 2-dimensional engineering coordinate reference system applied to locations in images. @@@ -68,12 -62,22 +66,24 @@@ "datum" }) @XmlRootElement(name = "ImageCRS") - public final class DefaultImageCRS extends AbstractSingleCRS<ImageDatum> implements ImageCRS { -public final class DefaultImageCRS extends AbstractCRS implements SingleCRS { ++@SuppressWarnings("deprecation") ++public final class DefaultImageCRS extends AbstractCRS implements ImageCRS { /** * Serial number for inter-operability with different versions. */ private static final long serialVersionUID = 7222610270977351462L; + /** + * The datum, or {@code null} if the <abbr>CRS</abbr> is associated only to a datum ensemble. + * + * <p><b>Consider this field as final!</b> + * This field is non-final only for construction convenience and for unmarshalling.</p> + * + * @see #getDatum() + */ - private DefaultImageDatum datum; ++ @SuppressWarnings("serial") ++ private ImageDatum datum; + /** * 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 @@@ -112,68 -116,23 +122,53 @@@ * @param properties the properties to be given to the coordinate reference system. * @param datum the datum. * @param cs the coordinate system. - * - * @see org.apache.sis.referencing.factory.GeodeticObjectFactory#createImageCRS(Map, ImageDatum, AffineCS) */ public DefaultImageCRS(final Map<String,?> properties, - final DefaultImageDatum datum, - final AffineCS cs) + final ImageDatum datum, + final AffineCS cs) { - super(properties, ImageDatum.class, 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. - */ - private DefaultImageCRS(final DefaultImageCRS original, final AbstractCS cs) { - super(original, null, cs); + super(properties, cs); + this.datum = Objects.requireNonNull(datum); } + /** + * Constructs a new coordinate reference system 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 crs the coordinate reference system to copy. + * + * @see #castOrCopy(ImageCRS) + */ + protected DefaultImageCRS(final ImageCRS crs) { + super(crs); + } + + /** + * 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 DefaultImageCRS castOrCopy(final ImageCRS object) { + return (object == null) || (object instanceof DefaultImageCRS) + ? (DefaultImageCRS) object : new DefaultImageCRS(object); + } + /** * Returns the GeoAPI interface implemented by this class. - * The SIS implementation returns {@code ImageCRS.class}. - * - * <h4>Note for implementers</h4> - * Subclasses usually do not need to override this method since GeoAPI does not define {@code ImageCRS} - * sub-interface. Overriding possibility is left mostly for implementers who wish to extend GeoAPI with - * their own set of interfaces. * - * @return {@code ImageCRS.class} or a user-defined sub-interface. + * @return the coordinate reference system interface implemented by this class. */ @Override - public Class<? extends SingleCRS> getInterface() { - return SingleCRS.class; + public Class<? extends ImageCRS> getInterface() { + return ImageCRS.class; } /** @@@ -181,10 -140,9 +176,10 @@@ * * @return the datum. */ + @Override @XmlElement(name = "imageDatum", required = true) - public DefaultImageDatum getDatum() { + public ImageDatum getDatum() { - return super.getDatum(); + return datum; } /** @@@ -257,7 -222,8 +259,9 @@@ * <strong>This is not a valid object.</strong> This constructor is strictly * reserved to JAXB, which will assign values to the fields using reflection. */ ++ @SuppressWarnings("unused") private DefaultImageCRS() { + super(Map.of(NAME_KEY, NilReferencingObject.UNNAMED), CommonCRS.Engineering.DISPLAY.crs().getCoordinateSystem()); /* * The datum and the coordinate system are mandatory for SIS working. We do not verify their presence * here because the verification would have to be done in an 'afterMarshal(…)' method and throwing an @@@ -271,8 -237,12 +275,13 @@@ * * @see #getDatum() */ - private void setDatum(final DefaultImageDatum value) { ++ @SuppressWarnings("unused") + private void setDatum(final ImageDatum value) { - setDatum("imageDatum", value); + if (datum == null) { + datum = value; + } else { + ImplementationHelper.propertyAlreadySet(getClass(), "setDatum", "imageDatum"); + } } /** @@@ -298,14 -268,34 +307,38 @@@ * * @see <a href="http://issues.apache.org/jira/browse/SIS-166">SIS-166</a> */ - @XmlElement(name = "cartesianCS") private CartesianCS getCartesianCS() {return getCoordinateSystem(CartesianCS.class);} - @XmlElement(name = "affineCS") private AffineCS getAffineCS() {return getCoordinateSystem(AffineCS.class);} ++ @SuppressWarnings("unused") + @XmlElement(name = "cartesianCS") + private CartesianCS getCartesianCS() { + final AffineCS cs = getCoordinateSystem(); + return (cs instanceof CartesianCS) ? (CartesianCS) cs : null; + } + ++ @SuppressWarnings("unused") + @XmlElement(name = "affineCS") + private AffineCS getAffineCS() { + final AffineCS cs = getCoordinateSystem(); + return (cs instanceof CartesianCS) ? null : cs; + } /** * Used by JAXB only (invoked by reflection). * * @see #getCartesianCS() */ - private void setCartesianCS(final CartesianCS cs) {setCoordinateSystem("cartesianCS", cs);} - private void setAffineCS (final AffineCS cs) {setCoordinateSystem("affineCS", cs);} ++ @SuppressWarnings("unused") + private void setCartesianCS(final CartesianCS cs) { + setAffineCS(cs); + } + ++ @SuppressWarnings("unused") + private void setAffineCS(final AffineCS cs) { + try { + Field coordinateSystem = AbstractCRS.class.getDeclaredField("coordinateSystem"); + coordinateSystem.setAccessible(true); + coordinateSystem.set(this, cs); + } catch (ReflectiveOperationException e) { + throw new BackingStoreException(e); + } + } } diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/DefaultImageDatum.java index b1f7d1e645,8b58c01e80..9d706c2f6b --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/DefaultImageDatum.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/DefaultImageDatum.java @@@ -21,17 -21,18 +21,19 @@@ import java.util.Objects import jakarta.xml.bind.annotation.XmlType; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlRootElement; -import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import jakarta.xml.bind.annotation.adapters.CollapsedStringAdapter; import org.opengis.util.GenericName; import org.opengis.util.InternationalString; + import org.apache.sis.referencing.datum.AbstractDatum; import org.apache.sis.referencing.internal.shared.WKTKeywords; + import org.apache.sis.referencing.internal.shared.NilReferencingObject; import org.apache.sis.metadata.internal.shared.ImplementationHelper; import org.apache.sis.io.wkt.Formatter; -import org.apache.sis.io.wkt.ElementKind; import org.apache.sis.util.ComparisonMode; +// Specific to the main and geoapi-3.1 branches: +import org.opengis.referencing.datum.PixelInCell; +import org.opengis.referencing.datum.ImageDatum; + // Specific to the geoapi-3.1 and geoapi-4.0 branches: import org.opengis.metadata.Identifier; @@@ -46,21 -47,13 +48,14 @@@ * given to the constructor are also immutable. Unless otherwise noted in the javadoc, this condition holds if * all components were created using only SIS factories and static constants. * - * @deprecated The {@code ImageDatum} class has been removed in ISO 19111:2019. - * It is replaced by {@code EngineeringDatum}. - * * @author Martin Desruisseaux (IRD, Geomatys) - * @version 1.5 - * - * @see org.apache.sis.referencing.crs.DefaultImageCRS - * @see org.apache.sis.referencing.factory.GeodeticAuthorityFactory#createImageDatum(String) * - * @since 0.4 + * @see DefaultImageCRS */ - @Deprecated(since="1.5", forRemoval=true) // Actually to be moved to an internal package for GML and WKT purposes. ++@SuppressWarnings("deprecation") @XmlType(name = "ImageDatumType") @XmlRootElement(name = "ImageDatum") -public final class DefaultImageDatum extends AbstractDatum { +public final class DefaultImageDatum extends AbstractDatum implements ImageDatum { /** * Serial number for inter-operability with different versions. */ @@@ -121,10 -114,8 +116,8 @@@ * * @param properties the properties to be given to the identified object. * @param pixelInCell the way the image grid is associated with the image data attributes. - * - * @see org.apache.sis.referencing.factory.GeodeticObjectFactory#createImageDatum(Map, PixelInCell) */ - public DefaultImageDatum(final Map<String,?> properties, final String pixelInCell) { + public DefaultImageDatum(final Map<String,?> properties, final PixelInCell pixelInCell) { super(properties); this.pixelInCell = Objects.requireNonNull(pixelInCell); } @@@ -275,7 -210,8 +268,9 @@@ * <strong>This is not a valid object.</strong> This constructor is strictly * reserved to JAXB, which will assign values to the fields using reflection. */ ++ @SuppressWarnings("unused") private DefaultImageDatum() { + super(Map.of(NAME_KEY, NilReferencingObject.UNNAMED)); } /** @@@ -283,7 -219,7 +278,8 @@@ * * @see #getPixelInCell() */ - private void setPixelInCell(final String value) { ++ @SuppressWarnings("unused") + private void setPixelInCell(final PixelInCell value) { if (pixelInCell == null) { pixelInCell = value; } else { diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/DefaultUserDefinedCS.java index 525b514ee2,5dfab47009..b12b1f3532 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/DefaultUserDefinedCS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/DefaultUserDefinedCS.java @@@ -19,11 -19,10 +19,13 @@@ package org.apache.sis.referencing.lega import java.util.Map; import jakarta.xml.bind.annotation.XmlType; import jakarta.xml.bind.annotation.XmlRootElement; + import org.apache.sis.referencing.cs.AbstractCS; + import org.apache.sis.referencing.internal.shared.NilReferencingObject; import org.opengis.referencing.cs.CoordinateSystemAxis; +// Specific to the main and geoapi-3.1 branches: +import org.opengis.referencing.cs.UserDefinedCS; + /** * A 2- or 3-dimensional coordinate system for any combination of coordinate axes not covered by other CS types. @@@ -45,15 -44,10 +47,10 @@@ * constants. * * @author Martin Desruisseaux (IRD, Geomatys) - * @version 1.5 - * @since 0.4 - * - * @deprecated The {@code UserDefinedCS} class has been removed from ISO 19111:2019. */ - @Deprecated(since="1.5", forRemoval=true) // Actually to be moved to an internal package for GML and WKT purposes. @XmlType(name = "UserDefinedCSType") @XmlRootElement(name = "UserDefinedCS") -public final class DefaultUserDefinedCS extends AbstractCS { +public final class DefaultUserDefinedCS extends AbstractCS implements UserDefinedCS { /** * Serial number for inter-operability with different versions. */ @@@ -123,84 -113,7 +116,52 @@@ super(properties, axis0, axis1, axis2); } - /** - * Creates a new CS derived from the specified one, but with different axis order or unit. - * - * @see #createForAxes(String, CoordinateSystemAxis[]) - */ - private DefaultUserDefinedCS(DefaultUserDefinedCS original, String name, CoordinateSystemAxis[] axes) { - super(original, name, axes); - } - + /** + * Creates a new coordinate system 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 original the coordinate system to copy. + * + * @see #castOrCopy(UserDefinedCS) + */ + protected DefaultUserDefinedCS(final UserDefinedCS original) { + super(original); + } + + /** + * Returns a SIS coordinate 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 DefaultUserDefinedCS castOrCopy(final UserDefinedCS object) { + return (object == null) || (object instanceof DefaultUserDefinedCS) + ? (DefaultUserDefinedCS) object : new DefaultUserDefinedCS(object); + } + + /** + * Returns the GeoAPI interface implemented by this class. + * The SIS implementation returns {@code UserDefinedCS.class}. + * + * <h4>Note for implementers</h4> + * Subclasses usually do not need to override this method since GeoAPI does not define {@code UserDefinedCS} + * sub-interface. Overriding possibility is left mostly for implementers who wish to extend GeoAPI with their + * own set of interfaces. + * + * @return {@code UserDefinedCS.class} or a user-defined sub-interface. + */ + @Override + public Class<? extends UserDefinedCS> getInterface() { + return UserDefinedCS.class; + } - /** - * {@inheritDoc} - * - * @return {@inheritDoc} - */ - @Override - public DefaultUserDefinedCS forConvention(final AxesConvention convention) { - return (DefaultUserDefinedCS) super.forConvention(convention); - } - - /** - * Returns a coordinate system with different axes. - */ - @Override - final AbstractCS createForAxes(final String name, final CoordinateSystemAxis[] axes) { - switch (axes.length) { - case 2: // Fall through - case 3: return new DefaultUserDefinedCS(this, name, axes); - default: throw unexpectedDimension(axes, 2, 3); - } - } - - /* diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/package-info.java index 0000000000,254a1087b2..0eb36f4c4b mode 000000,100644..100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/package-info.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/legacy/package-info.java @@@ -1,0 -1,63 +1,64 @@@ + /* + * 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. + */ + + /** + * Referencing objects that existed in legacy international standards but have been removed in more recent editions. + * Those objects are kept for compatibility with, for example, Geographic Markup Language (<abbr>GML</abbr>) but are + * not anymore in public <abbr>API</abbr>. + * + * @author Martin Desruisseaux (Geomatys) + * @author Cédric Briançon (Geomatys) + */ + @XmlSchema(location = "http://schemas.opengis.net/gml/3.2.1/coordinateReferenceSystems.xsd", + elementFormDefault = XmlNsForm.QUALIFIED, namespace = Namespaces.GML, xmlns = + { + @XmlNs(prefix = "gml", namespaceURI = Namespaces.GML), + @XmlNs(prefix = "gmd", namespaceURI = LegacyNamespaces.GMD), + @XmlNs(prefix = "gco", namespaceURI = Namespaces.GCO), + @XmlNs(prefix = "xsi", namespaceURI = Namespaces.XSI) + }) + @XmlAccessorType(XmlAccessType.NONE) + @XmlJavaTypeAdapters({ + /* + * Do NOT declare the following adapters in this package-info: + * + * - CS_CoordinateSystem + * - SC_SingleCRS + * - SC_CRS + * + * Because the above types are the base type of many other types, + * adding the above adapters is a cause of confusion for JAXB. + * + * Note: be careful with CS_AffineCS and CS_CartesianCS relationship. + */ + @XmlJavaTypeAdapter(CD_ImageDatum.class), ++ @XmlJavaTypeAdapter(CD_PixelInCell.class), + @XmlJavaTypeAdapter(CS_CartesianCS.class), // Must be before CS_AffineCS. + @XmlJavaTypeAdapter(CS_AffineCS.class) + }) + package org.apache.sis.referencing.legacy; + + import jakarta.xml.bind.annotation.XmlNs; + import jakarta.xml.bind.annotation.XmlNsForm; + import jakarta.xml.bind.annotation.XmlSchema; + import jakarta.xml.bind.annotation.XmlAccessType; + import jakarta.xml.bind.annotation.XmlAccessorType; + import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapters; + import org.apache.sis.xml.Namespaces; + import org.apache.sis.xml.bind.referencing.*; + import org.apache.sis.xml.internal.shared.LegacyNamespaces; diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java index 23c530fa78,58a2f1df00..65c37a4e28 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java @@@ -1097,8 -1087,10 +1097,9 @@@ class CoordinateOperationRegistry switch (operations.size()) { case 0: return null; case 1: return operations.get(0); - default: return factory.createConcatenatedOperation(derivedFrom(operation), - operations.toArray(CoordinateOperation[]::new)); + default: return factory.createConcatenatedOperation( + derivedFrom(operation), - null, null, // Take source and target CRS from the first and last steps. + operations.toArray(CoordinateOperation[]::new)); } } diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java index 54abf78062,65397554b0..0cf9b63dbe --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java @@@ -24,14 -24,8 +24,10 @@@ import java.util.Objects import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReference; - import java.util.logging.Level; - import java.io.Serializable; import java.lang.reflect.Constructor; +import org.opengis.parameter.ParameterValueGroup; import org.opengis.parameter.ParameterNotFoundException; - import org.opengis.referencing.crs.GeodeticCRS; +import org.opengis.referencing.cs.CoordinateSystem; - import org.opengis.referencing.cs.EllipsoidalCS; import org.opengis.referencing.datum.Ellipsoid; import org.opengis.referencing.operation.Matrix; import org.opengis.referencing.operation.MathTransform; @@@ -498,531 -477,6 +491,111 @@@ public class DefaultMathTransformFactor return new ParameterizedTransformBuilder(this, getOperationMethod(method)); } + /** + * Returns the default parameter values for a math transform using the given operation method. + * The {@code method} argument is the name of any {@code OperationMethod} instance returned by + * <code>{@link #getAvailableMethods(Class) getAvailableMethods}({@linkplain SingleOperation}.class)</code>. + * Valid names are <a href="https://sis.apache.org/tables/CoordinateOperationMethods.html">listed here</a>. + * + * <p>This function creates new parameter instances at every call. + * Parameters are intended to be modified by the user before to be given to the + * {@link #createParameterizedTransform createParameterizedTransform(…)} method.</p> + * + * @param method the case insensitive name of the coordinate operation method to search for. + * @return a new group of parameter values for the {@code OperationMethod} identified by the given name. + * @throws NoSuchIdentifierException if there is no method registered for the given name or identifier. + * + * @see #getAvailableMethods(Class) + * @see #createParameterizedTransform(ParameterValueGroup) + * @see AbstractMathTransform#getParameterValues() + * + * @deprecated This {@linkplain #createParameterizedTransform way to create parameterized transform} is ambiguous. + * Use {@link #builder(String)} instead. + */ + @Override + @Deprecated(since="1.5") + public ParameterValueGroup getDefaultParameters(final String method) throws NoSuchIdentifierException { + return getOperationMethod(method).getParameters().createValue(); + } + - /** - * Source and target coordinate systems for which a new parameterized transform is going to be used. - * - * @author Martin Desruisseaux (Geomatys) - * @version 1.5 - * @since 0.7 - * - * @deprecated Replaced by {@link #builder(String)}. - */ - @SuppressWarnings("serial") - @Deprecated(since="1.5", forRemoval=true) - public static class Context implements MathTransformProvider.Context, Serializable { - /** - * The factory to use if the provider needs to create other math transforms as operation steps. - * - * @see #getFactory() - */ - private transient DefaultMathTransformFactory factory; - - /** - * Coordinate system of the source or target points. - */ - private CoordinateSystem sourceCS, targetCS; - - /** - * The ellipsoid of the source or target ellipsoidal coordinate system, or {@code null} if it does not apply. - */ - private Ellipsoid sourceEllipsoid, targetEllipsoid; - - /** - * The builder, created when first needed. - */ - private ParameterizedTransformBuilder builder; - - /** - * The parameters actually used. - */ - private ParameterValueGroup parameters; - - /** - * Creates a new context with all properties initialized to {@code null}. - */ - public Context() { - } - - /** - * Sets the source coordinate system to the given value. - * The source ellipsoid is unconditionally set to {@code null}. - * - * @param cs the coordinate system to set as the source (can be {@code null}). - * @deprecated Replaced by {@link MathTransform.Builder#setSourceAxes(CoordinateSystem, Ellipsoid)}. - */ - @Deprecated(since="1.5", forRemoval=true) - public void setSource(final CoordinateSystem cs) { - sourceCS = cs; - sourceEllipsoid = null; - builder = null; - } - - /** - * Sets the source coordinate system and related ellipsoid to the components of given CRS. - * The {@link Ellipsoid}, fetched from the geodetic reference frame, is often used together with an {@link EllipsoidalCS}, - * but not necessarily. The geodetic CRS may also be associated with a spherical or Cartesian coordinate system, - * and the ellipsoid information may still be needed even with those non-ellipsoidal coordinate systems. - * - * <p><strong>This method is not for datum shifts.</strong> - * All datum information other than the ellipsoid are ignored.</p> - * - * @param crs the coordinate system and ellipsoid to set as the source, or {@code null}. - * - * @since 1.3 - * @deprecated Replaced by {@link MathTransform.Builder#setSourceAxes(CoordinateSystem, Ellipsoid)}. - */ - @Deprecated(since="1.5", forRemoval=true) - public void setSource(final GeodeticCRS crs) { - if (crs != null) { - sourceCS = crs.getCoordinateSystem(); - sourceEllipsoid = DatumOrEnsemble.getEllipsoid(crs).orElse(null); - } else { - sourceCS = null; - sourceEllipsoid = null; - } - builder = null; - } - - /** - * Sets the target coordinate system to the given value. - * The target ellipsoid is unconditionally set to {@code null}. - * - * @param cs the coordinate system to set as the target (can be {@code null}). - * @deprecated Replaced by {@link MathTransform.Builder#setTargetAxes(CoordinateSystem, Ellipsoid)}. - */ - @Deprecated(since="1.5", forRemoval=true) - public void setTarget(final CoordinateSystem cs) { - targetCS = cs; - targetEllipsoid = null; - builder = null; - } - - /** - * Sets the target coordinate system and related ellipsoid to the components of given CRS. - * The {@link Ellipsoid}, fetched from the geodetic reference frame, is often used together with an {@link EllipsoidalCS}, - * but not necessarily. The geodetic CRS may also be associated with a spherical or Cartesian coordinate system, - * and the ellipsoid information may still be needed even with those non-ellipsoidal coordinate systems. - * - * <p><strong>This method is not for datum shifts.</strong> - * All datum information other than the ellipsoid are ignored.</p> - * - * @param crs the coordinate system and ellipsoid to set as the target, or {@code null}. - * - * @since 1.3 - * @deprecated Replaced by {@link MathTransform.Builder#setTargetAxes(CoordinateSystem, Ellipsoid)}. - */ - @Deprecated(since="1.5", forRemoval=true) - public void setTarget(final GeodeticCRS crs) { - if (crs != null) { - targetCS = crs.getCoordinateSystem(); - targetEllipsoid = DatumOrEnsemble.getEllipsoid(crs).orElse(null); - } else { - targetCS = null; - targetEllipsoid = null; - } - builder = null; - } - - /** - * Returns the source coordinate system, or {@code null} if unspecified. - * - * @return the source coordinate system, or {@code null}. - */ - public CoordinateSystem getSourceCS() { - return sourceCS; - } - - /** - * Returns the ellipsoid used together with the source coordinate system, or {@code null} if none. - * - * @return the ellipsoid used together with the source coordinate system, or {@code null} if none. - */ - public Ellipsoid getSourceEllipsoid() { - return sourceEllipsoid; - } - - /** - * Returns the target coordinate system, or {@code null} if unspecified. - * - * @return the target coordinate system, or {@code null}. - */ - public CoordinateSystem getTargetCS() { - return targetCS; - } - - /** - * Returns the ellipsoid used together with the target coordinate system, or {@code null} if none. - * - * @return the ellipsoid used together with the target coordinate system, or {@code null} if none. - */ - public Ellipsoid getTargetEllipsoid() { - return targetEllipsoid; - } - - /** - * Returns the builder to which to delegate the {@code MathTransform} creation. - */ - final ParameterizedTransformBuilder builder() throws FactoryException { - if (builder == null) { - if (factory == null) { - factory = provider(); - } - builder = new ParameterizedTransformBuilder(factory, null); - if (parameters != null) { - builder.setParameters(parameters, false); - } - } - return builder; - } - - /** - * Returns the matrix that represent the affine transform to concatenate before or after - * the parameterized transform. The {@code role} argument specifies which matrix is desired: - * - * <ul class="verbose"> - * <li>{@link org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#NORMALIZATION - * NORMALIZATION} for the conversion from the {@linkplain #getSourceCS() source coordinate system} to - * a {@linkplain AxesConvention#NORMALIZED normalized} coordinate system, usually with - * (<var>longitude</var>, <var>latitude</var>) axis order in degrees or - * (<var>easting</var>, <var>northing</var>) in metres. - * This normalization needs to be applied <em>before</em> the parameterized transform.</li> - * - * <li>{@link org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#DENORMALIZATION - * DENORMALIZATION} for the conversion from a normalized coordinate system to the - * {@linkplain #getTargetCS() target coordinate system}, for example with - * (<var>latitude</var>, <var>longitude</var>) axis order. - * This denormalization needs to be applied <em>after</em> the parameterized transform.</li> - * - * <li>{@link org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#INVERSE_NORMALIZATION INVERSE_NORMALIZATION} and - * {@link org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#INVERSE_DENORMALIZATION INVERSE_DENORMALIZATION} - * are also supported but rarely used.</li> - * </ul> - * - * This method is invoked by {@link DefaultMathTransformFactory#swapAndScaleAxes(MathTransform, Context)}. - * Users can override this method if they need to customize the normalization process. - * - * @param role whether the normalization or denormalization matrix is desired. - * @return the requested matrix, or {@code null} if this {@code Context} has no information about the coordinate system. - * @throws FactoryException if an error occurred while computing the matrix. - * - * @see DefaultMathTransformFactory#createAffineTransform(Matrix) - * @see DefaultMathTransformFactory#createParameterizedTransform(ParameterValueGroup, Context) - */ - @SuppressWarnings("fallthrough") - public Matrix getMatrix(final ContextualParameters.MatrixRole role) throws FactoryException { - return builder().getMatrix(role); - } - - /** - * Returns the operation method used for the math transform creation. - * This is the same information as {@link #getLastMethodUsed()} but more stable - * (not affected by transforms created with other contexts). - * - * @return the operation method used by the factory. - * @throws IllegalStateException if {@link #createParameterizedTransform(ParameterValueGroup, Context)} - * has not yet been invoked. - * - * @deprecated Replaced by {@link MathTransform.Builder#getMethod()}. - * - * @since 1.3 - */ - @Deprecated(since="1.5", forRemoval=true) - public OperationMethod getMethodUsed() { - return (builder != null) ? builder.getMethod().orElse(null) : null; - } - - /** - * Returns the names of parameters that have been inferred from the context. - * The set of keys can contain any of {@code "dim"}, - * {@code "semi_major"}, {@code "semi_minor"}, - * {@code "src_semi_major"}, {@code "src_semi_minor"}, - * {@code "tgt_semi_major"}, {@code "tgt_semi_minor"} and/or - * {@code "inverse_flattening"}, depending on the operation method used. - * The parameters named in that set are included in the parameters - * returned by {@link #getCompletedParameters()}. - * - * <h4>Associated Boolean values</h4> - * The associated Boolean in the map tells whether the named parameter value is really contextual. - * The Boolean is {@code FALSE} if the user explicitly specified a value in the parameters given to - * the {@link #createParameterizedTransform(ParameterValueGroup, Context)} method, - * and that value is different than the value inferred from the context. - * Such inconsistencies are also logged at {@link Level#WARNING}. - * In all other cases - * (no value specified by the user, or a value was specified but is consistent with the context), - * the associated Boolean in the map is {@code TRUE}. - * - * @deprecated Replaced by {@link MathTransformProvider.Context#getContextualParameters()}. - * - * @return names of parameters inferred from context. - * - * @since 1.3 - */ - @Override - @Deprecated(since="1.5", forRemoval=true) - public Map<String,Boolean> getContextualParameters() { - try { - return builder().getContextualParameters(); - } catch (FactoryException e) { - throw new IllegalStateException(MESSAGE, e); - } - } - - /** - * Returns the parameter values used for the math transform creation, - * including the parameters completed by the factory. - * This is the union of {@link #parameters} with {@link #getContextualParameters()}. - * The completed parameters may only have additional parameters compared to the user-supplied parameters. - * Parameter values that were explicitly set by the user are not overwritten. - * - * <p>After this method has been invoked, the {@link #setSourceAxes setSourceAxes(…)} - * and {@link #setTargetAxes setTargetAxes(…)} methods can no longer be invoked.</p> - * - * @deprecated Replaced by {@link MathTransformProvider.Context#getCompletedParameters()}. - * - * @return the parameter values used by the factory. - */ - @Override - @Deprecated(since="1.5", forRemoval=true) - public ParameterValueGroup getCompletedParameters() { - try { - return builder().getCompletedParameters(); - } catch (FactoryException e) { - throw new IllegalStateException(MESSAGE, e); - } - } - - /** - * The "{@code createParameterizedTransform} has not been invoked" error message. - */ - private static final String MESSAGE = "createParameterizedTransform has not been invoked."; - - /** - * Returns a string representation of this context for debugging purposes. - * The current implementation writes the name of source/target coordinate systems and ellipsoids. - * If the {@linkplain #getContextualParameters() contextual parameters} have already been inferred, - * then their names are appended with inconsistent parameters (if any) written on a separated line. - * - * @return a string representation of this context. - */ - @Override - public String toString() { - return (builder != null) ? builder.toString() : super.toString(); - } - } - + /** + * Creates a transform from a group of parameters. + * The set of expected parameters varies for each operation. + * The easiest way to provide parameter values is to get an initially empty group for the desired + * operation by calling {@link #getDefaultParameters(String)}, then to fill the parameter values. + * Example: + * + * {@snippet lang="java" : + * ParameterValueGroup group = factory.getDefaultParameters("Transverse_Mercator"); + * group.parameter("semi_major").setValue(6378137.000); + * group.parameter("semi_minor").setValue(6356752.314); + * MathTransform mt = factory.createParameterizedTransform(group); + * } + * + * Sometimes the {@code "semi_major"} and {@code "semi_minor"} parameter values are not explicitly provided, + * but rather inferred from the {@linkplain org.opengis.referencing.datum.GeodeticDatum geodetic + * reference frame} of the source Coordinate Reference System. + * + * @param parameters the parameter values. The {@linkplain ParameterDescriptorGroup#getName() parameter group name} + * shall be the name of the desired {@linkplain DefaultOperationMethod operation method}. + * @return the transform created from the given parameters. + * @throws NoSuchIdentifierException if there is no method for the given parameter group name. + * @throws FactoryException if the object creation failed. This exception is thrown + * if some required parameter has not been supplied, or has illegal value. + * + * @see #getDefaultParameters(String) + * @see #getAvailableMethods(Class) + * @see #getLastMethodUsed() + * @see org.apache.sis.parameter.ParameterBuilder#createGroupForMapProjection(ParameterDescriptor...) + * + * @deprecated This constructor is ambiguous when axis directions are parts of the map projection definition + * as in <q>Transverse Mercator (South Orientated)</q>. + * Use {@link #builder(String)} instead for allowing the implementation to resolve such ambiguities. + */ + @Override + @Deprecated(since="1.5") + public MathTransform createParameterizedTransform(final ParameterValueGroup parameters) + throws NoSuchIdentifierException, FactoryException + { + final var builder = new ParameterizedTransformBuilder(this, null); + builder.setParameters(parameters, false); + return builder.create(); + } + - /** - * Creates a transform from a group of parameters and a context. - * - * @param parameters the parameter values. - * @param context information about the context, or {@code null} if none. - * @return the transform created from the given parameters. - * @throws NoSuchIdentifierException if there is no method for the given parameter group name. - * @throws FactoryException if the object creation failed. - * @deprecated Replaced by a builder pattern with {@link #builder(String)}. - */ - @Deprecated(since="1.5", forRemoval=true) - public MathTransform createParameterizedTransform(final ParameterValueGroup parameters, - final Context context) throws NoSuchIdentifierException, FactoryException - { - if (context == null) { - return createParameterizedTransform(parameters); - } - context.builder = null; - context.factory = this; - context.parameters = parameters; - return context.builder().create(); - } - - /** - * Given a transform between normalized spaces, - * creates a transform taking in account axis directions, units of measurement and longitude rotation. - * This method {@linkplain #createConcatenatedTransform concatenates} the given parameterized transform - * with any other transform required for performing units changes and coordinates swapping. - * - * <p>The given {@code parameterized} transform shall expect - * {@linkplain org.apache.sis.referencing.cs.AxesConvention#NORMALIZED normalized} input coordinates and - * produce normalized output coordinates. See {@link org.apache.sis.referencing.cs.AxesConvention} for more - * information about what Apache SIS means by "normalized".</p> - * - * <h4>Example</h4> - * The most typical examples of transforms with normalized inputs/outputs are normalized - * map projections expecting (<var>longitude</var>, <var>latitude</var>) inputs in degrees - * and calculating (<var>x</var>, <var>y</var>) coordinates in metres, - * both of them with ({@linkplain org.opengis.referencing.cs.AxisDirection#EAST East}, - * {@linkplain org.opengis.referencing.cs.AxisDirection#NORTH North}) axis orientations. - * - * <h4>Controlling the normalization process</h4> - * Users who need a different normalized space than the default one may find more convenient to - * override the {@link Context#getMatrix Context.getMatrix(ContextualParameters.MatrixRole)} method. - * - * @param parameterized a transform for normalized input and output coordinates. - * @param context source and target coordinate systems in which the transform is going to be used. - * @return a transform taking in account unit conversions and axis swapping. - * @throws FactoryException if the object creation failed. - * - * @see org.apache.sis.referencing.cs.AxesConvention#NORMALIZED - * @see org.apache.sis.referencing.operation.DefaultConversion#DefaultConversion(Map, OperationMethod, MathTransform, ParameterValueGroup) - * - * @since 0.7 - * - * @deprecated Considered internal API because the definition of "normalized" is implementation-dependent. - */ - @Deprecated(since="1.5", forRemoval=true) - public MathTransform swapAndScaleAxes(final MathTransform parameterized, final Context context) throws FactoryException { - context.builder = null; - context.factory = this; - return context.builder().swapAndScaleAxes(parameterized); - } - + /** + * Creates a transform from a base CRS to a derived CS using the given parameters. + * If this method needs to set the values of {@code "semi_major"} and {@code "semi_minor"} parameters, + * then it sets those values directly on the given {@code parameters} instance – not on a clone – for + * allowing the caller to get back the complete parameter values. + * However, this method only fills missing values, it never modify existing values. + * + * @param baseCRS the source coordinate reference system. + * @param parameters the parameter values for the transform. + * @param derivedCS the target coordinate system. + * @return the parameterized transform from {@code baseCRS} to {@code derivedCS}, + * including unit conversions and axis swapping. + * @throws NoSuchIdentifierException if there is no transform registered for the coordinate operation method. + * @throws FactoryException if the object creation failed. This exception is thrown + * if some required parameter has not been supplied, or has illegal value. + * + * @deprecated Replaced by {@link #builder(String)}. + */ + @Override + @Deprecated(since="0.7") + public MathTransform createBaseToDerived(final CoordinateReferenceSystem baseCRS, + final ParameterValueGroup parameters, final CoordinateSystem derivedCS) + throws NoSuchIdentifierException, FactoryException + { + ArgumentChecks.ensureNonNull("baseCRS", baseCRS); + ArgumentChecks.ensureNonNull("parameters", parameters); + ArgumentChecks.ensureNonNull("derivedCS", derivedCS); + final var builder = new ParameterizedTransformBuilder(this, null); + builder.setParameters(parameters, true); + builder.setSourceAxes(baseCRS); + builder.setTargetAxes(derivedCS, null); + return builder.create(); + } + - /** - * Creates a math transform that represent a change of coordinate system. If exactly one argument is - * an {@linkplain org.apache.sis.referencing.cs.DefaultEllipsoidalCS ellipsoidal coordinate systems}, - * then the {@code ellipsoid} argument is mandatory. In all other cases (including the case where both - * coordinate systems are ellipsoidal), the ellipsoid argument is ignored and can be {@code null}. - * - * <h4>Design note</h4> - * This method does not accept separated ellipsoid arguments for {@code source} and {@code target} because - * this method should not be used for datum shifts. If the two given coordinate systems are ellipsoidal, - * then they are assumed to use the same ellipsoid. If different ellipsoids are desired, then a - * {@linkplain #createParameterizedTransform parameterized transform} like <q>Molodensky</q>, - * <q>Geocentric translations</q>, <q>Coordinate Frame Rotation</q> or - * <q>Position Vector transformation</q> should be used instead. - * - * @param source the source coordinate system. - * @param target the target coordinate system. - * @param ellipsoid the ellipsoid of {@code EllipsoidalCS}, or {@code null} if none. - * @return a conversion from the given source to the given target coordinate system. - * @throws FactoryException if the conversion cannot be created. - * - * @since 0.8 - * - * @deprecated Replaced by the following pattern: - * - * {@snippet lang="java" : - * var builder = builder("Coordinate system conversion"); - * builder.setSourceAxes(source, ellipsoid); - * builder.setTargetAxes(target, ellipsoid); - * return builder.create(); - * } - */ - @Deprecated(since="1.5", forRemoval=true) - public MathTransform createCoordinateSystemChange(final CoordinateSystem source, final CoordinateSystem target, - final Ellipsoid ellipsoid) throws FactoryException - { - ArgumentChecks.ensureNonNull("source", source); - ArgumentChecks.ensureNonNull("target", target); - lastMethod.remove(); // In case an exception is thrown before completion. - final var builder = builder(Constants.COORDINATE_SYSTEM_CONVERSION); - builder.setSourceAxes(source, ellipsoid); - builder.setTargetAxes(target, ellipsoid); - return builder.create(); - } - /** * Creates an affine transform from a matrix. If the transform input dimension is {@code M}, * and output dimension is {@code N}, then the matrix will have size {@code [N+1][M+1]}. The diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/CD_ImageDatum.java index b3eaa6bb7b,2c5bbdfe68..bf868b5f53 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/CD_ImageDatum.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/CD_ImageDatum.java @@@ -18,11 -18,8 +18,11 @@@ package org.apache.sis.xml.bind.referen import jakarta.xml.bind.annotation.XmlElement; import org.apache.sis.xml.bind.gco.PropertyType; - import org.apache.sis.referencing.datum.DefaultImageDatum; + import org.apache.sis.referencing.legacy.DefaultImageDatum; +// Specific to the main and geoapi-3.1 branches: +import org.opengis.referencing.datum.ImageDatum; + /** * JAXB adapter mapping implementing class to the GeoAPI interface. See diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/CS_UserDefinedCS.java index c1022ef664,7900672d33..1ae5d4b8fc --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/CS_UserDefinedCS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/CS_UserDefinedCS.java @@@ -17,12 -17,9 +17,12 @@@ package org.apache.sis.xml.bind.referencing; import jakarta.xml.bind.annotation.XmlElement; - import org.apache.sis.referencing.cs.DefaultUserDefinedCS; + import org.apache.sis.referencing.legacy.DefaultUserDefinedCS; import org.apache.sis.xml.bind.gco.PropertyType; +// Specific to the main and geoapi-3.1 branches: +import org.opengis.referencing.cs.UserDefinedCS; + /** * JAXB adapter mapping implementing class to the GeoAPI interface. See diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/crs/HardCodedCRS.java index fe0a120af7,f0949b31d8..853d08213a --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/crs/HardCodedCRS.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/crs/HardCodedCRS.java @@@ -323,9 -321,9 +324,9 @@@ public final class HardCodedCRS * this CS cannot be reprojected to a geographic coordinate reference system for example). * * <p>The {@code pixelInCell} attribute of the associated {@code ImageDatum} - * is set to {@link org.apache.sis.coverage.grid.PixelInCell#CELL_CENTER}.</p> + * is set to {@link PixelInCell#CELL_CENTER}.</p> */ - @SuppressWarnings("removal") + @SuppressWarnings("exports") public static final DefaultImageCRS IMAGE = new DefaultImageCRS( getProperties(HardCodedDatum.IMAGE), HardCodedDatum.IMAGE, HardCodedCS.GRID); diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/datum/HardCodedDatum.java index 6835ce3c59,b1d86a1c5f..255dbdae5c --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/datum/HardCodedDatum.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/datum/HardCodedDatum.java @@@ -155,12 -153,12 +156,12 @@@ public final class HardCodedDatum properties("Day of year", null, null)); /** - * Image with {@link org.apache.sis.coverage.grid.PixelInCell#CELL_CENTER}. + * Image with {@link PixelInCell#CELL_CENTER}. */ - @SuppressWarnings("removal") + @SuppressWarnings("exports") public static final DefaultImageDatum IMAGE = new DefaultImageDatum( properties("Image", null, null), - "cell center"); + PixelInCell.CELL_CENTER); /** * An engineering datum for unknown coordinate reference system. Such CRS are usually diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/legacy/DefaultImageCRSTest.java index fddc9ccf66,9b25e5ec04..d426f736bf --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/legacy/DefaultImageCRSTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/legacy/DefaultImageCRSTest.java @@@ -36,9 -35,6 +35,11 @@@ import org.apache.sis.referencing.cs.Ha import static org.apache.sis.metadata.Assertions.assertXmlEquals; import static org.apache.sis.referencing.Assertions.assertWktEquals; +// Specific to the main and geoapi-3.1 branches: +import org.opengis.referencing.datum.PixelInCell; ++import org.apache.sis.referencing.legacy.DefaultImageCRS; ++import org.apache.sis.referencing.legacy.DefaultImageDatum; + // Specific to the geoapi-3.1 and geoapi-4.0 branches: import static org.opengis.test.Assertions.assertAxisDirectionsEqual; diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java index e11160d4c7,059e817a19..b9812f5a92 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java @@@ -42,6 -42,6 +42,7 @@@ import org.opengis.referencing.operatio import org.apache.sis.referencing.CommonCRS; import org.apache.sis.referencing.CRS; import org.apache.sis.referencing.internal.PositionalAccuracyConstant; ++import org.apache.sis.referencing.internal.shared.CoordinateOperations; import org.apache.sis.referencing.operation.transform.LinearTransform; import org.apache.sis.referencing.operation.transform.MathTransforms; import org.apache.sis.referencing.operation.matrix.Matrices; diff --cc endorsed/src/org.apache.sis.storage.xml/main/org/apache/sis/storage/gpx/Metadata.java index 4d49a51d10,bbd3d7bb09..eb0d4f845d --- a/endorsed/src/org.apache.sis.storage.xml/main/org/apache/sis/storage/gpx/Metadata.java +++ b/endorsed/src/org.apache.sis.storage.xml/main/org/apache/sis/storage/gpx/Metadata.java @@@ -48,11 -49,8 +49,11 @@@ import org.apache.sis.metadata.iso.cita import org.apache.sis.metadata.iso.identification.DefaultKeywords; import org.apache.sis.metadata.iso.extent.Extents; import org.apache.sis.referencing.CommonCRS; - import org.apache.sis.util.iso.Types; + import org.apache.sis.temporal.TemporalDate; +// Specific to the main and geoapi-3.1 branches: +import org.opengis.metadata.citation.ResponsibleParty; + // Specific to the geoapi-3.1 and geoapi-4.0 branches: import org.opengis.metadata.citation.Responsibility; import org.apache.sis.metadata.iso.citation.Citations; diff --cc geoapi/snapshot index ec781af595,8cc86e44c8..4b998b7f66 --- a/geoapi/snapshot +++ b/geoapi/snapshot @@@ -1,1 -1,1 +1,1 @@@ - Subproject commit ec781af595a5b8a234550237ea5d6f4e4eb876f8 -Subproject commit 8cc86e44c8cebbb07cd65cd666354d1397a2e975 ++Subproject commit 4b998b7f663fc2ec95e1a8533597dc42f886b094
