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 02d0e99b52ba03cad63fe867e74a65fe9c7d35eb Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Fri Jul 29 15:38:45 2022 +0200 Add a "Pseudo sinusoidal" projection similar to Pseudo Mercator: use spherical formulas but apply the result on WGS84 ellipsoid. https://issues.apache.org/jira/browse/SIS-553 --- .../referencing/provider/PseudoSinusoidal.java | 59 ++++++++++++++++++++ .../internal/referencing/provider/Sinusoidal.java | 22 +++++--- .../referencing/operation/projection/Mercator.java | 2 +- .../operation/projection/Sinusoidal.java | 64 ++++++++++++++++++++-- .../operation/projection/package-info.java | 2 +- ...g.opengis.referencing.operation.OperationMethod | 1 + .../referencing/provider/ProvidersTest.java | 3 +- .../apache/sis/internal/earth/netcdf/GCOM_C.java | 11 +--- 8 files changed, 139 insertions(+), 25 deletions(-) diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PseudoSinusoidal.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PseudoSinusoidal.java new file mode 100644 index 0000000000..bcf34efe4b --- /dev/null +++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PseudoSinusoidal.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.internal.referencing.provider; + +import javax.xml.bind.annotation.XmlTransient; +import org.opengis.parameter.ParameterDescriptorGroup; + + +/** + * The provider for <cite>"Pseudo sinusoidal equal-area"</cite> projection. + * This is similar to Pseudo-Mercator: uses spherical formulas but apply the result on an ellipsoid. + * This is sometime used with remote sensing data. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.3 + * @since 1.3 + * @module + */ +@XmlTransient +public final class PseudoSinusoidal extends Sinusoidal { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = 6523477856049963388L; + + /** + * Name of this projection. + */ + public static final String NAME = "Pseudo sinusoidal"; + + /** + * The group of all parameters expected by this coordinate operation. + */ + private static ParameterDescriptorGroup parameters() { + return builder().addName(NAME) + .createGroupForMapProjection(AbstractMercator.toArray(PARAMETERS.descriptors(), 0)); + } + + /** + * Constructs a new provider. + */ + public PseudoSinusoidal() { + super(parameters()); + } +} diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Sinusoidal.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Sinusoidal.java index 3c3dfff3fd..81a249ae55 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Sinusoidal.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Sinusoidal.java @@ -32,7 +32,7 @@ import org.apache.sis.referencing.operation.projection.NormalizedProjection; * This projection method has no associated EPSG code. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 1.3 * * @see <a href="https://en.wikipedia.org/wiki/Sinusoidal_projection">Sinusoidal projection on Wikipedia</a> * @see <a href="http://geotiff.maptools.org/proj_list/sinusoidal.html">GeoTIFF parameters for Sinusoidal</a> @@ -41,17 +41,12 @@ import org.apache.sis.referencing.operation.projection.NormalizedProjection; * @module */ @XmlTransient -public final class Sinusoidal extends MapProjection { +public class Sinusoidal extends MapProjection { /** * For cross-version compatibility. */ private static final long serialVersionUID = -3236247448683326299L; - /** - * Name of this projection. - */ - public static final String NAME = "Sinusoidal"; - /** * The operation parameter descriptor for the <cite>Longitude of projection center</cite> (λ₀) parameter value. * Valid values range is [-180 … 180]° and default value is 0°. @@ -97,10 +92,10 @@ public final class Sinusoidal extends MapProjection { /** * The group of all parameters expected by this coordinate operation. */ - private static final ParameterDescriptorGroup PARAMETERS; + static final ParameterDescriptorGroup PARAMETERS; static { PARAMETERS = builder().setCodeSpace(Citations.OGC, Constants.OGC) - .addName (NAME) + .addName ("Sinusoidal") .addName ("Sanson-Flamsteed") .addName (Citations.GEOTIFF, "CT_Sinusoidal") .addIdentifier(Citations.GEOTIFF, "24") @@ -115,6 +110,15 @@ public final class Sinusoidal extends MapProjection { super(PARAMETERS); } + /** + * Constructs a math transform provider from a set of parameters. + * + * @param parameters the set of parameters (never {@code null}). + */ + Sinusoidal(final ParameterDescriptorGroup parameters) { + super(parameters); + } + /** * {@inheritDoc} * diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java index 90097ef0a1..6a669f5edc 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java @@ -381,7 +381,7 @@ public class Mercator extends ConformalProjection { @Override public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException { NormalizedProjection kernel = this; -subst: if ((variant.spherical || eccentricity == 0) && getClass() == Mercator.class) { +subst: if (variant.spherical || (eccentricity == 0 && getClass() == Mercator.class)) { if (variant == Variant.AUXILIARY && eccentricity != 0) { final int type = context.getValue(MercatorAuxiliarySphere.AUXILIARY_SPHERE_TYPE); if (type == AuthalicMercator.TYPE) { diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Sinusoidal.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Sinusoidal.java index 808d9e439d..70283f04e3 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Sinusoidal.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Sinusoidal.java @@ -17,6 +17,7 @@ package org.apache.sis.referencing.operation.projection; import java.util.EnumMap; +import java.util.regex.Pattern; import org.opengis.util.FactoryException; import org.opengis.parameter.ParameterDescriptor; import org.opengis.referencing.operation.Matrix; @@ -41,7 +42,7 @@ import static org.apache.sis.internal.referencing.provider.Sinusoidal.*; * </ul> * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 1.3 * @since 1.0 * @module */ @@ -51,17 +52,61 @@ public class Sinusoidal extends MeridianArcBased { */ private static final long serialVersionUID = 7908925241331303236L; + /** + * Variants of Sinusoidal projection. Those variants modify the way the projections are constructed + * (e.g. in the way parameters are interpreted), but formulas are basically the same after construction. + * + * <p>We do not provide such codes in public API because they duplicate the functionality of + * {@link OperationMethod} instances. We use them only for constructors convenience.</p> + */ + private enum Variant implements ProjectionVariant { + // Declaration order matter. Patterns are matched in that order. + + /** The <cite>"Pseudo sinusoidal equal-area"</cite> projection. */ + PSEUDO(".*\\bPseudo.*"); + + /** Name pattern for this variant. */ + private final Pattern operationName; + + /** Creates a new enumeration value. */ + private Variant(final String operationName) { + this.operationName = Pattern.compile(operationName, Pattern.CASE_INSENSITIVE); + } + + /** The expected name pattern of an operation method for this variant. */ + @Override public Pattern getOperationNamePattern() { + return operationName; + } + + /** EPSG identifier of an operation method for this variant. */ + @Override public String getIdentifier() { + return null; + } + } + + /** + * The type of sinusoidal projection. Possible values are: + * <ul> + * <li>{@link Variant#PSEUDO} if this projection is the "Pseudo sinusoidal equal-area" case.</li> + * <li>{@code null} for the standard case.</li> + * </ul> + * + * Other cases may be added in the future. + */ + private final Variant variant; + /** * Work around for RFE #4093999 in Sun's bug database * ("Relax constraint on placement of this()/super() call in constructors"). */ @Workaround(library="JDK", version="1.8") private static Initializer initializer(final OperationMethod method, final Parameters parameters) { + final Variant variant = variant(method, Variant.values(), null); final EnumMap<ParameterRole, ParameterDescriptor<Double>> roles = new EnumMap<>(ParameterRole.class); roles.put(ParameterRole.CENTRAL_MERIDIAN, CENTRAL_MERIDIAN); roles.put(ParameterRole.FALSE_EASTING, FALSE_EASTING); roles.put(ParameterRole.FALSE_NORTHING, FALSE_NORTHING); - return new Initializer(method, parameters, roles, null); + return new Initializer(method, parameters, roles, variant); } /** @@ -76,7 +121,17 @@ public class Sinusoidal extends MeridianArcBased { * @param parameters the parameter values of the projection to create. */ public Sinusoidal(final OperationMethod method, final Parameters parameters) { - super(initializer(method, parameters)); + this(initializer(method, parameters)); + } + + /** + * Work around for RFE #4093999 in Sun's bug database + * ("Relax constraint on placement of this()/super() call in constructors"). + */ + @Workaround(library="JDK", version="1.7") + private Sinusoidal(final Initializer initializer) { + super(initializer); + variant = (Variant) initializer.variant; } /** @@ -84,6 +139,7 @@ public class Sinusoidal extends MeridianArcBased { */ Sinusoidal(final Sinusoidal other) { super(other); + variant = other.variant; } /** @@ -101,7 +157,7 @@ public class Sinusoidal extends MeridianArcBased { @Override public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException { Sinusoidal kernel = this; - if (eccentricity == 0 && getClass() == Sinusoidal.class) { + if ((eccentricity == 0 && getClass() == Sinusoidal.class) || variant == Variant.PSEUDO) { kernel = new Spherical(this); } return context.completeTransform(factory, kernel); diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java index f2ad34531e..0fa929c114 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java @@ -160,7 +160,7 @@ * @author Rémi Maréchal (Geomatys) * @author Adrian Custer (Geomatys) * @author Matthieu Bastianelli (Geomatys) - * @version 1.2 + * @version 1.3 * * @see <a href="https://mathworld.wolfram.com/MapProjection.html">Map projections on MathWorld</a> * diff --git a/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod b/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod index 52f61edf69..a1ac1bfbf8 100644 --- a/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod +++ b/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod @@ -64,6 +64,7 @@ org.apache.sis.internal.referencing.provider.ModifiedAzimuthalEquidistant org.apache.sis.internal.referencing.provider.AzimuthalEquidistantSpherical org.apache.sis.internal.referencing.provider.ZonedTransverseMercator org.apache.sis.internal.referencing.provider.Sinusoidal +org.apache.sis.internal.referencing.provider.PseudoSinusoidal org.apache.sis.internal.referencing.provider.Polyconic org.apache.sis.internal.referencing.provider.Mollweide org.apache.sis.internal.referencing.provider.SouthPoleRotation diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java index fb24e65e70..f13cda4040 100644 --- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java +++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java @@ -36,7 +36,7 @@ import static org.junit.Assert.*; * Tests {@link Providers} and some consistency rules of all providers defined in this package. * * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.3 * @since 0.6 * @module */ @@ -114,6 +114,7 @@ public final strictfp class ProvidersTest extends TestCase { ZonedTransverseMercator.class, SatelliteTracking.class, Sinusoidal.class, + PseudoSinusoidal.class, Polyconic.class, Mollweide.class, SouthPoleRotation.class, diff --git a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java index d21d264952..8ec93cd0b7 100644 --- a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java +++ b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java @@ -37,7 +37,7 @@ import org.apache.sis.internal.netcdf.Variable; import org.apache.sis.internal.netcdf.VariableRole; import org.apache.sis.internal.netcdf.Linearizer; import org.apache.sis.internal.netcdf.Node; -import org.apache.sis.internal.referencing.provider.Sinusoidal; +import org.apache.sis.internal.referencing.provider.PseudoSinusoidal; import org.apache.sis.internal.referencing.provider.Equirectangular; import org.apache.sis.internal.referencing.provider.PolarStereographicA; import org.apache.sis.referencing.operation.transform.TransferFunction; @@ -361,13 +361,11 @@ public final class GCOM_C extends Convention { if (name == null) { return super.projection(node); } - Number radius = null; final String method; final int s = name.indexOf(' '); final String code = (s >= 0) ? name.substring(0, s) : name; if (code.equalsIgnoreCase("EQA")) { - method = Sinusoidal.NAME; - radius = 6371000; // "Not specified (based on Authalic Sphere)" datum (EPSG:6035). + method = PseudoSinusoidal.NAME; } else if (code.equalsIgnoreCase("EQR")) { method = Equirectangular.NAME; } else if (code.equalsIgnoreCase("PS")) { @@ -378,11 +376,6 @@ public final class GCOM_C extends Convention { final Map<String,Object> definition = new HashMap<>(4); definition.put(CF.GRID_MAPPING_NAME, method); definition.put(CONVERSION_NAME, name); - if (radius != null) { - definition.put(CF.SEMI_MAJOR_AXIS, radius); - definition.put(CF.SEMI_MINOR_AXIS, radius); - definition.put(ELLIPSOID_NAME, "Authalic sphere"); - } return definition; }