This is an automated email from the ASF dual-hosted git repository.

jsorel 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 e15aa86  Mollweide : add support for Mollweide operation
e15aa86 is described below

commit e15aa86a1bac6771d592866bb6a03d317ef25d80
Author: jsorel <johann.so...@geomatys.com>
AuthorDate: Fri Jul 27 17:13:07 2018 +0200

    Mollweide : add support for Mollweide operation
---
 .../internal/referencing/provider/Mollweide.java   | 102 +++++++++++++++
 .../operation/projection/Mollweide.java            | 129 ++++++++++++++++++
 ...g.opengis.referencing.operation.OperationMethod |   1 +
 .../referencing/provider/ProvidersTest.java        |   1 +
 .../operation/projection/MollweideTest.java        | 145 +++++++++++++++++++++
 .../sis/test/suite/ReferencingTestSuite.java       |   1 +
 6 files changed, 379 insertions(+)

diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mollweide.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mollweide.java
new file mode 100644
index 0000000..72e3571
--- /dev/null
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mollweide.java
@@ -0,0 +1,102 @@
+/*
+ * 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 org.apache.sis.internal.util.Constants;
+import org.apache.sis.parameter.ParameterBuilder;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.referencing.operation.projection.NormalizedProjection;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.parameter.ParameterNotFoundException;
+
+/**
+ * The provider for <cite>"Mollweide"</cite> projection.
+ * There are no EPSG projection using this operation.
+ *
+ * @see <a 
href="http://mathworld.wolfram.com/MollweideProjection.html";>Mathworld 
formulas</a>
+ *
+ * @author Johann Sorel (Geomatys)
+ * @version 1.0
+ * @since 1.0
+ * @module
+ */
+public class Mollweide extends MapProjection {
+
+    /**
+     * The operation parameter descriptor for the {@linkplain
+     * org.apache.sis.internal.util.Constants#centralMeridian
+     * central meridian} parameter value.
+     *
+     * This parameter is <a 
href="package-summary.html#Obligation">mandatory</a>.
+     * Valid values range is [-180 &hellip; 180]&deg; and default value is 
0&deg;.
+     */
+    public static final ParameterDescriptor<Double> CENTRAL_MERIDIAN;
+
+    /**
+     * The operation parameter descriptor for the {@linkplain
+     * org.apache.sis.internal.util.Constants.Parameters#falseEasting
+     * false easting} parameter value.
+     *
+     * This parameter is <a 
href="package-summary.html#Obligation">mandatory</a>.
+     * Valid values range is unrestricted and default value is 0 metre.
+     */
+    public static final ParameterDescriptor<Double> FALSE_EASTING;
+
+    /**
+     * The operation parameter descriptor for the {@linkplain
+     * org.apache.sis.internal.util.Constants.Parameters#falseNorthing
+     * false northing} parameter value.
+     *
+     * This parameter is <a 
href="package-summary.html#Obligation">mandatory</a>.
+     * Valid values range is unrestricted and default value is 0 metre.
+     */
+    public static final ParameterDescriptor<Double> FALSE_NORTHING;
+
+    /**
+     * The group of all parameters expected by this coordinate operation.
+     */
+    static final ParameterDescriptorGroup PARAMETERS;
+    /**
+     * Parameters creation, which must be done before to initialize the {@link 
#PARAMETERS} field.
+     * Note that the central Meridian and Latitude of Origin are shared with 
ObliqueStereographic.
+     */
+    static {
+        final ParameterBuilder builder = new ParameterBuilder();
+
+        CENTRAL_MERIDIAN = 
createLongitude(builder.addName(Constants.CENTRAL_MERIDIAN));
+        FALSE_EASTING = createShift(builder.addName(Constants.FALSE_EASTING));
+        FALSE_NORTHING = 
createShift(builder.addName(Constants.FALSE_NORTHING));
+
+        PARAMETERS = new ParameterBuilder()
+                .addName("Mollweide")
+                .createGroupForMapProjection(
+                        CENTRAL_MERIDIAN,
+                        FALSE_EASTING,
+                        FALSE_NORTHING);
+    }
+
+    public Mollweide() {
+        super(PARAMETERS);
+    }
+
+    @Override
+    protected NormalizedProjection createProjection(Parameters parameters) 
throws ParameterNotFoundException {
+        return new 
org.apache.sis.referencing.operation.projection.Mollweide(this, 
Parameters.castOrWrap(parameters));
+    }
+
+}
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mollweide.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mollweide.java
new file mode 100644
index 0000000..be97193
--- /dev/null
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mollweide.java
@@ -0,0 +1,129 @@
+/*
+ * 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 static java.lang.Math.*;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.referencing.operation.matrix.MatrixSIS;
+import org.apache.sis.referencing.operation.transform.ContextualParameters;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.OperationMethod;
+
+/**
+ * <cite>Mollweide</cite> projection.
+ * The Mollweide projection do not preserve angles,surfaces
+ *
+ * TODO : this transform causes issues with large envelopes, we need to have 
the
+ *        information about tranform capability (bijective,subjective,...)
+ *        to correctly choose an appropriate common CRS for intersection.
+ *
+ * @see <a 
href="http://mathworld.wolfram.com/MollweideProjection.html";>Mathworld 
formulas</a>
+ *
+ * @author Johann Sorel (Geomatys)
+ * @version 1.0
+ * @since 1.0
+ * @module
+ */
+public class Mollweide extends NormalizedProjection{
+
+    private static final Map<ParameterRole, ParameterDescriptor<? extends 
Number>> ROLES = new HashMap<>();
+    static {
+        ROLES.put(ParameterRole.CENTRAL_MERIDIAN, 
org.apache.sis.internal.referencing.provider.Mollweide.CENTRAL_MERIDIAN);
+        ROLES.put(ParameterRole.FALSE_EASTING, 
org.apache.sis.internal.referencing.provider.Mollweide.FALSE_EASTING);
+        ROLES.put(ParameterRole.FALSE_NORTHING, 
org.apache.sis.internal.referencing.provider.Mollweide.FALSE_NORTHING);
+    }
+
+    private static final double SR2 = sqrt(2);
+    private static final double LAMDA_LIMIT = 2*SR2*PI;
+
+    /**
+     * Constructs a new map projection from the supplied parameters.
+     *
+     * @param parameters The parameters of the projection to be created.
+     */
+    public Mollweide(final OperationMethod method, final Parameters 
parameters) {
+        super(method, parameters, ROLES);
+        final MatrixSIS normalize   = 
context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION);
+        final MatrixSIS denormalize = 
context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
+        normalize.convertBefore(0, 2*SR2, null);
+        denormalize.convertBefore(0, 1/PI, null);
+        denormalize.convertBefore(1, SR2, null);
+    }
+
+    @Override
+    public Matrix transform(double[] srcPts, int srcOff, double[] dstPts, int 
dstOff, boolean derivate) throws ProjectionException {
+        if (derivate) {
+            //TODO
+            throw new ProjectionException("Derivation not supported");
+        }
+
+        final double λ = srcPts[srcOff]; //longitude
+        final double φ = srcPts[srcOff + 1]; //latitude
+        double primeθ = 2 * asin( (2 * φ) / PI );
+
+        final double sinφ = sin(φ);
+        /*
+        if sinφ is 1 or -1 we are on a pole.
+        iteration would produce NaN values.
+        */
+        if (abs(sinφ) != 1) {
+            final double pisinφ = PI * sinφ;
+            int nbIte = MAXIMUM_ITERATIONS;
+            double deltaθ = Double.MAX_VALUE;
+            do {
+                if (--nbIte < 0) {
+                    throw new ProjectionException("Operation does not 
converge");
+                }
+                deltaθ = - (primeθ + sin(primeθ) - pisinφ) / (1 + cos(primeθ));
+                primeθ += deltaθ;
+            } while (abs(deltaθ) > ITERATION_TOLERANCE);
+        }
+        final double θ = primeθ * 0.5;
+
+        final double x = λ * cos(θ);
+        final double y = sin(θ);
+
+        dstPts[dstOff    ] = x;
+        dstPts[dstOff + 1] = y;
+
+        Matrix matrix = null;
+        return matrix;
+    }
+
+    @Override
+    protected void inverseTransform(double[] srcPts, int srcOff, double[] 
dstPts, int dstOff) throws ProjectionException {
+
+        final double x = srcPts[srcOff];
+        final double y = srcPts[srcOff + 1];
+        final double θ = asin(y);
+
+        final double θθ = 2 * θ;
+        final double φ = asin( (θθ + sin(θθ)) / PI );
+        double λ = x / cos(θ);
+
+        if (abs(λ) > LAMDA_LIMIT) {
+            λ = Double.NaN;
+        }
+
+        dstPts[dstOff] = λ;
+        dstPts[dstOff+1] = φ;
+    }
+
+}
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 77628da..09c1df7 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,3 +55,4 @@ org.apache.sis.internal.referencing.provider.NTv2
 org.apache.sis.internal.referencing.provider.NADCON
 org.apache.sis.internal.referencing.provider.FranceGeocentricInterpolation
 org.apache.sis.internal.referencing.provider.Interpolation1D
