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 428919e44a91cd9c40080b2d1630132d0ad322d4 Merge: 1483fcf71b ff6542a3f7 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Mon Apr 22 15:55:59 2024 +0200 Merge branch 'geoapi-3.1': reduce usage of `AxisDirection.OTHER` and `VerticalDatumType`. .../apache/sis/coverage/grid/GridExtentCRS.java | 6 +- .../apache/sis/metadata/iso/extent/Extents.java | 62 ++++----- .../sis/metadata/iso/extent/ExtentsTest.java | 9 +- .../apache/sis/io/wkt/GeodeticObjectParser.java | 22 +-- .../main/org/apache/sis/referencing/CRS.java | 4 +- .../main/org/apache/sis/referencing/CommonCRS.java | 24 ++-- .../org/apache/sis/referencing/cs/AbstractCS.java | 4 +- .../main/org/apache/sis/referencing/cs/Codes.java | 24 ++-- .../org/apache/sis/referencing/cs/Normalizer.java | 4 +- .../referencing/datum/DefaultVerticalDatum.java | 14 +- .../referencing/factory/sql/EPSGCodeFinder.java | 7 - .../referencing/factory/sql/EPSGDataAccess.java | 14 +- .../sis/referencing/factory/sql/TableInfo.java | 1 - .../apache/sis/referencing/internal/Legacy.java | 8 +- .../referencing/internal/VerticalDatumTypes.java | 147 ++++++++++++--------- .../operation/CoordinateOperationRegistry.java | 2 +- .../sis/referencing/operation/matrix/Matrices.java | 2 +- .../sis/referencing/privy/AxisDirections.java | 27 ++-- .../privy/EllipsoidalHeightCombiner.java | 3 +- .../referencing/privy/ReferencingUtilities.java | 7 +- .../org/apache/sis/io/wkt/TransliteratorTest.java | 13 +- .../org/apache/sis/referencing/CommonCRSTest.java | 20 +-- .../apache/sis/referencing/cs/HardCodedAxes.java | 4 +- .../datum/DefaultVerticalDatumTest.java | 4 +- .../sis/referencing/datum/HardCodedDatum.java | 2 +- .../referencing/datum/VerticalDatum (GML 3.1).xml | 2 +- .../internal/VerticalDatumTypesTest.java | 32 +++-- .../sis/referencing/privy/AxisDirectionsTest.java | 21 +-- .../org/apache/sis/storage/netcdf/base/Axis.java | 2 +- 29 files changed, 251 insertions(+), 240 deletions(-) diff --cc endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtentCRS.java index ae28430fdb,95020e45e4..8d078fddfd --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtentCRS.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtentCRS.java @@@ -296,7 -299,7 +296,7 @@@ final class GridExtentCRS abbreviation = "t"; direction = AxisDirection.FUTURE; hasTime = true; } else { abbreviation = abbreviation(target); - direction = AxisDirection.OTHER; - direction = AxisDirection.UNSPECIFIED; ++ direction = AxisDirections.UNSPECIFIED; hasOther = true; } /* @@@ -308,7 -311,7 +308,7 @@@ final CoordinateSystemAxis previous = axes[k]; if (previous != null) { if (direction.equals(AxisDirections.absolute(previous.getDirection()))) { - direction = AxisDirection.OTHER; - direction = AxisDirection.UNSPECIFIED; ++ direction = AxisDirections.UNSPECIFIED; hasOther = true; } if (abbreviation.equals(previous.getAbbreviation())) { @@@ -331,7 -334,7 +331,7 @@@ if (axes[j] == null) { final String name = Vocabulary.forLocale(locale).getString(Vocabulary.Keys.Dimension_1, j); final String abbreviation = abbreviation(j); - axes[j] = axis(csFactory, name, abbreviation, AxisDirection.OTHER); - axes[j] = axis(csFactory, name, abbreviation, AxisDirection.UNSPECIFIED); ++ axes[j] = axis(csFactory, name, abbreviation, AxisDirections.UNSPECIFIED); } } /* diff --cc endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/Extents.java index 360b50cc81,2fda0bf211..b4ec7fc882 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/Extents.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/Extents.java @@@ -371,16 -362,15 +365,15 @@@ public final class Extents extends Stat * performs a choice based on the vertical datum and the unit of measurement: * * <ul class="verbose"> - * <li><p><b>Choice based on vertical datum</b><br> + * <li><p><b>Choice based on realization method</b><br> - * Only the extents associated (indirectly, through their CRS) to the same non-null {@link RealizationMethod} + * Only the extents associated (indirectly, through their CRS) to the same non-null {@link VerticalDatumType} - * will be taken in account. If all datum types are null, then this method conservatively uses only the first - * vertical extent. Otherwise the datum type used for filtering the vertical extents is:</p> + * will be taken in account. If all realization methods are absent, then this method conservatively uses only + * the first vertical extent. Otherwise the realization method used for filtering the vertical extents is:</p> * * <ul> - * <li>{@link VerticalDatumType#GEOIDAL} or {@link VerticalDatumType#DEPTH DEPTH} if at least one extent - * uses those datum types. For this method, {@code DEPTH} is considered as equivalent to {@code GEOIDAL} - * except for the axis direction.</li> - * <li>Otherwise, the first non-null datum type found in iteration order.</li> - * <li>{@link RealizationMethod#GEOID} if at least one extent uses this realization method.</li> - * <li>Otherwise, {@link RealizationMethod#TIDAL} if at least one extent uses this realization method.</li> ++ * <li>{@link VerticalDatumType#GEOIDAL} if at least one extent uses this realization method.</li> ++ * <li>Otherwise, {@link VerticalDatumType#DEPTH} if at least one extent uses this realization method.</li> + * <li>Otherwise, the first non-null realization type found in iteration order.</li> * </ul> * * <div class="note"><b>Rational:</b> like {@linkplain #getGeographicBoundingBox(Extent) geographic bounding box}, @@@ -420,23 -409,21 +412,20 @@@ * @since 0.4 */ @OptionalCandidate - @SuppressWarnings("deprecation") public static MeasurementRange<Double> getVerticalRange(final Extent extent) { MeasurementRange<Double> range = null; - VerticalDatumType selectedType = null; - RealizationMethod selectedMethod = null; ++ VerticalDatumType selectedMethod = null; if (extent != null) { for (final VerticalExtent element : nonNull(extent.getVerticalElements())) { double min = element.getMinimumValue(); double max = element.getMaximumValue(); final VerticalCRS crs = element.getVerticalCRS(); - VerticalDatumType type = null; - RealizationMethod method = null; ++ VerticalDatumType method = null; Unit<?> unit = null; if (crs != null) { final VerticalDatum datum = crs.getDatum(); if (datum != null) { - type = datum.getVerticalDatumType(); - if (type == VerticalDatumType.DEPTH) { - type = VerticalDatumType.GEOIDAL; - } - method = datum.getRealizationMethod().orElse(method); ++ method = datum.getVerticalDatumType(); } final CoordinateSystemAxis axis = crs.getCoordinateSystem().getAxis(0); unit = axis.getUnit(); @@@ -456,14 -443,17 +445,17 @@@ } /* * If the new range is not measured relative to the same kind of surface than the previous range, - * then we do not know how to combine those ranges. Do nothing, unless the new range is a Mean Sea - * Level Height in which case we forget all previous ranges and use the new one instead. + * then we do not know how to combine those ranges. Do nothing, unless the new range is a geoidal + * height in which case we forget all previous ranges and use the new one instead. */ - if (!type.equals(selectedType)) { - if (!type.equals(VerticalDatumType.GEOIDAL)) { + if (method != selectedMethod) { - if (selectedMethod == RealizationMethod.GEOID || - (method != RealizationMethod.GEOID && - method != RealizationMethod.TIDAL)) ++ if (selectedMethod == VerticalDatumType.GEOIDAL || ++ (method != VerticalDatumType.GEOIDAL && ++ method != VerticalDatumType.DEPTH)) + { continue; } - } else if (selectedType != null) { + } else if (selectedMethod != null) { /* * If previous range did not specify any unit, then unconditionally replace it by * the new range since it provides more information. If both ranges specify units, diff --cc endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/extent/ExtentsTest.java index 71f0b919df,848979dc2f..f562dd5a60 --- a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/extent/ExtentsTest.java +++ b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/extent/ExtentsTest.java @@@ -31,6 -31,9 +31,9 @@@ import org.apache.sis.measure.Units import org.apache.sis.measure.MeasurementRange; import static org.apache.sis.metadata.privy.ReferencingServices.NAUTICAL_MILE; -// 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.datum.VerticalDatumType; + // Test dependencies import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@@ -82,7 -85,7 +85,7 @@@ public final class ExtentsTest extends Unit<?> unit = null; for (final DefaultVerticalExtent e : extents) { unit = e.getVerticalCRS().getCoordinateSystem().getAxis(0).getUnit(); - if (Units.isLinear(unit)) break; - if (e.getVerticalCRS().getDatum().getRealizationMethod().orElse(null) == RealizationMethod.GEOID) break; ++ if (e.getVerticalCRS().getDatum().getVerticalDatumType() == VerticalDatumType.GEOIDAL) break; } final UnitConverter c = unit.getConverterToAny(Units.METRE); /* diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java index 09d1ba92d7,643d8ceb56..af7f934d23 --- 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 @@@ -875,7 -865,7 +875,7 @@@ class GeodeticObjectParser extends Math if (defaultUnit == null) { throw parent.missingComponent(WKTKeywords.ParametricUnit); } - direction = AxisDirection.OTHER; - direction = AxisDirection.UNSPECIFIED; ++ direction = AxisDirections.UNSPECIFIED; nz = "Parametric"; z = "p"; break; @@@ -1461,12 -1446,13 +1461,12 @@@ return null; } final String name = element.pullString("name"); - VerticalDatumType type = null; - @SuppressWarnings("deprecation") - RealizationMethod method = null; ++ VerticalDatumType method = null; if (isWKT1) { - type = VerticalDatumTypes.fromLegacy(element.pullInteger("datum")); + method = VerticalDatumTypes.fromLegacy(element.pullInteger("datum")); } - if (type == null) { - type = VerticalDatumTypes.guess(name, null, null); + if (method == null) { + method = VerticalDatumTypes.guess(name, null, null); } final DatumFactory datumFactory = factories.getDatumFactory(); try { @@@ -2258,7 -2247,7 +2258,7 @@@ buffer.append(number); axes[i] = csFactory.createCoordinateSystemAxis( singletonMap(CoordinateSystemAxis.NAME_KEY, buffer.toString()), - number, AxisDirection.OTHER, Units.UNITY); - number, AxisDirection.UNSPECIFIED, Units.UNITY); ++ number, AxisDirections.UNSPECIFIED, Units.UNITY); } final Map<String,Object> properties = parseMetadataAndClose(element, name, baseCRS); final Map<String,Object> axisName = singletonMap(CoordinateSystem.NAME_KEY, AxisDirections.appendTo(new StringBuilder("CS"), axes)); diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CRS.java index 8873622ad1,7c012a1e8e..fc312dda24 --- 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 @@@ -945,8 -992,8 +945,8 @@@ public final class CRS extends Static * of the domain of validity of all components. * * <h4>Ellipsoidal height</h4> - * If a two-dimensional geographic or projected CRS if followed or preceded by a vertical CRS with ellipsoidal - * {@linkplain org.apache.sis.referencing.datum.DefaultVerticalDatum#getVerticalDatumType() datum type}, then + * If a two-dimensional geographic or projected CRS is followed or preceded by a vertical CRS with ellipsoidal - * {@linkplain org.apache.sis.referencing.datum.DefaultVerticalDatum#getRealizationMethod() realization method}, ++ * {@linkplain org.apache.sis.referencing.datum.DefaultVerticalDatum#getVerticalDatumType() datum type}, * this method combines them in a single three-dimensional geographic or projected CRS. Note that standalone * ellipsoidal heights are not allowed according ISO 19111. But if such situation is nevertheless found, then * the action described here fixes the issue. This is the reverse of <code>{@linkplain #getVerticalComponent diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java index 622d9c2836,8abad5348b..3ff72a19f8 --- 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 @@@ -48,9 -47,9 +48,9 @@@ import org.opengis.referencing.datum.Da import org.opengis.referencing.datum.Ellipsoid; import org.opengis.referencing.datum.GeodeticDatum; import org.opengis.referencing.datum.PrimeMeridian; + import org.opengis.referencing.datum.TemporalDatum; import org.opengis.referencing.datum.VerticalDatum; -import org.opengis.referencing.datum.RealizationMethod; +import org.opengis.referencing.datum.VerticalDatumType; - import org.opengis.referencing.datum.TemporalDatum; import org.opengis.referencing.datum.EngineeringDatum; import org.opengis.metadata.extent.GeographicBoundingBox; import static org.opengis.referencing.IdentifiedObject.NAME_KEY; @@@ -1259,8 -1247,8 +1256,6 @@@ public enum CommonCRS * <tr><th>Direction:</th> <td>{@link AxisDirection#UP}</td></tr> * <tr><th>Unit:</th> <td>{@link Units#METRE}</td></tr> * </table></blockquote> -- * - * @see VerticalDatumType#GEOIDAL - * @see RealizationMethod#TIDAL */ MEAN_SEA_LEVEL(true, (short) 5714, (short) 5100), @@@ -1274,8 -1262,8 +1269,6 @@@ * <tr><th>Direction:</th> <td>{@link AxisDirection#DOWN}</td></tr> * <tr><th>Unit:</th> <td>{@link Units#METRE}</td></tr> * </table></blockquote> -- * - * @see VerticalDatumType#GEOIDAL - * @see RealizationMethod#TIDAL */ DEPTH(true, (short) 5715, (short) 5100), @@@ -1343,9 -1332,8 +1337,8 @@@ * Creates a new enumeration value of the given name. * * <h4>API design note</h4> - * This constructor does not expect {@link VerticalDatumType} constant in order to avoid too - * early class initialization. In particular, we do not want early dependency to the SIS-specific - * {@code VerticalDatumTypes.ELLIPSOIDAL} constant. - * This constructor does not expect {@link RealizationMethod} constant in order to avoid ++ * This constructor does not expect {@link VerticalDatumType} constant in order to avoid + * the creation of non-standard code list value before they are actually needed. */ private Vertical(final boolean isEPSG, final short crs, final short datum) { this.isEPSG = isEPSG; @@@ -1481,7 -1467,16 +1472,12 @@@ if (isEPSG) { object = StandardDefinitions.createVerticalDatum(datum); } else { + /* + * All cases where the first constructor argument is `false`, currently BAROMETRIC and + * ELLIPSOIDAL. The way to construct the ellipsoidal pseudo-method shall be equivalent + * to a call to `VerticalDatumTypes.ellipsoidal()`. + */ - RealizationMethod method = null; - if (this != OTHER_SURFACE) { - method = RealizationMethod.valueOf(name()); - } - object = new DefaultVerticalDatum(properties(datum), method); + object = new DefaultVerticalDatum(properties(datum), VerticalDatumType.valueOf(name())); } cached = object; } diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/AbstractCS.java index 4a03d9f291,1625e20723..a43be5bf76 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/AbstractCS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/AbstractCS.java @@@ -228,7 -229,7 +228,7 @@@ public class AbstractCS extends Abstrac * more than one time axis. Such case happen in meteorological models. */ final AxisDirection dir = AxisDirections.absolute(direction); - if (!dir.equals(AxisDirection.OTHER)) { - if (dir != AxisDirection.UNSPECIFIED && dir != AxisDirection.OTHER) { ++ if (dir != AxisDirections.UNSPECIFIED && dir != AxisDirection.OTHER) { for (int j=i; --j>=0;) { final AxisDirection other = axes[j].getDirection(); final AxisDirection abs = AxisDirections.absolute(other); diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultVerticalDatum.java index 4f911e51e5,776b9d95dd..6b29262c9d --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultVerticalDatum.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultVerticalDatum.java @@@ -198,26 -223,15 +198,25 @@@ public class DefaultVerticalDatum exten } /** - * Returns the method through which this vertical reference frame is realized. + * Returns the type of this datum, or infers the type from the datum name if no type were specified. + * The latter case occurs after unmarshalling, since GML 3.2 does not contain any attribute for the datum type. + * It may also happen if the datum were created using reflection. + * - * <p>This method uses heuristic rules and may be changed in any future SIS version. If the type cannot be - * determined, default on the ellipsoidal type since it will usually implies no additional calculation.</p> ++ * <p>This method uses heuristic rules and may be changed in any future SIS version.</p> * - * @return method through which this vertical reference frame is realized. + * <p>No synchronization needed; this is not a problem if this value is computed twice. + * This method returns only existing immutable instances.</p> * - * @since 2.0 + * @see #getVerticalDatumType() + * @see #getTypeElement() */ - @Override - public Optional<RealizationMethod> getRealizationMethod() { - return Optional.ofNullable(method); + private VerticalDatumType type() { + VerticalDatumType t = type; + if (t == null) { + final ReferenceIdentifier name = super.getName(); + type = t = VerticalDatumTypes.guess(name != null ? name.getCode() : null, super.getAlias(), null); + } + return t; } /** @@@ -264,10 -283,9 +263,9 @@@ } default: { /* - * RealizationMethod is considered as metadata because it is related to the anchor definition, + * VerticalDatumType is considered as metadata because it is related to the anchor definition, * which is itself considered as metadata. Furthermore, GeodeticObjectParser and EPSGDataAccess - * do not always set this property to the same value: the former uses the information provided - * by the coordinate system axis while the other does not. + * do not always set this property to the same value, because of historical changes in the WKT. */ return true; } @@@ -290,10 -308,10 +288,10 @@@ * Formats this datum as a <i>Well Known Text</i> {@code VerticalDatum[…]} element. * * <h4>Compatibility note</h4> - * OGC 01-009 defined numerical codes for various vertical datum types, for example 2005 for geoidal height - * and 2002 for ellipsoidal height. Such codes were formatted for all {@code Datum} subtypes in WKT 1. - * Datum types became provided only for vertical datum in the ISO 19111:2003 specification, then removed - * completely in ISO 19111:2007. + * OGC 01-009 defined numerical codes for various vertical datum types, for example 2005 for geoidal height. + * Such codes were formatted for all {@code Datum} subtypes in WKT 1. Datum types became specified only for + * vertical datum in the ISO 19111:2003 standard, then removed completely in the ISO 19111:2007 standard. - * They were reintroduced in a different form ({@link RealizationMethod}) in the ISO 19111:2019 standard. ++ * They were reintroduced in a different form ({@code RealizationMethod}) in the ISO 19111:2019 standard. * * @return {@code "VerticalDatum"} (WKT 2) or {@code "Vert_Datum"} (WKT 1). * diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java index 3b89bbf16c,a05d123ee6..e8f36e5fb3 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java @@@ -1719,14 -1712,8 +1713,8 @@@ codes: for (int i=0; i<codes.length; i datum = datumFactory.createGeodeticDatum(properties, ellipsoid, meridian); break; } - /* - * Vertical datum type is hard-coded to geoidal. It would be possible to infer other - * types by looking at the coordinate system, but it could result in different datum - * associated to the same EPSG code. Since vertical datum type is no longer part of - * ISO 19111:2007, it is probably not worth to handle such cases. - */ case "vertical": { - datum = datumFactory.createVerticalDatum(properties, VERTICAL_DATUM_TYPE); - datum = datumFactory.createVerticalDatum(properties, (RealizationMethod) null); ++ datum = datumFactory.createVerticalDatum(properties, VerticalDatumType.GEOIDAL); break; } /* diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/Legacy.java index eba35c1897,ca37336531..ff134ec0fa --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/Legacy.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/Legacy.java @@@ -90,7 -63,8 +90,7 @@@ public final class Legacy * the ISO 19111's ones (ISO names are "Geocentric X", "Geocentric Y" and "Geocentric Z"). This constant uses * the invalid names and directions for WKT 1 parsing/formatting purposes. */ - private static final CartesianCS LEGACY = new DefaultCartesianCS(Map.of(NAME_KEY, "Legacy geocentric"), - @SuppressWarnings("deprecation") + private static final CartesianCS GEOCENTRIC = new DefaultCartesianCS(Map.of(NAME_KEY, "Legacy geocentric"), new DefaultCoordinateSystemAxis(Map.of(NAME_KEY, "X"), "X", AxisDirection.OTHER, Units.METRE), new DefaultCoordinateSystemAxis(Map.of(NAME_KEY, "Y"), "Y", AxisDirection.EAST, Units.METRE), new DefaultCoordinateSystemAxis(Map.of(NAME_KEY, "Z"), "Z", AxisDirection.NORTH, Units.METRE)); diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/VerticalDatumTypes.java index b6de9fa530,11f58d1e6d..6ccaa8d0c4 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/VerticalDatumTypes.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/VerticalDatumTypes.java @@@ -16,11 -16,11 +16,12 @@@ */ package org.apache.sis.referencing.internal; + import java.util.Locale; import java.util.Collection; +import java.util.function.Predicate; import javax.measure.Unit; +import org.opengis.util.CodeList; import org.opengis.util.GenericName; -import org.opengis.referencing.datum.RealizationMethod; import org.opengis.referencing.datum.VerticalDatumType; import org.opengis.referencing.cs.CoordinateSystemAxis; import org.opengis.referencing.cs.AxisDirection; @@@ -36,71 -35,93 +37,90 @@@ import org.apache.sis.measure.Units * Those constants are not in public API because they were intentionally omitted from ISO 19111, * and the ISO experts said that they should really not be public. * + * <p>This class implements {@link Predicate} for opportunist reasons. + * This implementation convenience may change in any future SIS version.</p> + * * @author Martin Desruisseaux (IRD, Geomatys) */ -public final class VerticalDatumTypes { +public final class VerticalDatumTypes implements Predicate<CodeList<?>> { /** - * A vertical datum for ellipsoidal heights that are measured along the - * normal to the ellipsoid used in the definition of horizontal datum. + * A pseudo-realization method for ellipsoidal heights that are measured along + * the normal to the ellipsoid used in the definition of horizontal datum. + * <strong>The use of this method is deprecated</strong> as ellipsoidal height + * should never be separated from the horizontal components according ISO 19111. * - * <p>Identifier: {@code CS_DatumType.CS_VD_Ellipsoidal}</p> + * <h4>Legacy</h4> + * This type was associated to code 2000 in the {@code Vert_Datum} element of the legacy WKT 1 format. + * The UML identifier was {@code CS_DatumType.CS_VD_Ellipsoidal}. + * + * @see org.apache.sis.referencing.CommonCRS.Vertical#ELLIPSOIDAL */ - public static final VerticalDatumType ELLIPSOIDAL = VerticalDatumType.valueOf("ELLIPSOIDAL"); + static final String ELLIPSOIDAL = "ELLIPSOIDAL"; /** - * A vertical datum for orthometric heights that are measured along the plumb line. + * A vertical datum type for orthometric heights that are measured along the plumb line. * - * <p>Identifier: {@code CS_DatumType.CS_VD_Orthometric}</p> + * <h4>Legacy</h4> + * This type was associated to code 2001 in the {@code Vert_Datum} element of the legacy WKT 1 format. + * The UML identifier was {@code CS_DatumType.CS_VD_Orthometric}. */ - public static final VerticalDatumType ORTHOMETRIC = VerticalDatumType.valueOf("ORTHOMETRIC"); + private static final String ORTHOMETRIC = "ORTHOMETRIC"; /** - * Mapping from the numeric values used in legacy specification (OGC 01-009) to {@link VerticalDatumType}. - * Indices in this array are the legacy codes minus 2000. + * A vertical datum type for origin of the vertical axis based on atmospheric pressure. + * + * <h4>Legacy</h4> + * This type was associated to code 2003 in the {@code Vert_Datum} element of the legacy WKT 1 format. + * The UML identifier was {@code CS_DatumType.CS_VD_AltitudeBarometric}. * - * <strong>This array shall not be fill before the above static constants.</strong> + * @see org.apache.sis.referencing.CommonCRS.Vertical#BAROMETRIC */ - private static final VerticalDatumType[] TYPES; + static final String BAROMETRIC = "BAROMETRIC"; - /** - * Do not allow instantiation of this class. - */ - private VerticalDatumTypes() { - } - /** - * Mapping from {@link VerticalDatumType} to the numeric values used in legacy specification (OGC 01-009). + * Returns a pseudo-realization method for ellipsoidal heights. + * <strong>The use of this method is deprecated</strong> as ellipsoidal height + * should never be separated from the horizontal components according ISO 19111. + * + * <h4>Maintenance note</h4> - * If the implementation of this method is modified, search for {@code RealizationMethod.valueOf} ++ * If the implementation of this method is modified, search for {@code VerticalDatumType.valueOf} + * at least in {@link org.apache.sis.referencing.CommonCRS.Vertical#datum()} and make sure that + * the code is equivalent. + * + * @return the ellipsoidal pseudo-realization method. */ - private static final short[] LEGACY_CODES; - static { - TYPES = new VerticalDatumType[7]; - LEGACY_CODES = new short[Math.max(ELLIPSOIDAL.ordinal(), ORTHOMETRIC.ordinal()) + 1]; - for (short code = 2000; code <= 2006; code++) { - final VerticalDatumType type; - switch (code) { - case 2000: type = VerticalDatumType .OTHER_SURFACE; break; // CS_VD_Other - case 2001: type = VerticalDatumTypes.ORTHOMETRIC; break; // CS_VD_Orthometric - case 2002: type = VerticalDatumTypes.ELLIPSOIDAL; break; // CS_VD_Ellipsoidal - case 2003: type = VerticalDatumType .BAROMETRIC; break; // CS_VD_AltitudeBarometric - case 2005: type = VerticalDatumType .GEOIDAL; break; // CS_VD_GeoidModelDerived - case 2006: type = VerticalDatumType .DEPTH; break; // CS_VD_Depth - default: continue; - } - TYPES[code - 2000] = type; - LEGACY_CODES[type.ordinal()] = code; - } - public static RealizationMethod ellipsoidal() { - return RealizationMethod.valueOf(ELLIPSOIDAL); ++ public static VerticalDatumType ellipsoidal() { ++ return VerticalDatumType.valueOf(ELLIPSOIDAL); + } + + /** + * Returns {@code true} if the given value is the ellipsoidal pseudo-realization method. + * + * @param method the method to test, or {@code null}. + * @return whether the given method is the ellipsoidal pseudo-realization method. + */ - public static boolean ellipsoidal(final RealizationMethod method) { ++ public static boolean ellipsoidal(final VerticalDatumType method) { + return (method != null) && ELLIPSOIDAL.equalsIgnoreCase(method.name()); } /** * Returns the vertical datum type from a legacy code. The legacy codes were defined in - * <a href="https://www.ogc.org/standards/ct">OGC 01-009</a> - * (<cite>Coordinate Transformation Services)</cite>, which also defined the version 1 of - * <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well - * Known Text</cite></a> format (WKT 1). This method is used for WKT 1 parsing. + * OGC 01-009 (<cite>Coordinate Transformation Services)</cite>, which also defined the version 1 + * of <cite>Well Known Text</cite></a> format (WKT 1). This method is used for WKT 1 parsing. * * @param code the legacy vertical datum code. - * @return the vertical datum type, or {@code null} if the code is unrecognized. + * @return the vertical datum type, or {@code null} if none. */ - public static VerticalDatumType fromLegacy(int code) { - code -= 2000; - return (code >= 0 && code < TYPES.length) ? TYPES[code] : null; - public static RealizationMethod fromLegacy(final int code) { ++ public static VerticalDatumType fromLegacy(final int code) { + switch (code) { + // case 2000: return null; // CS_VD_Other - case 2001: return RealizationMethod.valueOf(ORTHOMETRIC); // CS_VD_Orthometric ++ case 2001: return VerticalDatumType.valueOf(ORTHOMETRIC); // CS_VD_Orthometric + case 2002: return ellipsoidal(); // CS_VD_Ellipsoidal - case 2003: return RealizationMethod.valueOf(BAROMETRIC); // CS_VD_AltitudeBarometric - case 2005: return RealizationMethod.GEOID; // CS_VD_GeoidModelDerived - case 2006: return RealizationMethod.TIDAL; // CS_VD_Depth ++ case 2003: return VerticalDatumType.BAROMETRIC; // CS_VD_AltitudeBarometric ++ case 2005: return VerticalDatumType.GEOIDAL; // CS_VD_GeoidModelDerived ++ case 2006: return VerticalDatumType.DEPTH; // CS_VD_Depth + default: return null; + } } /** @@@ -110,35 -131,76 +130,38 @@@ * @param type the vertical datum type, or {@code null} if unknown. * @return the legacy code for the given datum type, or 0 if unknown. */ + @SuppressWarnings("deprecation") public static int toLegacy(final VerticalDatumType type) { if (type != null) { - final int ordinal = type.ordinal(); - if (ordinal >= 0 && ordinal < LEGACY_CODES.length) { - return LEGACY_CODES[ordinal]; + switch (type.name().toUpperCase(Locale.US)) { + case ORTHOMETRIC: return 2001; // CS_VD_Orthometric + case ELLIPSOIDAL: return 2002; // CS_VD_Ellipsoidal + case BAROMETRIC: return 2003; // CS_VD_AltitudeBarometric + case "GEOIDAL": return 2005; // CS_VD_GeoidModelDerived + case "DEPTH": return 2006; // CS_VD_Depth } } - return 0; + return 2000; } - /** - * Returns the vertical datum type from a realization method. - * If the given method cannot be mapped to a legacy type, then this method returns "other surface". - * This is because the vertical datum type was a mandatory property in legacy OGC/ISO standards. - * This method is used for writing GML documents older than GML 3.2. - * - * @param method the realization method, or {@code null}. - * @return the vertical datum type (never null). - */ - @SuppressWarnings("deprecation") - public static VerticalDatumType fromMethod(final RealizationMethod method) { - if (method == RealizationMethod.GEOID) return VerticalDatumType.GEOIDAL; - if (method == RealizationMethod.TIDAL) return VerticalDatumType.DEPTH; - if (method != null) { - return VerticalDatumType.valueOf(method.name().toUpperCase(Locale.US)); - } - return VerticalDatumType.OTHER_SURFACE; - } - - /** - * Returns the realization method from a vertical datum type. - * This method is used for reading GML documents older than GML 3.2. - * - * @param type the vertical datum type, or {@code null}. - * @return the realization method, or {@code null} if none. - */ - @SuppressWarnings("deprecation") - public static RealizationMethod toMethod(final VerticalDatumType type) { - if (type != null) { - if (type == VerticalDatumType.GEOIDAL) return RealizationMethod.GEOID; - if (type == VerticalDatumType.DEPTH) return RealizationMethod.TIDAL; - if (type == VerticalDatumType.BAROMETRIC) return RealizationMethod.valueOf(BAROMETRIC); - if (ORTHOMETRIC.equalsIgnoreCase(type.name())) return RealizationMethod.valueOf(ORTHOMETRIC); - if (ELLIPSOIDAL.equalsIgnoreCase(type.name())) return ellipsoidal(); - } - return null; - } - /** - * Guesses the type of a datum from its name, aliases or a given vertical axis. This is sometimes needed - * after XML unmarshalling or WKT parsing, since GML 3.2 and ISO 19162 do not contain any attribute for - * the datum type. + * Guesses the realization method of a datum from its name, aliases or a given vertical axis. + * This is sometimes needed after XML unmarshalling or WKT parsing, because GML 3.2 and ISO 19162 + * do not contain any attribute for the datum type. * - * <p>This method uses heuristic rules and may be changed in any future SIS version. - * If the type cannot be determined, defaults to {@link VerticalDatumType#OTHER_SURFACE}.</p> + * <p>This method uses heuristic rules and may be changed in any future SIS version.</p> * * @param name the name of the datum for which to guess a type, or {@code null} if unknown. * @param aliases the aliases of the datum for which to guess a type, or {@code null} if unknown. * @param axis the vertical axis for which to guess a type, or {@code null} if unknown. - * @return a datum type, or {@code null} if none can be guessed. + * @return a datum type, or {@link VerticalDatumType#OTHER_SURFACE} if none can be guessed. */ - public static RealizationMethod guess(final String name, final Collection<? extends GenericName> aliases, + public static VerticalDatumType guess(final String name, final Collection<? extends GenericName> aliases, final CoordinateSystemAxis axis) { - VerticalDatumType type = guess(name); - if (type != null) { - return type; - RealizationMethod method = guess(name); ++ VerticalDatumType method = guess(name); + if (method != null) { + return method; } if (aliases != null) { for (final GenericName alias : aliases) { @@@ -155,13 -217,13 +178,13 @@@ if (abbreviation.length() == 1) { AxisDirection dir = AxisDirection.UP; // Expected direction for accepting the type. switch (abbreviation.charAt(0)) { - case 'h': type = ELLIPSOIDAL; break; - case 'H': type = VerticalDatumType.GEOIDAL; break; - case 'D': type = VerticalDatumType.DEPTH; dir = AxisDirection.DOWN; break; + case 'h': method = ellipsoidal(); break; - case 'H': method = RealizationMethod.GEOID; break; - case 'D': method = RealizationMethod.TIDAL; dir = AxisDirection.DOWN; break; - default: return null; ++ case 'H': method = VerticalDatumType.GEOIDAL; break; ++ case 'D': method = VerticalDatumType.DEPTH; dir = AxisDirection.DOWN; break; + default: return VerticalDatumType.OTHER_SURFACE; } if (dir.equals(axis.getDirection())) { - return type; + return method; } } } else if (Units.isPressure(unit)) { @@@ -172,23 -234,19 +195,23 @@@ } /** - * Guesses the type of a datum of the given name. This method attempts to guess only if the given name - * contains at least one letter. If the type cannot be determined, returns {@code null}. + * Guesses the realization method of a datum of the given name. This method attempts to guess only if + * the given name contains at least one letter. If the type cannot be determined, returns {@code null}. * - * @param name name of the datum for which to guess a type, or {@code null}. - * @return a datum type, or {@code null} if none can be guessed. + * @param name name of the datum for which to guess a realization method, or {@code null}. + * @return a realization method, or {@code null} if none can be guessed. */ - private static RealizationMethod guess(final String name) { + private static VerticalDatumType guess(final String name) { if (name != null) { if (CharSequences.equalsFiltered("Mean Sea Level", name, Characters.Filter.LETTERS_AND_DIGITS, true)) { - return RealizationMethod.TIDAL; + return VerticalDatumType.GEOIDAL; } - if (name.contains("geoid")) { - return RealizationMethod.GEOID; + for (int i=0; i<name.length();) { + final int c = name.codePointAt(i); + if (Character.isLetter(c)) { + return CodeLists.find(VerticalDatumType.class, new VerticalDatumTypes(name)); + } + i += Character.charCount(c); } } return null; diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/AxisDirections.java index 96a6d5e2ad,4671df63a3..3826d39454 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/AxisDirections.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/AxisDirections.java @@@ -35,11 -35,6 +35,11 @@@ import org.apache.sis.util.iso.Types import org.apache.sis.measure.Units; import static org.apache.sis.util.CharSequences.*; +// Specific to the main branch: +import org.opengis.annotation.UML; +import static org.opengis.annotation.Obligation.CONDITIONAL; - import static org.opengis.annotation.Specification.UNSPECIFIED; ++import static org.opengis.annotation.Specification.ISO_19111; + /** * Utilities methods related to {@link AxisDirection}. @@@ -71,53 -66,8 +71,59 @@@ public final class AxisDirections exten * * @see #isUserDefined(AxisDirection) */ - private static final int LAST_ORDINAL = UNSPECIFIED.ordinal(); + private static final int LAST_ORDINAL = DISPLAY_DOWN.ordinal(); + + /** + * Forward direction. + * For an observer at the centre of the object this is will be towards its front, bow or nose. + * Added in ISO 19111:2019 (was not in ISO 19111:2007). + */ - @UML(identifier="forward", obligation=CONDITIONAL, specification=UNSPECIFIED) ++ @UML(identifier="forward", obligation=CONDITIONAL, specification=ISO_19111) + public static final AxisDirection FORWARD = AxisDirection.valueOf("FORWARD"); + + /** + * Starboard direction. + * For an observer at the centre of the object this will be towards its right. + * Added in ISO 19111:2019 (was not in ISO 19111:2007). + */ - @UML(identifier="starboard", obligation=CONDITIONAL, specification=UNSPECIFIED) ++ @UML(identifier="starboard", obligation=CONDITIONAL, specification=ISO_19111) + public static final AxisDirection STARBOARD = AxisDirection.valueOf("STARBOARD"); + + /** + * Port direction. + * For an observer at the centre of the object this will be towards its left. + * Added in ISO 19111:2019 (was not in ISO 19111:2007). + */ - @UML(identifier="port", obligation=CONDITIONAL, specification=UNSPECIFIED) ++ @UML(identifier="port", obligation=CONDITIONAL, specification=ISO_19111) + public static final AxisDirection PORT = AxisDirection.valueOf("PORT"); + + /** + * Direction of geographic angles (bearing). + * Added in ISO 19111:2019 (was not in ISO 19111:2007). + */ - @UML(identifier="clockwise", obligation=CONDITIONAL, specification=UNSPECIFIED) ++ @UML(identifier="clockwise", obligation=CONDITIONAL, specification=ISO_19111) + public static final AxisDirection CLOCKWISE = AxisDirection.valueOf("CLOCKWISE"); + + /** + * Direction of arithmetic angles. Used in polar coordinate systems. + * Added in ISO 19111:2019 (was not in ISO 19111:2007). + */ - @UML(identifier="counterClockwise", obligation=CONDITIONAL, specification=UNSPECIFIED) ++ @UML(identifier="counterClockwise", obligation=CONDITIONAL, specification=ISO_19111) + public static final AxisDirection COUNTER_CLOCKWISE = AxisDirection.valueOf("COUNTER_CLOCKWISE"); + + /** + * Distance from the origin in a polar coordinate system. + * Added in ISO 19111:2019 (was not in ISO 19111:2007). + */ - @UML(identifier="awayFrom", obligation=CONDITIONAL, specification=UNSPECIFIED) ++ @UML(identifier="awayFrom", obligation=CONDITIONAL, specification=ISO_19111) + public static final AxisDirection AWAY_FROM = AxisDirection.valueOf("AWAY_FROM"); + ++ /** ++ * Axis positive direction is unspecified. ++ */ ++ @UML(identifier="unspecified", obligation=CONDITIONAL, specification=ISO_19111) ++ public static final AxisDirection UNSPECIFIED = AxisDirection.valueOf("UNSPECIFIED"); + /** * For each direction, the opposite direction. * This map shall be immutable after construction. diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ReferencingUtilities.java index a1a8eb1a5c,65b6d458f0..9fc219d785 --- 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 @@@ -272,10 -220,7 +272,7 @@@ public final class ReferencingUtilitie */ public static boolean isEllipsoidalHeight(final VerticalDatum datum) { if (datum != null) { - final VerticalDatumType type = datum.getVerticalDatumType(); - if (type != null) { - return "ELLIPSOIDAL".equalsIgnoreCase(type.name()); - } - return datum.getRealizationMethod().map(VerticalDatumTypes::ellipsoidal).orElse(false); ++ return VerticalDatumTypes.ellipsoidal(datum.getVerticalDatumType()); } return false; } diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/io/wkt/TransliteratorTest.java index 31c0786c52,3ba62d844f..0e4ad77061 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/io/wkt/TransliteratorTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/io/wkt/TransliteratorTest.java @@@ -21,6 -21,6 +21,7 @@@ import org.opengis.referencing.cs.Spher import org.opengis.referencing.cs.EllipsoidalCS; import org.opengis.referencing.cs.CoordinateSystem; import org.apache.sis.metadata.privy.AxisNames; ++import org.apache.sis.referencing.privy.AxisDirections; // Test dependencies import org.junit.jupiter.api.Test; @@@ -98,12 -98,12 +99,12 @@@ public final class TransliteratorTest e @Test public void testToUnicodeAbbreviation() { final Transliterator t = Transliterator.DEFAULT; - assertEquals("φ", t.toUnicodeAbbreviation("ellipsoidal", AxisDirection.NORTH, "P"), "P"); - assertEquals("φ", t.toUnicodeAbbreviation("ellipsoidal", AxisDirection.NORTH, "B"), "B"); - assertEquals("λ", t.toUnicodeAbbreviation("ellipsoidal", AxisDirection.EAST, "L"), "L"); - assertEquals("θ", t.toUnicodeAbbreviation("polar", AxisDirection.OTHER, "U"), "U"); - assertEquals("Ω", t.toUnicodeAbbreviation("spherical", AxisDirection.NORTH, "U"), "U"); - assertEquals("θ", t.toUnicodeAbbreviation("spherical", AxisDirection.EAST, "V"), "V"); + assertEquals("φ", t.toUnicodeAbbreviation("ellipsoidal", AxisDirection.NORTH, "P"), "P"); + assertEquals("φ", t.toUnicodeAbbreviation("ellipsoidal", AxisDirection.NORTH, "B"), "B"); + assertEquals("λ", t.toUnicodeAbbreviation("ellipsoidal", AxisDirection.EAST, "L"), "L"); - assertEquals("θ", t.toUnicodeAbbreviation("polar", AxisDirection.CLOCKWISE, "U"), "U"); ++ assertEquals("θ", t.toUnicodeAbbreviation("polar", AxisDirections.CLOCKWISE,"U"), "U"); + assertEquals("Ω", t.toUnicodeAbbreviation("spherical", AxisDirection.NORTH, "U"), "U"); + assertEquals("θ", t.toUnicodeAbbreviation("spherical", AxisDirection.EAST, "V"), "V"); } /** diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/CommonCRSTest.java index b2560e43fb,c109be58ca..80f6689c5d --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/CommonCRSTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/CommonCRSTest.java @@@ -214,34 -214,37 +214,34 @@@ public final class CommonCRSTest extend * Verifies the vertical datum enumeration. */ @Test - @SuppressWarnings("deprecation") public void testVertical() { for (final CommonCRS.Vertical e : CommonCRS.Vertical.values()) { - final VerticalDatumType datumType; - final RealizationMethod method; ++ final VerticalDatumType method; final String axisName, datumName; switch (e) { - case NAVD88: axisName = AxisNames.GRAVITY_RELATED_HEIGHT; datumName = "North American Vertical Datum 1988"; datumType = VerticalDatumType. GEOIDAL; break; - case BAROMETRIC: axisName = "Barometric altitude"; datumName = "Constant pressure surface"; datumType = VerticalDatumType. BAROMETRIC; break; - case MEAN_SEA_LEVEL: axisName = AxisNames.GRAVITY_RELATED_HEIGHT; datumName = "Mean Sea Level"; datumType = VerticalDatumType. GEOIDAL; break; - case DEPTH: axisName = AxisNames.DEPTH; datumName = "Mean Sea Level"; datumType = VerticalDatumType. GEOIDAL; break; - case ELLIPSOIDAL: axisName = AxisNames.ELLIPSOIDAL_HEIGHT; datumName = "Ellipsoid"; datumType = VerticalDatumTypes.ELLIPSOIDAL; break; - case OTHER_SURFACE: axisName = "Height"; datumName = "Other surface"; datumType = VerticalDatumType. OTHER_SURFACE; break; - case NAVD88: axisName = AxisNames.GRAVITY_RELATED_HEIGHT; datumName = "North American Vertical Datum 1988"; method = RealizationMethod. GEOID; break; - case BAROMETRIC: axisName = "Barometric altitude"; datumName = "Constant pressure surface"; method = RealizationMethod.valueOf("BAROMETRIC"); break; - case MEAN_SEA_LEVEL: axisName = AxisNames.GRAVITY_RELATED_HEIGHT; datumName = "Mean Sea Level"; method = RealizationMethod. TIDAL; break; - case DEPTH: axisName = AxisNames.DEPTH; datumName = "Mean Sea Level"; method = RealizationMethod. TIDAL; break; ++ case NAVD88: axisName = AxisNames.GRAVITY_RELATED_HEIGHT; datumName = "North American Vertical Datum 1988"; method = VerticalDatumType. GEOIDAL; break; ++ case BAROMETRIC: axisName = "Barometric altitude"; datumName = "Constant pressure surface"; method = VerticalDatumType. BAROMETRIC; break; ++ case MEAN_SEA_LEVEL: axisName = AxisNames.GRAVITY_RELATED_HEIGHT; datumName = "Mean Sea Level"; method = VerticalDatumType. GEOIDAL; break; ++ case DEPTH: axisName = AxisNames.DEPTH; datumName = "Mean Sea Level"; method = VerticalDatumType. GEOIDAL; break; + case ELLIPSOIDAL: axisName = AxisNames.ELLIPSOIDAL_HEIGHT; datumName = "Ellipsoid"; method = VerticalDatumTypes.ellipsoidal(); break; - case OTHER_SURFACE: axisName = "Height"; datumName = "Other surface"; method = null; break; ++ case OTHER_SURFACE: axisName = "Height"; datumName = "Other surface"; method = VerticalDatumType. OTHER_SURFACE; break; default: throw new AssertionError(e); } final String name = e.name(); final VerticalDatum datum = e.datum(); final VerticalCRS crs = e.crs(); - if (e.isEPSG) { + if (e.isEPSG && !name.startsWith("NAV")) { /* - * BAROMETRIC, ELLIPSOIDAL and OTHER_SURFACE uses an axis named "Height", which is not - * a valid axis name according ISO 19111. We skip the validation test for those enums. + * BAROMETRIC and ELLIPSOIDAL uses an axis named "Height", which is not a valid + * axis name according ISO 19111. We skip the validation test for those enums. */ Validators.validate(crs); } assertSame(datum, e.datum(), name); // Datum before CRS creation. assertSame(crs.getDatum(), e.datum(), name); // Datum after CRS creation. assertEquals(datumName, datum.getName().getCode(), name); - assertEquals(datumType, datum.getVerticalDatumType(), name); ++ assertEquals(method, datum.getVerticalDatumType(), name); assertEquals(axisName, crs.getCoordinateSystem().getAxis(0).getName().getCode(), name); - if (!e.isEPSG) { // Because the information is not in EPSG database 9.x. - assertEquals(method, datum.getRealizationMethod().orElse(null), name); - } } } diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/cs/HardCodedAxes.java index 48ac69bb32,b7b43a955b..bffb391065 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/cs/HardCodedAxes.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/cs/HardCodedAxes.java @@@ -471,8 -468,8 +471,8 @@@ public final class HardCodedAxes * and the unit is dimensionless. This constant is sometimes used as a placeholder * for axes that were not properly defined. */ - public static final DefaultCoordinateSystemAxis UNDEFINED = create("Undefined", "z", - AxisDirection.OTHER, Units.UNITY, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, null); + public static final DefaultCoordinateSystemAxis UNDEFINED = create("Undefined", "m", - AxisDirection.UNSPECIFIED, Units.UNITY, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, null); ++ AxisDirections.UNSPECIFIED, Units.UNITY, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, null); /** * Creates a new axis of the given name, abbreviation, direction and unit. diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/datum/DefaultVerticalDatumTest.java index 81fb6a38bd,9de1a8749b..fe792940f1 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/datum/DefaultVerticalDatumTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/datum/DefaultVerticalDatumTest.java @@@ -65,34 -65,6 +65,34 @@@ public final class DefaultVerticalDatum : "VerticalDatum.xml"); } + /** + * Tests the {@link DefaultVerticalDatum#getVerticalDatumType()} method in a state + * simulating unmarshalling of GML 3.2 document. + * + * @throws NoSuchFieldException Should never happen. + * @throws IllegalAccessException Should never happen. + */ + @Test + public void testAfterUnmarshal() throws NoSuchFieldException, IllegalAccessException { + final Field typeField = DefaultVerticalDatum.class.getDeclaredField("type"); + typeField.setAccessible(true); + assertEquals(VerticalDatumType .GEOIDAL, typeForName(typeField, "Geoidal height")); + assertEquals(VerticalDatumType .DEPTH, typeForName(typeField, "Some depth measurement")); - assertEquals(VerticalDatumTypes.ELLIPSOIDAL, typeForName(typeField, "Ellipsoidal height")); ++ assertEquals(VerticalDatumTypes.ellipsoidal(), typeForName(typeField, "Ellipsoidal height")); + assertEquals(VerticalDatumType .OTHER_SURFACE, typeForName(typeField, "NotADepth")); + } + + /** + * Returns the vertical datum type inferred by {@link DefaultVerticalDatum} for the given name. + */ + private static VerticalDatumType typeForName(final Field typeField, final String name) throws IllegalAccessException { + final var datum = new DefaultVerticalDatum( + Map.of(DefaultVerticalDatum.NAME_KEY, name), + VerticalDatumType.OTHER_SURFACE); + typeField.set(datum, null); + return datum.getVerticalDatumType(); + } + /** * Tests {@link DefaultVerticalDatum#toWKT()}. */ diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/internal/VerticalDatumTypesTest.java index 950f9f7f82,2b846e8736..7a19958814 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/internal/VerticalDatumTypesTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/internal/VerticalDatumTypesTest.java @@@ -16,7 -16,9 +16,8 @@@ */ package org.apache.sis.referencing.internal; -import org.opengis.referencing.datum.RealizationMethod; import org.opengis.referencing.datum.VerticalDatumType; + import org.apache.sis.referencing.CommonCRS; import org.apache.sis.util.ArraysExt; // Test dependencies @@@ -37,14 -40,25 +38,25 @@@ public final class VerticalDatumTypesTe public VerticalDatumTypesTest() { } + /** + * Verifies name constraint with values defined in {@link org.apache.sis.referencing.CommonCRS.Vertical}. + * Some enumeration values must have the same names as the constants defined in {@link VerticalDatumTypes}, - * because the realization method is obtained by a call to {@link RealizationMethod#valueOf(String)}. ++ * because the realization method is obtained by a call to {@link VerticalDatumType#valueOf(String)}. + */ + @Test + public void verifyNameConstraint() { + assertEquals(VerticalDatumTypes.ELLIPSOIDAL, CommonCRS.Vertical.ELLIPSOIDAL.name()); + assertEquals(VerticalDatumTypes.BAROMETRIC, CommonCRS.Vertical.BAROMETRIC.name()); + } + /** * Tests the {@link VerticalDatumTypes#fromLegacy(int)} method. */ @Test public void testFromLegacy() { - assertEquals(VerticalDatumTypes.ELLIPSOIDAL, VerticalDatumTypes.fromLegacy(2002)); - assertEquals(VerticalDatumType .GEOIDAL, VerticalDatumTypes.fromLegacy(2005)); - assertEquals(VerticalDatumType .DEPTH, VerticalDatumTypes.fromLegacy(2006)); + assertEquals(VerticalDatumTypes.ellipsoidal(), VerticalDatumTypes.fromLegacy(2002)); - assertEquals(RealizationMethod .GEOID, VerticalDatumTypes.fromLegacy(2005)); - assertEquals(RealizationMethod .TIDAL, VerticalDatumTypes.fromLegacy(2006)); ++ assertEquals(VerticalDatumType .GEOIDAL, VerticalDatumTypes.fromLegacy(2005)); ++ assertEquals(VerticalDatumType .DEPTH, VerticalDatumTypes.fromLegacy(2006)); } /** @@@ -58,13 -72,13 +70,13 @@@ } /** - * Tests the list of vertical datum types. Note that {@link #testFromLegacy()} must be executed - * first for ensuring {@link VerticalDatumTypes} class initialization prior this test. + * Verifies the list of realization methods. */ @Test - public void testVerticalDatumTypes() { + public void verifyCodeList() { - final RealizationMethod expected = VerticalDatumTypes.ellipsoidal(); // Must be first. - final RealizationMethod[] types = RealizationMethod.values(); - assertEquals(RealizationMethod.LEVELLING, types[0]); ++ final VerticalDatumType expected = VerticalDatumTypes.ellipsoidal(); // Must be first. + final VerticalDatumType[] types = VerticalDatumType.values(); + assertEquals(VerticalDatumType.OTHER_SURFACE, types[0]); - assertTrue(ArraysExt.contains(types, VerticalDatumTypes.ELLIPSOIDAL)); + assertTrue(ArraysExt.contains(types, expected)); } } diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/privy/AxisDirectionsTest.java index 528027e9ca,b926d08d7c..f50eb7f5f9 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/privy/AxisDirectionsTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/privy/AxisDirectionsTest.java @@@ -32,11 -32,6 +32,12 @@@ import org.apache.sis.referencing.cs.Ha import org.apache.sis.referencing.cs.HardCodedCS; import org.apache.sis.test.TestCase; +// Specific to the main branch: +import static org.apache.sis.referencing.privy.AxisDirections.AWAY_FROM; +import static org.apache.sis.referencing.privy.AxisDirections.CLOCKWISE; +import static org.apache.sis.referencing.privy.AxisDirections.COUNTER_CLOCKWISE; ++import static org.apache.sis.referencing.privy.AxisDirections.UNSPECIFIED; + /** * Tests the {@link AxisDirections} class. diff --cc endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/base/Axis.java index 5784bbf8e5,8bff2968de..9ca1fbd600 --- a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/base/Axis.java +++ b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/base/Axis.java @@@ -630,7 -630,7 +630,7 @@@ public final class Axis extends NamedEl } else switch (order) { case 0: dir = AxisDirection.COLUMN_POSITIVE; break; case 1: dir = AxisDirection.ROW_POSITIVE; break; - default: dir = AxisDirection.OTHER; break; - default: dir = AxisDirection.UNSPECIFIED; break; ++ default: dir = AxisDirections.UNSPECIFIED; break; } } final String abbr;