sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Begin implementation of "Modified Azimuthal Equidistant" projection (EPSG:9832). Only forward projection for now. Inverse projection and derivative will be in a next commit.
Date Tue, 17 Mar 2020 21:45:11 GMT
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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 8f1e806  Begin implementation of "Modified Azimuthal Equidistant" projection (EPSG:9832).
Only forward projection for now. Inverse projection and derivative will be in a next commit.
8f1e806 is described below

commit 8f1e80667c5b2249d405b0aedd380c1040d966be
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Tue Mar 17 22:43:52 2020 +0100

    Begin implementation of "Modified Azimuthal Equidistant" projection (EPSG:9832).
    Only forward projection for now. Inverse projection and derivative will be in a next commit.
    
    https://issues.apache.org/jira/browse/SIS-237
---
 .../provider/ModifiedAzimuthalEquidistant.java     | 163 +++++++++++++++++
 .../projection/ModifiedAzimuthalEquidistant.java   | 198 +++++++++++++++++++++
 ...g.opengis.referencing.operation.OperationMethod |   1 +
 .../referencing/provider/ProvidersTest.java        |   1 +
 .../ModifiedAzimuthalEquidistantTest.java          |  50 ++++++
 .../sis/test/suite/ReferencingTestSuite.java       |   1 +
 6 files changed, 414 insertions(+)

diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ModifiedAzimuthalEquidistant.java
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ModifiedAzimuthalEquidistant.java
new file mode 100644
index 0000000..9b2abd1
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ModifiedAzimuthalEquidistant.java
@@ -0,0 +1,163 @@
+/*
+ * 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.ParameterDescriptor;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.apache.sis.parameter.ParameterBuilder;
+import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.referencing.operation.projection.NormalizedProjection;
+import org.opengis.referencing.operation.PlanarProjection;
+
+
+/**
+ * The provider for <cite>"Modified Azimuthal Equidistant"</cite> projection
(EPSG:9832).
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ *
+ * @see <a href="http://geotiff.maptools.org/proj_list/azimuthal_equidistant.html">GeoTIFF
parameters for Azimuthal Equidistant</a>
+ *
+ * @since 1.1
+ * @module
+ */
+@XmlTransient
+public final class ModifiedAzimuthalEquidistant extends MapProjection {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = -9025540136016917410L;
+
+    /**
+     * The operation parameter descriptor for the <cite>Latitude of natural origin</cite>
(φ₀) parameter value.
+     * Valid values range is (-90 … 90)° and default value is 0°.
+     *
+     * <!-- Generated by ParameterNameTableGenerator -->
+     * <table class="sis">
+     *   <caption>Parameter names</caption>
+     *   <tr><td> EPSG:    </td><td> Latitude of natural origin </td></tr>
+     *   <tr><td> GeoTIFF: </td><td> CenterLat </td></tr>
+     *   <tr><td> Proj4:   </td><td> lat_0 </td></tr>
+     * </table>
+     */
+    public static final ParameterDescriptor<Double> LATITUDE_OF_ORIGIN;
+
+    /**
+     * The operation parameter descriptor for the <cite>Longitude of natural origin</cite>
(λ₀) parameter value.
+     * Valid values range is [-180 … 180]° and default value is 0°.
+     *
+     * <!-- Generated by ParameterNameTableGenerator -->
+     * <table class="sis">
+     *   <caption>Parameter names</caption>
+     *   <tr><td> EPSG:    </td><td> Longitude of natural origin
</td></tr>
+     *   <tr><td> GeoTIFF: </td><td> CenterLong </td></tr>
+     *   <tr><td> Proj4:   </td><td> lon_0 </td></tr>
+     * </table>
+     */
+    public static final ParameterDescriptor<Double> LONGITUDE_OF_ORIGIN;
+
+    /**
+     * The operation parameter descriptor for the <cite>False easting</cite>
(FE) parameter value.
+     * Valid values range is unrestricted and default value is 0 metre.
+     *
+     * <!-- Generated by ParameterNameTableGenerator -->
+     * <table class="sis">
+     *   <caption>Parameter names</caption>
+     *   <tr><td> EPSG:    </td><td> False easting </td></tr>
+     *   <tr><td> GeoTIFF: </td><td> FalseEasting </td></tr>
+     *   <tr><td> Proj4:   </td><td> x_0 </td></tr>
+     * </table>
+     */
+    public static final ParameterDescriptor<Double> FALSE_EASTING;
+
+    /**
+     * The operation parameter descriptor for the <cite>False northing</cite>
(FN) parameter value.
+     * Valid values range is unrestricted and default value is 0 metre.
+     *
+     * <!-- Generated by ParameterNameTableGenerator -->
+     * <table class="sis">
+     *   <caption>Parameter names</caption>
+     *   <tr><td> EPSG:    </td><td> False northing </td></tr>
+     *   <tr><td> GeoTIFF: </td><td> FalseNorthing </td></tr>
+     *   <tr><td> Proj4:   </td><td> y_0 </td></tr>
+     * </table>
+     */
+    public static final ParameterDescriptor<Double> FALSE_NORTHING;
+
+    /**
+     * Returns a parameter with the same names and identifiers than the given parameter,
+     * except OGC, ESRI and netCDF names which are omitted. We omit those names for now
+     * because we have not seen a reference about what those parameter names should be.
+     * This may be revisited in future SIS versions.
+     *
+     * <p>The OGC and GeoTIFF names kept by this method are actually the names for
+     * <cite>Azimuthal Equidistant</cite> (not modified) projection.</p>
+     */
+    private static ParameterBuilder erase(final ParameterBuilder builder, ParameterDescriptor<?>
template) {
+        return builder.addNamesAndIdentifiers(template)                         // Copy from
this parameter…
+                      .rename(Citations.OGC,    (CharSequence[]) null)          // … except
for those names.
+                      .rename(Citations.ESRI,   (CharSequence[]) null)
+                      .rename(Citations.NETCDF, (CharSequence[]) null);
+    }
+
+    /**
+     * The group of all parameters expected by this coordinate operation.
+     */
+    static final ParameterDescriptorGroup PARAMETERS;
+    static {
+        final ParameterBuilder builder = builder();
+        LATITUDE_OF_ORIGIN  = createLatitude (erase(builder, Orthographic.LATITUDE_OF_ORIGIN),
true);
+        LONGITUDE_OF_ORIGIN = createLongitude(erase(builder, Orthographic.LONGITUDE_OF_ORIGIN));
+        FALSE_EASTING       = createShift    (erase(builder, Orthographic.FALSE_EASTING));
+        FALSE_NORTHING      = createShift    (erase(builder, Orthographic.FALSE_NORTHING));
+
+        PARAMETERS = builder.addIdentifier("9832")
+                .addName("Modified Azimuthal Equidistant")
+                .createGroupForMapProjection(
+                        LATITUDE_OF_ORIGIN,
+                        LONGITUDE_OF_ORIGIN,
+                        FALSE_EASTING,
+                        FALSE_NORTHING);
+    }
+
+    /**
+     * Constructs a new provider.
+     */
+    public ModifiedAzimuthalEquidistant() {
+        super(PARAMETERS);
+    }
+
+    /**
+     * Returns the operation type for this map projection.
+     */
+    @Override
+    public Class<PlanarProjection> getOperationType() {
+        return PlanarProjection.class;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the map projection created from the given parameter values.
+     */
+    @Override
+    protected final NormalizedProjection createProjection(final Parameters parameters) {
+        return new org.apache.sis.referencing.operation.projection.ModifiedAzimuthalEquidistant(this,
parameters);
+    }
+}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ModifiedAzimuthalEquidistant.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ModifiedAzimuthalEquidistant.java
new file mode 100644
index 0000000..51e5663
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ModifiedAzimuthalEquidistant.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.operation.projection;
+
+import java.util.EnumMap;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.parameter.ParameterDescriptor;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.referencing.operation.transform.ContextualParameters;
+import org.apache.sis.referencing.operation.matrix.MatrixSIS;
+import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.util.Workaround;
+
+import static java.lang.Math.*;
+import static org.apache.sis.internal.referencing.provider.ModifiedAzimuthalEquidistant.*;
+
+
+/**
+ * <cite>Modified Azimuthal Equidistant</cite> projection (EPSG:9832).
+ * See the following references for an overview:
+ * <ul>
+ *   <li><a href="https://en.wikipedia.org/wiki/Azimuthal_equidistant_projection">Azimuthal
equidistant projection</a></li>
+ *   <li><a href="https://mathworld.wolfram.com/AzimuthalEquidistantProjection.html">Azimuthal
Equidistant Projection</a></li>
+ * </ul>
+ *
+ * <h2>Description</h2>
+ * An approximation of the oblique form of the <cite>Azimuthal Equidistant</cite>
projection.
+ * For relatively short distances (e.g. under 800 kilometres) this modification introduces
no significant error.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ * @since   1.1
+ * @module
+ */
+public class ModifiedAzimuthalEquidistant extends NormalizedProjection {
+    /**
+     * Sine and cosine of the latitude of origin φ₀.
+     */
+    private final double sinφ0, cosφ0;
+
+    /**
+     * The radius of curvature (assuming <var>a</var>=1) at the latitude of origin
+     * multiplied by the sine of that latitude.
+     */
+    private final double ℯ2_ν0_sinφ0;
+
+    /**
+     * The ℯ⋅sin(φ₀)/√(1 − ℯ²) term.
+     */
+    private final double G;
+
+    /**
+     * The ℯ⋅cos(φ₀)/√(1 − ℯ²) term. This is the <var>H</var> term
in EPSG guidance notes
+     * but without the cos(α) term.
+     */
+    private final double Hp;
+
+    /**
+     * 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 EnumMap<ParameterRole, ParameterDescriptor<Double>> roles = new
EnumMap<>(ParameterRole.class);
+        roles.put(ParameterRole.CENTRAL_MERIDIAN, LONGITUDE_OF_ORIGIN);
+        roles.put(ParameterRole.FALSE_EASTING,    FALSE_EASTING);
+        roles.put(ParameterRole.FALSE_NORTHING,   FALSE_NORTHING);
+        return new Initializer(method, parameters, roles, (byte) 0);
+    }
+
+    /**
+     * Creates a Modified Azimuthal Equidistant projection from the given parameters.
+     * The {@code method} argument can be the description of one of the following:
+     *
+     * <ul>
+     *   <li><cite>"Modified Azimuthal Equidistant"</cite>.</li>
+     * </ul>
+     *
+     * @param method      description of the projection parameters.
+     * @param parameters  the parameter values of the projection to create.
+     */
+    public ModifiedAzimuthalEquidistant(final OperationMethod method, final Parameters 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.8")
+    private ModifiedAzimuthalEquidistant(final Initializer initializer) {
+        super(initializer);
+        final double φ0 = toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
+        cosφ0 = cos(φ0);
+        sinφ0 = sin(φ0);
+        final double ν0 = initializer.radiusOfCurvature(sinφ0);
+        ℯ2_ν0_sinφ0 = eccentricitySquared * ν0 * sinφ0;
+        final double f = eccentricity / sqrt(1 - eccentricitySquared);
+        G  = f * sinφ0;
+        Hp = f * cosφ0;
+
+        final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
+        denormalize.convertBefore(0, ν0, null);
+        denormalize.convertBefore(1, ν0, null);
+    }
+
+    /**
+     * Converts the specified (λ,φ) coordinate and stores the (<var>x</var>,<var>y</var>)
result in {@code dstPts}.
+     *
+     * @return the matrix of the projection derivative at the given source position,
+     *         or {@code null} if the {@code derivate} argument is {@code false}.
+     * @throws ProjectionException if the coordinate can not be converted.
+     */
+    @Override
+    public Matrix transform(final double[] srcPts, final int srcOff,
+                            final double[] dstPts, final int dstOff,
+                            final boolean derivate) throws ProjectionException
+    {
+        final double λ    = srcPts[srcOff  ];
+        final double φ    = srcPts[srcOff+1];
+        final double cosλ = cos(λ);
+        final double sinλ = sin(λ);
+        final double cosφ = cos(φ);
+        final double sinφ = sin(φ);
+        final double rν   = sqrt(1 - eccentricitySquared*(sinφ*sinφ));
+        final double Ψ    = atan((1 - eccentricitySquared)*tan(φ) + ℯ2_ν0_sinφ0*rν/cosφ);
+        final double α    = atan2(sinλ, cosφ0*tan(Ψ) - sinφ0*cosλ);
+        final double sinα = sin(α);
+        final double cosα = cos(α);
+        final double H    = cosα * Hp;
+        double c;
+        if (abs(α) < ANGULAR_TOLERANCE) {
+            c = cosφ0*sin(Ψ) - sinφ0*cos(Ψ);
+            if (abs(α) > PI/2) c = -c;
+        } else {
+            c = sinλ*cos(Ψ) / sinα;
+        }
+        c = asin(c);                    // After this line this is the `s` value in EPSG
guidance notes.
+        final double s2 = c  * c;
+        final double s3 = s2 * c;
+        final double s4 = s2 * s2;
+        final double s5 = s4 * c;
+        final double H2 = H*H;
+        final double GH = G*H;
+        c *= 1 - (s2/6   *  H2*(1 -   H2))
+               + (s3/8   *  GH*(1 - 2*H2))
+               + (s4/120 * (H2*(4 - 7*H2) - 3*(G*G)*(1 - 7*H2)))
+               - (s5/48  * GH);
+        if (dstPts != null) {
+            dstPts[dstOff  ] = c*sinα;
+            dstPts[dstOff+1] = c*cosα;
+        }
+        if (!derivate) {
+            return null;
+        }
+        throw new ProjectionException("Derivative not yet implemented.");
+    }
+
+    /**
+     * Converts the specified (<var>x</var>,<var>y</var>) coordinates
+     * and stores the result in {@code dstPts} (angles in radians).
+     */
+    @Override
+    protected void inverseTransform(final double[] srcPts, final int srcOff,
+                                    final double[] dstPts, final int dstOff)
+            throws ProjectionException
+    {
+        throw new ProjectionException("Inverse transform not yet implemented.");
+    }
+
+    /**
+     * Compares the given object with this transform for equivalence.
+     */
+    @Override
+    public boolean equals(final Object object, final ComparisonMode mode) {
+        if (super.equals(object, mode)) {
+            final ModifiedAzimuthalEquidistant that = (ModifiedAzimuthalEquidistant) object;
+            return Numerics.epsilonEqual(ℯ2_ν0_sinφ0, that.ℯ2_ν0_sinφ0, mode);
+        }
+        return false;
+    }
+}
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 ae5ddfe..b549967 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
@@ -55,6 +55,7 @@ org.apache.sis.internal.referencing.provider.ObliqueMercatorCenter
 org.apache.sis.internal.referencing.provider.ObliqueMercatorTwoPoints
 org.apache.sis.internal.referencing.provider.ObliqueMercatorTwoPointsCenter
 org.apache.sis.internal.referencing.provider.Orthographic
+org.apache.sis.internal.referencing.provider.ModifiedAzimuthalEquidistant
 org.apache.sis.internal.referencing.provider.ZonedTransverseMercator
 org.apache.sis.internal.referencing.provider.Sinusoidal
 org.apache.sis.internal.referencing.provider.Polyconic
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 3373bae..7bc59ed 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
@@ -104,6 +104,7 @@ public final strictfp class ProvidersTest extends TestCase {
             ObliqueMercatorTwoPoints.class,
             ObliqueMercatorTwoPointsCenter.class,
             Orthographic.class,
+            ModifiedAzimuthalEquidistant.class,
             ZonedTransverseMercator.class,
             SatelliteTracking.class,
             Sinusoidal.class,
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ModifiedAzimuthalEquidistantTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ModifiedAzimuthalEquidistantTest.java
new file mode 100644
index 0000000..f131653
--- /dev/null
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ModifiedAzimuthalEquidistantTest.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.operation.projection;
+
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.util.FactoryException;
+import org.apache.sis.test.DependsOn;
+import org.junit.Test;
+
+
+/**
+ * Tests the {@link ModifiedAzimuthalEquidistant} class.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ * @since   1.1
+ * @module
+ */
+@DependsOn(NormalizedProjectionTest.class)
+public final strictfp class ModifiedAzimuthalEquidistantTest extends MapProjectionTestCase
{
+    /**
+     * Tests the <cite>"Modified Azimuthal Equidistant"</cite> (EPSG:9832) projection
method.
+     * This test is defined in GeoAPI conformance test suite.
+     *
+     * @throws FactoryException if an error occurred while creating the map projection.
+     * @throws TransformException if an error occurred while projecting a coordinate.
+     *
+     * @see org.opengis.test.referencing.ParameterizedTransformTest#testModifiedAzimuthalEquidistant()
+     */
+    @Test
+    @org.junit.Ignore("Implementation not yet completed")
+    public void runGeoapiTest() throws FactoryException, TransformException {
+        createGeoApiTest(new org.apache.sis.internal.referencing.provider.ModifiedAzimuthalEquidistant())
+                         .testModifiedAzimuthalEquidistant();
+    }
+}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
b/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
index 5e26fe4..7d9facb 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
@@ -192,6 +192,7 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.operation.projection.PolyconicTest.class,
     org.apache.sis.referencing.operation.projection.MollweideTest.class,
     org.apache.sis.referencing.operation.projection.OrthographicTest.class,
+    org.apache.sis.referencing.operation.projection.ModifiedAzimuthalEquidistantTest.class,
     org.apache.sis.referencing.operation.projection.SatelliteTrackingTest.class,
 
     // Coordinate operation and derived Coordinate Reference Systems (cyclic dependency).


Mime
View raw message