+org.apache.sis.internal.referencing.provider.Mollweide
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 4b6eb94..14b5cb1 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
@@ -82,6 +82,7 @@ public final strictfp class ProvidersTest extends TestCase {
             PseudoMercator.class,
             RegionalMercator.class,
             MillerCylindrical.class,
+            Mollweide.class,
             LambertConformal1SP.class,
             LambertConformal2SP.class,
             LambertConformalWest.class,
diff --git 
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MollweideTest.java
 
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MollweideTest.java
new file mode 100644
index 0000000..9c7bf32
--- /dev/null
+++ 
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MollweideTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.util.Constants;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.TestCase;
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.util.FactoryException;
+
+/**
+ * Tests for Mollveide transform.
+ *
+ * @author Johann Sorel (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+@DependsOn(NormalizedProjectionTest.class)
+public class MollweideTest extends TestCase {
+
+    private double tolerance = 0.00001;
+
+    public MollweideTest() {
+    }
+
+    @Test
+    public void testTransform() throws TransformException, 
ParameterNotFoundException, FactoryException {
+        final org.apache.sis.internal.referencing.provider.Mollweide provider 
= new org.apache.sis.internal.referencing.provider.Mollweide();
+        final Parameters parameters = 
Parameters.castOrWrap(provider.getParameters().createValue());
+        parameters.parameter(Constants.CENTRAL_MERIDIAN).setValue(0.0);
+        parameters.parameter(Constants.FALSE_EASTING).setValue(0.0);
+        parameters.parameter(Constants.FALSE_NORTHING).setValue(0.0);
+        parameters.parameter(Constants.SEMI_MAJOR).setValue(6378137);
+        parameters.parameter(Constants.SEMI_MINOR).setValue(6378137);
+
+
+        final MathTransform trs = 
provider.createMathTransform(DefaultFactories.forClass(MathTransformFactory.class),
 parameters);
+        final MathTransform invtrs = trs.inverse();
+
+        final double[] in = new double[2];
+        final double[] out = new double[2];
+
+        // at (0,0) point should be unchanged
+        in[0] = 0.0;
+        in[1] = 0.0;
+        trs.transform(in, 0, out, 0, 1);
+        assertEquals(0.0, out[0], tolerance);
+        assertEquals(0.0, out[1], tolerance);
+
+        // at (0,±90) north/south poles singularity
+        in[0] = 0.0;
+        in[1] = 90;
+        trs.transform(in, 0, out, 0, 1);
+        assertEquals(0.0, out[0], tolerance);
+        assertEquals(9020047.848073645, out[1], tolerance);
+        invtrs.transform(out, 0, in, 0, 1);
+        assertEquals(0.0, in[0], tolerance);
+        assertEquals(90.0, in[1], tolerance);
+
+        in[0] = 0.0;
+        in[1] = -90;
+        trs.transform(in, 0, out, 0, 1);
+        assertEquals(0.0, out[0], tolerance);
+        assertEquals(-9020047.848073645, out[1], tolerance);
+        invtrs.transform(out, 0, in, 0, 1);
+        assertEquals(0.0, in[0], tolerance);
+        assertEquals(-90.0, in[1], tolerance);
+
+        // at (0,~90) point near north pole singularity should be close to 
~9.000.000
+        in[0] = 0.0;
+        in[1] = 89;
+        trs.transform(in, 0, out, 0, 1);
+        assertEquals(0.0, out[0], tolerance);
+        assertEquals(8997266.89915323, out[1], tolerance);
+        invtrs.transform(out, 0, in, 0, 1);
+        assertEquals(0.0, in[0], tolerance);
+        assertEquals(89.0, in[1], tolerance);
+
+        //other random points
+        //compared to epsg.io (Bad reference, find something more trustable)
+        
//https://epsg.io/transform#s_srs=4326&t_srs=54009&x=-150.0000000&y=-70.0000000
+        in[0] = 12.0;
+        in[1] = 50.0;
+        trs.transform(in, 0, out, 0, 1);
+        assertEquals(912759.82345261, out[0], tolerance);
+        assertEquals(5873471.95621065, out[1], tolerance);
+        invtrs.transform(out, 0, in, 0, 1);
+        assertEquals(12.0, in[0], tolerance);
+        assertEquals(50.0, in[1], tolerance);
+
+
+        in[0] = -150.0;
+        in[1] = -70.0;
+        trs.transform(in, 0, out, 0, 1);
+        assertEquals(-7622861.35718471, out[0], tolerance);
+        assertEquals(-7774469.60789149, out[1], tolerance);
+        invtrs.transform(out, 0, in, 0, 1);
+        assertEquals(-150.0, in[0], tolerance);
+        assertEquals(-70.0, in[1], tolerance);
+
+        in[0] = -179.9999;
+        in[1] = 0.0;
+        trs.transform(in, 0, out, 0, 1);
+        assertEquals(-18040085.67387191, out[0], tolerance);
+        assertEquals(0.0, out[1], tolerance);
+        invtrs.transform(out, 0, in, 0, 1);
+        assertEquals(-179.9999, in[0], tolerance);
+        assertEquals(0.0, in[1], tolerance);
+
+        //outside of validity area, should have NaN with the reverse transform
+        in[0] = -180.0001;
+        in[1] = 0.0;
+        trs.transform(in, 0, out, 0, 1);
+        assertEquals(-1.8040105718422677E7, out[0], tolerance);
+        assertEquals(0.0, out[1], tolerance);
+        invtrs.transform(out, 0, in, 0, 1);
+        assertEquals(Double.NaN, in[0], tolerance);
+        assertEquals(0.0, in[1], tolerance);
+
+
+    }
+
+}
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 9e395d9..c63c51e 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
@@ -171,6 +171,7 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.operation.projection.ObliqueMercatorTest.class,
     
org.apache.sis.referencing.operation.projection.CylindricalEqualAreaTest.class,
     org.apache.sis.referencing.operation.projection.AlbersEqualAreaTest.class,
+    org.apache.sis.referencing.operation.projection.MollweideTest.class,
 
     // Coordinate operation and derived Coordinate Reference Systems (cyclic 
dependency).
     org.apache.sis.referencing.operation.DefaultTransformationTest.class,

Reply via email to