This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 8fc9815c594c47d497d5fabd5faaf320a45a49f1 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Thu May 25 15:49:09 2023 +0200 Add support for two-dimensional `SphericalCS` as submitted in ISO 19111 amendment 2. --- .../apache/sis/io/wkt/GeodeticObjectParser.java | 14 +++++---- .../sis/referencing/cs/CoordinateSystems.java | 4 +-- .../sis/referencing/cs/DefaultSphericalCS.java | 32 ++++++++++++++++++-- .../referencing/factory/GeodeticObjectFactory.java | 35 ++++++++++++++++++++++ .../referencing/factory/sql/EPSGDataAccess.java | 1 + .../org/apache/sis/storage/geotiff/CRSBuilder.java | 4 +-- .../org/apache/sis/internal/netcdf/CRSBuilder.java | 10 +++++-- 7 files changed, 86 insertions(+), 14 deletions(-) diff --git a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java index 5bae69b55b..701a429280 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java @@ -99,7 +99,7 @@ import static java.util.Collections.singletonMap; * @author Rémi Eve (IRD) * @author Martin Desruisseaux (IRD, Geomatys) * @author Johann Sorel (Geomatys) - * @version 1.3 + * @version 1.4 * @since 0.6 */ class GeodeticObjectParser extends MathTransformParser implements Comparator<CoordinateSystemAxis> { @@ -927,6 +927,14 @@ class GeodeticObjectParser extends MathTransformParser implements Comparator<Coo dimension = (axes.length < 2) ? 2 : 3; // For error message. break; } + case WKTKeywords.spherical: { + switch (axes.length) { + case 2: return csFactory.createSphericalCS(csProperties, axes[0], axes[1]); + case 3: return csFactory.createSphericalCS(csProperties, axes[0], axes[1], axes[2]); + } + dimension = (axes.length < 2) ? 2 : 3; // For error message. + break; + } case WKTKeywords.Cartesian: { switch (axes.length) { case 2: return csFactory.createCartesianCS(csProperties, axes[0], axes[1]); @@ -963,10 +971,6 @@ class GeodeticObjectParser extends MathTransformParser implements Comparator<Coo if (axes.length != (dimension = 3)) break; return csFactory.createCylindricalCS(csProperties, axes[0], axes[1], axes[2]); } - case WKTKeywords.spherical: { - if (axes.length != (dimension = 3)) break; - return csFactory.createSphericalCS(csProperties, axes[0], axes[1], axes[2]); - } case WKTKeywords.parametric: { if (axes.length != (dimension = 1)) break; return csFactory.createParametricCS(csProperties, axes[0]); diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java index 722da90e42..09debdf369 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java @@ -520,7 +520,7 @@ next: for (final CoordinateSystem cs : targets) { */ public static CoordinateSystem replaceLinearUnit(final CoordinateSystem cs, final Unit<Length> newUnit) { ArgumentChecks.ensureNonNull("newUnit", newUnit); - return CoordinateSystems.replaceAxes(cs, new AxisFilter() { + return replaceAxes(cs, new AxisFilter() { @Override public Unit<?> getUnitReplacement(CoordinateSystemAxis axis, Unit<?> unit) { return Units.isLinear(unit) ? newUnit : unit; } @@ -551,7 +551,7 @@ next: for (final CoordinateSystem cs : targets) { */ public static CoordinateSystem replaceAngularUnit(final CoordinateSystem cs, final Unit<javax.measure.quantity.Angle> newUnit) { ArgumentChecks.ensureNonNull("newUnit", newUnit); - return CoordinateSystems.replaceAxes(cs, new AxisFilter() { + return replaceAxes(cs, new AxisFilter() { @Override public Unit<?> getUnitReplacement(CoordinateSystemAxis axis, Unit<?> unit) { return Units.isAngular(unit) ? newUnit : unit; } diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultSphericalCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultSphericalCS.java index d9a14ba01d..f82fc34bce 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultSphericalCS.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultSphericalCS.java @@ -28,7 +28,8 @@ import org.apache.sis.measure.Units; /** - * A 3-dimensional coordinate system with one distance measured from the origin and two angular coordinates. + * A 2- or 3-dimensional coordinate system with one distance measured from the origin and two angular coordinates. + * In the two-dimensional case, the radius is omitted and may be implicitly an ellipsoid surface. * Not to be confused with an {@linkplain DefaultEllipsoidalCS ellipsoidal coordinate system} * based on an ellipsoid "degenerated" into a sphere. * @@ -125,6 +126,27 @@ public class DefaultSphericalCS extends AbstractCS implements SphericalCS { super(properties, axis0, axis1, axis2); } + /** + * Constructs a two-dimensional coordinate system from a set of properties. + * The given axes shall be angular measurements, without radius. + * The properties map is given unchanged to the + * {@linkplain AbstractCS#AbstractCS(Map,CoordinateSystemAxis[]) super-class constructor}. + * + * @param properties the properties to be given to the identified object. + * @param axis0 the first axis (e.g. “Spherical latitude”). + * @param axis1 the second axis (e.g. “Spherical longitude”). + * + * @see org.apache.sis.referencing.factory.GeodeticObjectFactory#createSphericalCS(Map, CoordinateSystemAxis, CoordinateSystemAxis) + * + * @since 1.4 + */ + public DefaultSphericalCS(final Map<String,?> properties, + final CoordinateSystemAxis axis0, + final CoordinateSystemAxis axis1) + { + super(properties, axis0, axis1); + } + /** * Creates a new coordinate system with the same values than the specified one. * This copy constructor provides a way to convert an arbitrary implementation into a SIS one @@ -202,9 +224,15 @@ public class DefaultSphericalCS extends AbstractCS implements SphericalCS { * Returns a coordinate system with different axes. */ @Override + @SuppressWarnings("fallthrough") final AbstractCS createForAxes(final Map<String,?> properties, final CoordinateSystemAxis[] axes) { switch (axes.length) { - case 2: return new DefaultPolarCS(properties, axes); + case 2: { + if (Units.isLinear(axes[0].getUnit()) || Units.isLinear(axes[1].getUnit())) { + return new DefaultPolarCS(properties, axes); + } + // Fall through + } case 3: return new DefaultSphericalCS(properties, axes); default: throw unexpectedDimension(properties, axes, 2); } diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java index 5d721fdbc5..f53cf7812e 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java @@ -479,6 +479,41 @@ public class GeodeticObjectFactory extends AbstractFactory implements CRSFactory return unique("createSphericalCS", cs); } + /** + * Creates a spherical coordinate system without radius. + * This coordinate system can be used with geocentric, engineering and derived CRS. + * + * <h4>Dependencies</h4> + * The components needed by this method can be created by the following methods: + * <ol> + * <li>{@link #createCoordinateSystemAxis(Map, String, AxisDirection, Unit)}</li> + * </ol> + * + * The default implementation creates a {@link DefaultSphericalCS} instance. + * + * @param properties name and other properties to give to the new object. + * @param axis0 the first axis (e.g. “Spherical latitude”). + * @param axis1 the second axis (e.g. “Spherical longitude”). + * @throws FactoryException if the object creation failed. + * + * @see DefaultSphericalCS#DefaultSphericalCS(Map, CoordinateSystemAxis, CoordinateSystemAxis) + * + * @since 1.4 + */ + @Override + public SphericalCS createSphericalCS(final Map<String,?> properties, + final CoordinateSystemAxis axis0, + final CoordinateSystemAxis axis1) throws FactoryException + { + final DefaultSphericalCS cs; + try { + cs = new DefaultSphericalCS(complete(properties), axis0, axis1); + } catch (IllegalArgumentException exception) { + throw new InvalidGeodeticParameterException(exception); + } + return unique("createSphericalCS", cs); + } + /** * Creates a geographic coordinate reference system. It can be (<var>latitude</var>, <var>longitude</var>) * or (<var>longitude</var>, <var>latitude</var>), optionally with an ellipsoidal height. diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java index 79894aaf20..5f0eb61e0e 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java @@ -2197,6 +2197,7 @@ codes: for (int i=0; i<codes.length; i++) { } case WKTKeywords.spherical: { switch (dimension) { + case 2: cs = csFactory.createSphericalCS(properties, axes[0], axes[1]); break; case 3: cs = csFactory.createSphericalCS(properties, axes[0], axes[1], axes[2]); break; } break; diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java index 2a700e0c6d..f19ab41b14 100644 --- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java +++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java @@ -1067,7 +1067,7 @@ final class CRSBuilder extends ReferencingFactoryContainer { private void verify(final GeographicCRS crs, final Unit<Angle> angularUnit) throws FactoryException { /* * Note: current createUnit(…) implementation does not allow us to distinguish whether METRE ou DEGREE units - * were specified in the GeoTIFF file or if we got the default values. We do not compare units of that reason. + * were specified in the GeoTIFF file or if we got the default values. We do not compare units for that reason. */ final Unit<Length> linearUnit = createUnit(GeoKeys.GeogLinearUnits, GeoKeys.GeogLinearUnitSize, Length.class, Units.METRE); final GeodeticDatum datum = crs.getDatum(); @@ -1134,7 +1134,7 @@ final class CRSBuilder extends ReferencingFactoryContainer { private void verify(final GeocentricCRS crs) throws FactoryException { /* * Note: current createUnit(…) implementation does not allow us to distinguish whether METRE ou DEGREE units - * were specified in the GeoTIFF file or if we got the default values. We do not compare units of that reason. + * were specified in the GeoTIFF file or if we got the default values. We do not compare units for that reason. */ final Unit<Length> linearUnit = createUnit(GeoKeys.GeogLinearUnits, GeoKeys.GeogLinearUnitSize, Length.class, Units.METRE); final Unit<Angle> angularUnit = createUnit(GeoKeys.AngularUnits, GeoKeys.AngularUnitSize, Angle.class, Units.DEGREE); diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java index d62c4b041b..97d0ca7164 100644 --- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java +++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java @@ -84,7 +84,7 @@ import org.apache.sis.measure.Units; * while {@link DataStoreException} is handled as a fatal error. Warnings are stored in {@link #warnings} field. * * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.4 * @since 1.0 */ abstract class CRSBuilder<D extends Datum, CS extends CoordinateSystem> { @@ -677,12 +677,16 @@ previous: for (int i=components.size(); --i >= 0;) { } /** - * Creates the three-dimensional {@link SphericalCS} from given axes. This method is invoked only + * Creates the two- or three-dimensional {@link SphericalCS} from given axes. This method is invoked only * if {@link #setPredefinedComponents(Decoder)} failed to assign a CS or if {@link #build(Decoder, boolean)} * found that the {@link #coordinateSystem} does not have compatible axes. */ @Override void createCS(CSFactory factory, Map<String,?> properties, CoordinateSystemAxis[] axes) throws FactoryException { - coordinateSystem = factory.createSphericalCS(properties, axes[0], axes[1], axes[2]); + if (axes.length > 2) { + coordinateSystem = factory.createSphericalCS(properties, axes[0], axes[1], axes[2]); + } else { + coordinateSystem = factory.createSphericalCS(properties, axes[0], axes[1]); + } } /**