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: Port the "American Polyconic" projection (EPSG:9818) from Geotk as a side effect of the work on the Sinudoisal projection (those two projections share a common basis coded in MericianArcBased class) and cleanup some tests based on the experience gained by the addition of those two projections.
Date Tue, 30 Apr 2019 11:20:56 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 8ca9f9a  Port the "American Polyconic" projection (EPSG:9818) from Geotk as a side effect of the work on the Sinudoisal projection (those two projections share a common basis coded in MericianArcBased class) and cleanup some tests based on the experience gained by the addition of those two projections.
8ca9f9a is described below

commit 8ca9f9abb7d87f748e73d5fddb62eb056c98c7e6
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Tue Apr 30 13:19:10 2019 +0200

    Port the "American Polyconic" projection (EPSG:9818) from Geotk as a side effect of the work on the Sinudoisal projection
    (those two projections share a common basis coded in MericianArcBased class) and cleanup some tests based on the experience
    gained by the addition of those two projections.
---
 .../internal/referencing/provider/Polyconic.java   | 117 +++++++
 .../operation/projection/Initializer.java          |   9 +-
 .../operation/projection/MeridianArcBased.java     |   2 +-
 .../operation/projection/NormalizedProjection.java |   2 +-
 .../operation/projection/Polyconic.java            | 382 +++++++++++++++++++++
 ...g.opengis.referencing.operation.OperationMethod |   1 +
 .../referencing/provider/ProvidersTest.java        |   5 +-
 .../operation/projection/AlbersEqualAreaTest.java  |  10 +-
 .../projection/MapProjectionTestCase.java          |  17 +-
 .../projection/ObliqueStereographicTest.java       |   2 +-
 .../{SinusoidalTest.java => PolyconicTest.java}    |  89 +++--
 .../operation/projection/SinusoidalTest.java       |  55 +--
 .../sis/test/suite/ReferencingTestSuite.java       |   1 +
 .../org/apache/sis/storage/gdal/TransformTest.java |   3 +-
 14 files changed, 611 insertions(+), 84 deletions(-)

diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Polyconic.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Polyconic.java
new file mode 100644
index 0000000..ac774db
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Polyconic.java
@@ -0,0 +1,117 @@
+/*
+ * 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.opengis.referencing.operation.ConicProjection;
+import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.referencing.operation.projection.NormalizedProjection;
+
+
+/**
+ * The provider for "<cite>American Polyconic</cite>" projection (EPSG:9818).
+ *
+ * @author  Simon Reynard (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ *
+ * @see <a href="http://geotiff.maptools.org/proj_list/polyconic.html">GeoTIFF parameters for Polyconic</a>
+ *
+ * @since 1.0
+ * @module
+ */
+@XmlTransient
+public class Polyconic extends MapProjection {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = -1825903718928445742L;
+
+    /**
+     * 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°.
+     */
+    public static final ParameterDescriptor<Double> LATITUDE_OF_ORIGIN = TransverseMercator.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°.
+     */
+    public static final ParameterDescriptor<Double> LONGITUDE_OF_ORIGIN = TransverseMercator.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.
+     */
+    public static final ParameterDescriptor<Double> FALSE_EASTING = TransverseMercator.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.
+     */
+    public static final ParameterDescriptor<Double> FALSE_NORTHING = TransverseMercator.FALSE_NORTHING;
+
+    /**
+     * The group of all parameters expected by this coordinate operation.
+     */
+    private static final ParameterDescriptorGroup PARAMETERS;
+    static {
+        PARAMETERS = builder()
+                .addIdentifier("9818")
+                .addName      ("American Polyconic")
+                .addName      (Citations.OGC,       "Polyconic")
+                .addName      (Citations.GEOTIFF,   "CT_Polyconic")
+                .addName      (Citations.PROJ4,     "poly")
+                .addIdentifier(Citations.GEOTIFF,   "22")
+                .addIdentifier(Citations.MAP_INFO,  "27")
+                .createGroupForMapProjection(
+                        LATITUDE_OF_ORIGIN,
+                        LONGITUDE_OF_ORIGIN,
+                        FALSE_EASTING,
+                        FALSE_NORTHING);
+    }
+
+    /**
+     * Constructs a new provider.
+     */
+    public Polyconic() {
+        super(PARAMETERS);
+    }
+
+    /**
+     * Returns the operation type for this map projection.
+     *
+     * @return {@code ConicProjection.class}
+     */
+    @Override
+    public Class<ConicProjection> getOperationType() {
+        return ConicProjection.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.Polyconic(this, parameters);
+    }
+}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
index cb87dd4..e76708f 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
@@ -298,13 +298,6 @@ final class Initializer {
      * <blockquote>ν = 1 / √(1 - ℯ²⋅sin²φ)</blockquote>
      *
      * This method returns 1/ν², which is the (1 - ℯ²⋅sin²φ) part of above equation.
-     *
-     * <div class="section">Relationship with Snyder</div>
-     * This is related to functions (14-15) from Snyder (used for computation of scale factors
-     * at the true scale latitude) as below:
-     *
-     * <blockquote>m = cosφ / sqrt(rν²)</blockquote>
-     *
      * Special cases:
      * <ul>
      *   <li>If φ is 0°, then <var>m</var> is 1.</li>
@@ -355,7 +348,7 @@ final class Initializer {
     }
 
     /**
-     * Returns the scale factor at latitude φ. This is computed as:
+     * Returns the scale factor at latitude φ (Snyder 14-15). This is computed as:
      *
      * <blockquote>cosφ / sqrt(rν2(sinφ))</blockquote>
      *
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java
index 4f005ea..6e369d8 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java
@@ -119,7 +119,7 @@ abstract class MeridianArcBased extends NormalizedProjection {
         cf2 = -2625./0x8000  * e10  +   175./0x6000  * e8  +  5120./0x60000 * e6  +  -15./0x20 * e4;
         cf3 =   735./0x800   * e10  +  2240./0x60000 * e8  +   -35./0x60    * e6;
         cf4 = -2205./0x1000  * e10  +  -315./0x400   * e8;
-     // c6 =   693./0x20000 * e10  omitted for now (not yet used).
+     // cf5 =   693./0x20000 * e10  omitted for now (not yet used).
         /*
          * Coefficients for inverse transform derived from Snyder 3-26 and EPSG guidance notes:
          *
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
index 2a537fd..1b6974e 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
@@ -892,7 +892,7 @@ public abstract class NormalizedProjection extends AbstractMathTransform2D imple
      * @param  applyOtherFirst  whether {@code other} is concatenated before {@code projection} or the converse.
      * @return the 3×3 matrix of the affine transform step, or {@code null} if none.
      */
-    static Matrix getMiddleMatrix(final AbstractMathTransform projection, final MathTransform other,
+    private static Matrix getMiddleMatrix(final AbstractMathTransform projection, final MathTransform other,
             final boolean applyOtherFirst)
     {
         final List<MathTransform> steps = MathTransforms.getSteps(other);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Polyconic.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Polyconic.java
new file mode 100644
index 0000000..cb08253
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Polyconic.java
@@ -0,0 +1,382 @@
+/*
+ * 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.util.FactoryException;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.apache.sis.referencing.operation.matrix.Matrix2;
+import org.apache.sis.referencing.operation.matrix.MatrixSIS;
+import org.apache.sis.referencing.operation.transform.ContextualParameters;
+import org.apache.sis.internal.referencing.Resources;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.util.Workaround;
+
+import static java.lang.Math.*;
+import static org.apache.sis.internal.referencing.provider.Polyconic.*;
+
+
+/**
+ * <cite>American Polyconic</cite> projection (EPSG codes 9818).
+ * This projection has the following properties:
+ * <ul>
+ *   <li>Neither conformal nor equal-area.</li>
+ *   <li>Parallels of latitude (except for Equator) are arcs of circles, but are not concentrics.</li>
+ *   <li>Central Meridian and Equator are straight lines; all other meridians are complex curves.</li>
+ *   <li>Scale is true along each parallel and along the central meridian, but no parallel is "standard".</li>
+ *   <li>Free of distortion only along the central meridian.</li>
+ * </ul>
+ *
+ * <p><b>References:</b></p>
+ * <ul>
+ *   <li>John P. Snyder (Map Projections - A Working Manual,<br>
+ *       U.S. Geological Survey Professional Paper 1395, 1987)</li>
+ *   <li>"Coordinate Conversions and Transformations including Formulas",<br>
+ *       EPSG Guidance Note Number 7.</li>
+ * </ul>
+ *
+ * @author  Simon Reynard (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @author  Rémi Maréchal (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+public class Polyconic extends MeridianArcBased {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = -808283103170618880L;
+
+    /**
+     * Coefficients for inverse projection. Snyder 18-17 gives:
+     *
+     * {@preformat math
+     *     c₀ =    (-5/256 ⋅e⁶  +  -3/64 ⋅e⁴  +  -1/4⋅e²  +  1)
+     *     c₂ = -2⋅(45/1024⋅e⁶  +   3/32 ⋅e⁴  +   3/8⋅e²)
+     *     c₄ = +4⋅(45/1024⋅e⁶  +  15/256⋅e⁴)
+     *     c₆ = -6⋅(35/3072⋅e⁶)
+     *     M′  = c₀ + c₂cos(2φ) + c₄cos(4φ) + c₆cos(6φ)
+     * }
+     *
+     * but using trigonometric identities we rewrite as:
+     *
+     * {@preformat math
+     *     c₀ =    1 - e²
+     *     c₂ = - 3/2 ⋅e⁴  +   3/2⋅e²
+     *     c₄ = -15/8 ⋅e⁶  +  15/8⋅e⁴
+     *     c₆ =  35/16⋅e⁶
+     *     M′  = c₀ + sin²φ⋅(c₂ + sin²φ⋅(c₄ + sin²φ⋅c₆))
+     * }
+     *
+     * @see <a href="https://svn.apache.org/repos/asf/sis/analysis/Map%20projection%20formulas.ods">Coefficients derivation</a>
+     */
+    private final double ci2, ci4, ci6;
+
+    /**
+     * 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 Polyconic projection from the given parameters.
+     * The {@code method} argument can be the description of one of the following:
+     *
+     * <ul>
+     *   <li><cite>"American Polyconic"</cite>.</li>
+     * </ul>
+     *
+     * @param method      description of the projection parameters.
+     * @param parameters  the parameter values of the projection to create.
+     */
+    public Polyconic(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").
+     */
+    private Polyconic(final Initializer initializer) {
+        super(initializer);
+        final double φ0 = toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
+        final double e2 = eccentricitySquared;
+        final double e4 = e2 * e2;
+        final double e6 = e2 * e4;
+        ci2 =  -3./2  * e4 +  3./2 * e2;
+        ci4 = -15./8  * e6 + 15./8 * e4;
+        ci6 =  35./16 * e6;
+        final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
+        denormalize.convertBefore(1, null, -distance(φ0, sin(φ0), cos(φ0)));
+    }
+
+    /**
+     * Creates a new projection initialized to the same parameters than the given one.
+     */
+    Polyconic(final Polyconic other) {
+        super(other);
+        ci2 = other.ci2;
+        ci4 = other.ci4;
+        ci6 = other.ci6;
+    }
+
+    /**
+     * Returns the sequence of <cite>normalization</cite> → {@code this} → <cite>denormalization</cite> transforms
+     * as a whole. The transform returned by this method expects (<var>longitude</var>, <var>latitude</var>)
+     * coordinates in <em>degrees</em> and returns (<var>x</var>,<var>y</var>) coordinates in <em>metres</em>.
+     *
+     * <p>The non-linear part of the returned transform will be {@code this} transform, except if the ellipsoid
+     * is spherical. In the later case, {@code this} transform will be replaced by a simplified implementation.</p>
+     *
+     * @param  factory  the factory to use for creating the transform.
+     * @return the map projection from (λ,φ) to (<var>x</var>,<var>y</var>) coordinates.
+     * @throws FactoryException if an error occurred while creating a transform.
+     */
+    @Override
+    public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException {
+        Polyconic kernel = this;
+        if (eccentricity == 0) {
+            kernel = new Spherical(this);
+        }
+        return context.completeTransform(factory, kernel);
+    }
+
+    /**
+     * Converts the specified (λ,φ) coordinate (units in radians) and stores the result in {@code dstPts}
+     * (linear distance on a unit sphere). In addition, opportunistically computes the projection derivative
+     * if {@code derivate} is {@code true}.
+     *
+     * @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 coordinates 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 sinφ  = sin(φ);
+        final double cosφ  = cos(φ);
+        final double νcosφ = cosφ / sqrt(1 - eccentricitySquared*(sinφ*sinφ));
+        final double νcotφ = νcosφ / sinφ;
+        if (Double.isInfinite(νcotφ)) {                 // May happen if φ == 0.
+            if (dstPts != null) {
+                dstPts[dstOff  ] = λ;
+                dstPts[dstOff+1] = φ;
+            }
+            return derivate ? new Matrix2() : null;
+        }
+        final double L    = λ*sinφ;                     // Named E in Snyder 18-2.
+        final double sinL = sin(L);
+        final double cosL = cos(L);
+        if (dstPts != null) {
+            dstPts[dstOff  ] = νcotφ * sinL;
+            dstPts[dstOff+1] = νcotφ*(1 - cosL) + distance(φ, sinφ, cosφ);
+        }
+        if (!derivate) {
+            return null;
+        }
+        final double cotφ = cosφ / sinφ;
+        double dνcotφ_dφ = νcosφ * eccentricity;
+        dνcotφ_dφ = (dνcotφ_dφ - 1) * (dνcotφ_dφ + 1) / cotφ - cotφ;
+        final double dL_dφ = λ*cosφ;
+        return new Matrix2(
+                νcosφ * cosL,  νcotφ * (dL_dφ * cosL + dνcotφ_dφ * (  sinL)),
+                νcosφ * sinL,  νcotφ * (dL_dφ * sinL + dνcotφ_dφ * (1-cosL)) + dM_dφ(sinφ*sinφ));
+    }
+
+    /**
+     * Transforms the specified (<var>x</var>,<var>y</var>) coordinates
+     * and stores the result in {@code dstPts} (angles in radians).
+     *
+     * @throws ProjectionException if the coordinates can not be converted.
+     */
+    @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];
+        double φ = y;                           // A = (M₀ + (N-FE)/a)      — Snyder 18-18 with M₀=0, FE=0 and a=1.
+        final double B = y*y + x*x;             // B = A² + ((E-FE)²/a²)    — Synder 18-19 with FE=0 and a=1.
+        int i = MAXIMUM_ITERATIONS;
+        double dφ;
+        do {
+            if (--i < 0) {
+                throw new ProjectionException(Resources.format(Resources.Keys.NoConvergence));
+            }
+            final double cosφ  = cos(φ);
+            final double sinφ  = sin(φ);
+            final double sinφ2 = sinφ*sinφ;
+            final double rν    = sqrt(1 - eccentricitySquared * sinφ2);
+            final double C     = rν * sinφ/cosφ;
+            final double M     = distance(φ, sinφ, cosφ);
+            final double Mp    = (1 - eccentricitySquared) + sinφ2*(ci2 + sinφ2*(ci4 + sinφ2*ci6));     // Derived from Snyder 18-17
+            final double M2B   = M*M + B;
+            final double sin2φ = sin(2*φ);
+            /*
+             * Following monster is Snyder 18-21 simplified with A=y and Ma=M.
+             * This is also EPSG formula with A=y and J=M and H=Mp.
+             *
+             * Note for comparison purposes: the spherical formula is:
+             *
+             *   dφ = (y*(φ*tanφ + 1) - φ - 0.5*(φ*φ + B)*tanφ) / ((φ - y) / tanφ - 1)
+             */
+            dφ = (y*(M*C + 1) - M - 0.5*M2B*C) /
+                        (eccentricitySquared*sin2φ*(M2B - 2*y*M)/(4*C) + (y - M)*(C*Mp - 2/sin2φ) - Mp);
+            φ -= dφ;
+        } while (abs(dφ) > ITERATION_TOLERANCE);
+        final double sinφ = sin(φ);
+        double λ = asin(x*tan(φ) * sqrt(1 - eccentricitySquared*(sinφ*sinφ))) / sinφ;
+        /*
+         * If y=0, then we got some 0/0 in above formula, either in calculation of φ or
+         * in calculation of λ (which itself uses φ, so a NaN in φ will propagate in λ).
+         * We test only after the loop because those cases should be rare, and we want a
+         * continuous behavior for values close to zero but not close enough for causing
+         * those divisions by zero.
+         */
+        if (!Double.isFinite(λ) && abs(y) <= ANGULAR_TOLERANCE && Double.isFinite(x)) {
+            λ = x;
+            φ = y;
+        }
+        dstPts[dstOff  ] = λ;
+        dstPts[dstOff+1] = φ;
+    }
+
+
+    /**
+     * Provides the transform equations for the spherical case of the Polyconic projection.
+     *
+     * @author  Simon Reynard (Geomatys)
+     * @author  Martin Desruisseaux (Geomatys)
+     * @version 1.0
+     * @since   1.0
+     * @module
+     */
+    static final class Spherical extends Polyconic {
+        /**
+         * For cross-version compatibility.
+         */
+        private static final long serialVersionUID = 8500881467002808593L;
+
+        /**
+         * Constructs a new map projection from the parameters of the given projection.
+         *
+         * @param  other  the other projection (usually ellipsoidal) from which to copy the parameters.
+         */
+        Spherical(final Polyconic other) {
+            super(other);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @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 sinφ = sin(φ);
+            final double cosφ = cos(φ);
+            final double cotφ = cosφ / sinφ;
+            if (Double.isInfinite(cotφ)) {                  // May happen if φ == 0.
+                if (dstPts != null) {
+                    dstPts[dstOff  ] = λ;
+                    dstPts[dstOff+1] = φ;
+                }
+                return derivate ? new Matrix2() : null;
+            }
+            final double E    = λ * sinφ;
+            final double sinE = sin(E);
+            final double cosE = cos(E);
+            if (dstPts != null) {
+                dstPts[dstOff  ] = sinE * cotφ;
+                dstPts[dstOff+1] = φ + cotφ * (1 - cosE);
+            }
+            if (!derivate) {
+                return null;
+            }
+            /*
+             * Derivation of:
+             *
+             *   x = sin(λ * sin(φ)) * cotφ
+             *   y = φ + cot(φ) * (1 - cos(λ * sin(φ)))
+             */
+            final double c2λ = cosφ*cosφ * λ;
+            return new Matrix2(
+                    cosφ * cosE,                                // ∂x/∂λ
+                    (c2λ*cosE - sinE/sinφ)/sinφ,                // ∂x/∂λ
+                    cosφ * sinE,                                // ∂y/∂λ
+                    (c2λ*sinE - (1 - cosE)/sinφ)/sinφ + 1);     // ∂y/∂φ
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        protected void inverseTransform(final double[] srcPts, final int srcOff,
+                                        final double[] dstPts, final int dstOff)
+                throws ProjectionException
+        {
+            final double x = srcPts[srcOff  ];
+            final double y = srcPts[srcOff+1];
+            double φ = y;                           // A = φ₀ + y/R         — Snyder 18-7 with φ₀=0 and R=1.
+            final double B = x*x + y*y;             // B = x²/R² + A²       — Snyder 18-8 with A=φ and R=1.
+            int i = MAXIMUM_ITERATIONS;
+            double dφ;
+            do {
+                if (--i < 0) {
+                    throw new ProjectionException(Resources.format(Resources.Keys.NoConvergence));
+                }
+                final double tanφ = tan(φ);
+                // Snyder 18-9 simplified with A=y and Ma=M.
+                dφ = (y*(φ*tanφ + 1) - φ - 0.5*(φ*φ + B) * tanφ) / ((φ - y) / tanφ - 1);
+                φ -= dφ;
+            } while (abs(dφ) > ITERATION_TOLERANCE);
+            double λ = asin(x*tan(φ)) / sin(φ);
+            /*
+             * If y=0, then we got some 0/0 in above formula, either in calculation of φ or
+             * in calculation of λ (which itself uses φ, so a NaN in φ will propagate in λ).
+             * We test only after the loop because those cases should be rare, and we want a
+             * continuous behavior for values close to zero but not close enough for causing
+             * those divisions by zero.
+             */
+            if (!Double.isFinite(λ) && abs(y) <= ANGULAR_TOLERANCE && Double.isFinite(x)) {
+                λ = x;
+                φ = y;
+            }
+            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 7868784..f1a2d3d 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
@@ -56,6 +56,7 @@ org.apache.sis.internal.referencing.provider.ObliqueMercatorTwoPoints
 org.apache.sis.internal.referencing.provider.ObliqueMercatorTwoPointsCenter
 org.apache.sis.internal.referencing.provider.ZonedTransverseMercator
 org.apache.sis.internal.referencing.provider.Sinusoidal
+org.apache.sis.internal.referencing.provider.Polyconic
 org.apache.sis.internal.referencing.provider.Mollweide
 org.apache.sis.internal.referencing.provider.NTv2
 org.apache.sis.internal.referencing.provider.NADCON
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 64e2d69..8888882 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
@@ -83,8 +83,6 @@ public final strictfp class ProvidersTest extends TestCase {
             PseudoMercator.class,
             RegionalMercator.class,
             MillerCylindrical.class,
-            Sinusoidal.class,
-            Mollweide.class,
             LambertConformal1SP.class,
             LambertConformal2SP.class,
             LambertConformalWest.class,
@@ -106,6 +104,9 @@ public final strictfp class ProvidersTest extends TestCase {
             ObliqueMercatorTwoPoints.class,
             ObliqueMercatorTwoPointsCenter.class,
             ZonedTransverseMercator.class,
+            Sinusoidal.class,
+            Polyconic.class,
+            Mollweide.class,
             NTv2.class,
             NADCON.class,
             FranceGeocentricInterpolation.class,
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java
index 1da9806..139f930 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java
@@ -111,8 +111,8 @@ public final strictfp class AlbersEqualAreaTest extends MapProjectionTestCase {
     @DependsOnMethod("testSphere")
     public void testEllipse() throws FactoryException, TransformException {
         createCompleteProjection(new org.apache.sis.internal.referencing.provider.AlbersEqualArea(),
-                6378206.4,  // Semi-major axis from Snyder table 15
-                6356583.8,  // Semi-minor axis
+                CLARKE_A,   // Semi-major axis from Snyder table 15
+                CLARKE_B,   // Semi-minor axis
                 0,          // Central meridian
                 0,          // Latitude of origin
                 29.5,       // Standard parallel 1 (from Snyder table 15)
@@ -168,8 +168,8 @@ public final strictfp class AlbersEqualAreaTest extends MapProjectionTestCase {
 
         // Spherical case
         createCompleteProjection(new org.apache.sis.internal.referencing.provider.AlbersEqualArea(),
-                6400000,    // Semi-major axis
-                6400000,    // Semi-minor axis
+                RADIUS,     // Semi-major axis
+                RADIUS,     // Semi-minor axis
                 0,          // Central meridian
                 0,          // Latitude of origin
                 0,          // Standard parallel 1
@@ -182,7 +182,7 @@ public final strictfp class AlbersEqualAreaTest extends MapProjectionTestCase {
 
         // Ellipsoidal case
         createCompleteProjection(new org.apache.sis.internal.referencing.provider.AlbersEqualArea(),
-                6378137,            // Semi-major axis
+                6378137,            // Semi-major axis (not WGS84 despite same values)
                 6356752.314140347,  // Semi-minor axis
                 0,                  // Central meridian
                 0,                  // Latitude of origin
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
index 8b7222e..614c3b9 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
@@ -40,20 +40,27 @@ import static org.junit.Assert.*;
  * Base class of map projection tests.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.6
  * @module
  */
 abstract strictfp class MapProjectionTestCase extends MathTransformTestCase {
     /**
-     * Semi-major axis length of WGS84 ellipsoid.
+     * Axis length of WGS84 ellipsoid.
      */
-    static final double WGS84_A = 6378137;
+    static final double WGS84_A = 6378137,
+                        WGS84_B = 6356752.314245179;
 
     /**
-     * Semi-minor axis length of WGS84 ellipsoid.
+     * Axis length of Clarke 1866 ellipsoid. This ellipsoid is used by Snyder examples.
      */
-    static final double WGS84_B = 6356752.314245179;
+    static final double CLARKE_A = 6378206.4,
+                        CLARKE_B = 6356583.8;
+
+    /**
+     * A radius for tests of spherical formulas.
+     */
+    static final double RADIUS = 6400000;
 
     /**
      * Tolerance level for comparing formulas on the unitary sphere or ellipsoid.
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
index 78c9c93..859967a 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
@@ -369,7 +369,7 @@ public final strictfp class ObliqueStereographicTest extends MapProjectionTestCa
     public void testPolarStereographic() throws FactoryException, TransformException {
         final OperationMethod op = new org.apache.sis.internal.referencing.provider.ObliqueStereographic();
         final ParameterValueGroup p = op.getParameters().createValue();
-        p.parameter("semi_major")                    .setValue(6378137);
+        p.parameter("semi_major")                    .setValue(WGS84_A);
         p.parameter("inverse_flattening")            .setValue(298.2572236);
         p.parameter("Latitude of natural origin")    .setValue(90);
         p.parameter("Scale factor at natural origin").setValue(0.994);
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/SinusoidalTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolyconicTest.java
similarity index 56%
copy from core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/SinusoidalTest.java
copy to core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolyconicTest.java
index a448db2..7ffe0d5 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/SinusoidalTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolyconicTest.java
@@ -16,42 +16,46 @@
  */
 package org.apache.sis.referencing.operation.projection;
 
-import org.opengis.referencing.operation.TransformException;
 import org.opengis.util.FactoryException;
+import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
-
 
 /**
- * Tests the {@link Sinusoidal} projection.
+ * Tests the {@link Polyconic} class.
  *
+ * @author  Simon Reynard (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
+ * @author  Rémi Maréchal (Geomatys)
  * @version 1.0
  * @since   1.0
  * @module
  */
 @DependsOn(MeridianArcTest.class)
-public final strictfp class SinusoidalTest extends MapProjectionTestCase {
+public final strictfp class PolyconicTest extends MapProjectionTestCase {
     /**
-     * Creates a new instance of {@link Sinusoidal} concatenated with the (de)normalization matrices.
+     * Creates a new instance of {@link Polyconic} concatenated with the (de)normalization matrices.
      * The new instance is stored in the inherited {@link #transform} field.
      *
-     * @param  ellipse  {@code false} for a sphere, or {@code true} for WGS84 ellipsoid.
+     * @param  ellipsoidal  {@code false} for a sphere, or {@code true} for WGS84 ellipsoid.
      */
-    private void createProjection(final boolean ellipse) throws FactoryException {
-        createCompleteProjection(new org.apache.sis.internal.referencing.provider.Sinusoidal(),
-                ellipse ? WGS84_A : 6400000,
-                ellipse ? WGS84_B : 6400000,
-                Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN);
+    private void createProjection(final boolean ellipsoidal) throws FactoryException {
+        createCompleteProjection(new org.apache.sis.internal.referencing.provider.Polyconic(),
+                ellipsoidal ? CLARKE_A : RADIUS,        // Semi-major axis (Clarke 1866)
+                ellipsoidal ? CLARKE_B : RADIUS,        // Semi-minor axis (Clarke 1866)
+                -96,                                    // Central meridian
+                 30,                                    // Latitude of origin
+                Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN);
         tolerance = Formulas.LINEAR_TOLERANCE;  // Not NORMALIZED_TOLERANCE since this is not a NormalizedProjection.
     }
 
     /**
-     * Tests the projection of a few points on a sphere.
+     * Tests the projection of a few points on a sphere. The first point in this test is provided
+     * by Snyder at page 304. The Snyder example gives intermediate values at different step,
+     * which may be verified by executing this code in the debugger.
      *
      * @throws FactoryException if an error occurred while creating the map projection.
      * @throws TransformException if an error occurred while projecting a point.
@@ -59,20 +63,28 @@ public final strictfp class SinusoidalTest extends MapProjectionTestCase {
     @Test
     public void testSpherical() throws FactoryException, TransformException {
         createProjection(false);
-        assertTrue(isInverseTransformSupported);
         verifyTransform(
             new double[] {                  // (λ,φ) coordinates in degrees to project.
-                  2,              1,
-                -75 - -90,      -50         // Snyder example is relative to λ₀ = 90°W.
+                -75, 40,                    // Snyder example is relative to λ₀ = 96°W.
+                -75,  0
             },
             new double[] {                  // Expected (x,y) results in metres.
-               223368.12,    111701.07,     // Values taken from PROJ.4.
-              1077000.98,  -5585053.61      // Values derived from Snyder page 365.
+                1780350.84,  1327706.12,    // Values derived from Snyder page 303 with R=6400000 metres.
+                2345722.51, -3351032.16
             });
     }
 
     /**
-     * Tests the projection of a few points on an ellipsoid.
+     * Tests the projection of a few points on an ellipsoid. The first point in this test is provided
+     * by Snyder at page 304. The Snyder example gives intermediate values at different step, which may
+     * be verified by executing this code in the debugger. In particular during inverse projection,
+     * values of φ should be as below during each iteration steps:
+     *
+     * <ol>
+     *   <li>0.6967280</li>
+     *   <li>0.6981286</li>
+     *   <li>0.6981317</li>
+     * </ol>
      *
      * @throws FactoryException if an error occurred while creating the map projection.
      * @throws TransformException if an error occurred while projecting a point.
@@ -80,15 +92,14 @@ public final strictfp class SinusoidalTest extends MapProjectionTestCase {
     @Test
     public void testEllipsoidal() throws FactoryException, TransformException {
         createProjection(true);
-        assertTrue(isInverseTransformSupported);
         verifyTransform(
             new double[] {                  // (λ,φ) coordinates in degrees to project.
-                  2,              1,
-                -75 - -90,      -50         // Snyder example is relative to λ₀ = 90°W.
+                -75, 40,                    // Snyder example is relative to λ₀ = 96°W.
+                -75,  0
             },
             new double[] {                  // Expected (x,y) results in metres.
-               222605.30,    110574.39,     // Values taken from PROJ.4.
-              1075436.30,  -5540847.04      // Snyder values modified for WGS84 (Δx ≈ 35m and Δy ≈ 219m).
+                1776774.54,  1319657.78,    // Values derived from Snyder page 304.
+                2337734.74, -3319933.30
             });
     }
 
@@ -103,11 +114,12 @@ public final strictfp class SinusoidalTest extends MapProjectionTestCase {
     @DependsOnMethod("testInverseDerivative")
     public void testDerivativeOnSphere() throws FactoryException, TransformException {
         createProjection(false);
-        final double delta = (100.0 / 60) / 1852;               // Approximatively 100 metres.
+        final double delta = (1.0 / 60) / 1852;                 // Approximatively 1 metre.
         derivativeDeltas = new double[] {delta, delta};
-        tolerance = 1E-6;                                       // More severe than Formulas.LINEAR_TOLERANCE.
-        verifyDerivative(15,  30);
-        verifyDerivative(10, -60);
+        tolerance = Formulas.LINEAR_TOLERANCE / 10;
+        verifyDerivative(-100,  3);
+        verifyDerivative( -56, 50);
+        verifyDerivative( -20, 47);
     }
 
     /**
@@ -121,10 +133,23 @@ public final strictfp class SinusoidalTest extends MapProjectionTestCase {
     @DependsOnMethod("testInverseDerivative")
     public void testDerivativeOnEllipsoid() throws FactoryException, TransformException {
         createProjection(true);
-        final double delta = (100.0 / 60) / 1852;               // Approximatively 100 metres.
+        final double delta = (1.0 / 60) / 1852;                 // Approximatively 1 metre.
         derivativeDeltas = new double[] {delta, delta};
-        tolerance = 1E-6;                                       // More severe than Formulas.LINEAR_TOLERANCE.
-        verifyDerivative(15,  30);
-        verifyDerivative(10, -60);
+        tolerance = Formulas.LINEAR_TOLERANCE / 10;
+        verifyDerivative(-100,  3);
+        verifyDerivative( -56, 50);
+        verifyDerivative( -20, 47);
+    }
+
+    /**
+     * Runs the test defined in the GeoAPI-conformance module.
+     *
+     * @throws FactoryException   if the transform can not be created.
+     * @throws TransformException if an error occurred while projecting a point.
+     */
+    @Test
+    @DependsOnMethod("testEllipsoidal")
+    public void runGeoapiTest() throws FactoryException, TransformException {
+        createGeoApiTest(new org.apache.sis.internal.referencing.provider.Polyconic()).testPolyconic();
     }
 }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/SinusoidalTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/SinusoidalTest.java
index a448db2..2ce6ffc 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/SinusoidalTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/SinusoidalTest.java
@@ -23,8 +23,6 @@ import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
-
 
 /**
  * Tests the {@link Sinusoidal} projection.
@@ -40,18 +38,21 @@ public final strictfp class SinusoidalTest extends MapProjectionTestCase {
      * Creates a new instance of {@link Sinusoidal} concatenated with the (de)normalization matrices.
      * The new instance is stored in the inherited {@link #transform} field.
      *
-     * @param  ellipse  {@code false} for a sphere, or {@code true} for WGS84 ellipsoid.
+     * @param  ellipsoidal  {@code false} for a sphere, or {@code true} for WGS84 ellipsoid.
      */
-    private void createProjection(final boolean ellipse) throws FactoryException {
+    private void createProjection(final boolean ellipsoidal) throws FactoryException {
         createCompleteProjection(new org.apache.sis.internal.referencing.provider.Sinusoidal(),
-                ellipse ? WGS84_A : 6400000,
-                ellipse ? WGS84_B : 6400000,
-                Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN);
+                ellipsoidal ? CLARKE_A : RADIUS,        // Semi-major axis (Clarke 1866)
+                ellipsoidal ? CLARKE_B : RADIUS,        // Semi-minor axis (Clarke 1866)
+                -90,                                    // Central meridian
+                Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN);
         tolerance = Formulas.LINEAR_TOLERANCE;  // Not NORMALIZED_TOLERANCE since this is not a NormalizedProjection.
     }
 
     /**
-     * Tests the projection of a few points on a sphere.
+     * Tests the projection of a few points on a sphere. The first point in this test is provided
+     * by Snyder at page 365. The Snyder example gives intermediate values at different step,
+     * which may be verified by executing this code in the debugger.
      *
      * @throws FactoryException if an error occurred while creating the map projection.
      * @throws TransformException if an error occurred while projecting a point.
@@ -59,20 +60,21 @@ public final strictfp class SinusoidalTest extends MapProjectionTestCase {
     @Test
     public void testSpherical() throws FactoryException, TransformException {
         createProjection(false);
-        assertTrue(isInverseTransformSupported);
         verifyTransform(
             new double[] {                  // (λ,φ) coordinates in degrees to project.
-                  2,              1,
-                -75 - -90,      -50         // Snyder example is relative to λ₀ = 90°W.
+                -75, -50,                   // Snyder example is relative to λ₀ = 90°W.
+                -88,   1
             },
             new double[] {                  // Expected (x,y) results in metres.
-               223368.12,    111701.07,     // Values taken from PROJ.4.
-              1077000.98,  -5585053.61      // Values derived from Snyder page 365.
+              1077000.98,  -5585053.61,     // Values derived from Snyder page 365.
+               223368.12,    111701.07      // Values taken from PROJ.4.
             });
     }
 
     /**
-     * Tests the projection of a few points on an ellipsoid.
+     * Tests the projection of a few points on an ellipsoid. The first point in this test is provided
+     * by Snyder at page 366. The Snyder example gives intermediate values at different step, which
+     * may be verified by executing this code in the debugger.
      *
      * @throws FactoryException if an error occurred while creating the map projection.
      * @throws TransformException if an error occurred while projecting a point.
@@ -80,15 +82,14 @@ public final strictfp class SinusoidalTest extends MapProjectionTestCase {
     @Test
     public void testEllipsoidal() throws FactoryException, TransformException {
         createProjection(true);
-        assertTrue(isInverseTransformSupported);
         verifyTransform(
             new double[] {                  // (λ,φ) coordinates in degrees to project.
-                  2,              1,
-                -75 - -90,      -50         // Snyder example is relative to λ₀ = 90°W.
+                -75, -50,                   // Snyder example is relative to λ₀ = 90°W.
+                -88,   1,
             },
             new double[] {                  // Expected (x,y) results in metres.
-               222605.30,    110574.39,     // Values taken from PROJ.4.
-              1075436.30,  -5540847.04      // Snyder values modified for WGS84 (Δx ≈ 35m and Δy ≈ 219m).
+              1075471.54,  -5540628.03,     // Values from Snyder page 366.
+               222607.72,    110567.32      // Values taken from PROJ.4 and modified for Clarke 1866.
             });
     }
 
@@ -103,11 +104,11 @@ public final strictfp class SinusoidalTest extends MapProjectionTestCase {
     @DependsOnMethod("testInverseDerivative")
     public void testDerivativeOnSphere() throws FactoryException, TransformException {
         createProjection(false);
-        final double delta = (100.0 / 60) / 1852;               // Approximatively 100 metres.
+        final double delta = (1.0 / 60) / 1852;                 // Approximatively 1 metre.
         derivativeDeltas = new double[] {delta, delta};
-        tolerance = 1E-6;                                       // More severe than Formulas.LINEAR_TOLERANCE.
-        verifyDerivative(15,  30);
-        verifyDerivative(10, -60);
+        tolerance = Formulas.LINEAR_TOLERANCE / 10000;
+        verifyDerivative(105,  30);
+        verifyDerivative(100, -60);
     }
 
     /**
@@ -121,10 +122,10 @@ public final strictfp class SinusoidalTest extends MapProjectionTestCase {
     @DependsOnMethod("testInverseDerivative")
     public void testDerivativeOnEllipsoid() throws FactoryException, TransformException {
         createProjection(true);
-        final double delta = (100.0 / 60) / 1852;               // Approximatively 100 metres.
+        final double delta = (1.0 / 60) / 1852;                 // Approximatively 1 metre.
         derivativeDeltas = new double[] {delta, delta};
-        tolerance = 1E-6;                                       // More severe than Formulas.LINEAR_TOLERANCE.
-        verifyDerivative(15,  30);
-        verifyDerivative(10, -60);
+        tolerance = Formulas.LINEAR_TOLERANCE / 10000;
+        verifyDerivative(105,  30);
+        verifyDerivative(100, -60);
     }
 }
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 85d9c85..6aed0e3 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
@@ -178,6 +178,7 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.operation.projection.AlbersEqualAreaTest.class,
     org.apache.sis.referencing.operation.projection.MeridianArcTest.class,
     org.apache.sis.referencing.operation.projection.SinusoidalTest.class,
+    org.apache.sis.referencing.operation.projection.PolyconicTest.class,
     org.apache.sis.referencing.operation.projection.MollweideTest.class,
 
     // Coordinate operation and derived Coordinate Reference Systems (cyclic dependency).
diff --git a/storage/sis-gdal/src/test/java/org/apache/sis/storage/gdal/TransformTest.java b/storage/sis-gdal/src/test/java/org/apache/sis/storage/gdal/TransformTest.java
index 78c97d8..703b5a6 100644
--- a/storage/sis-gdal/src/test/java/org/apache/sis/storage/gdal/TransformTest.java
+++ b/storage/sis-gdal/src/test/java/org/apache/sis/storage/gdal/TransformTest.java
@@ -34,7 +34,7 @@ import static org.apache.sis.test.Assert.*;
  * Tests various map projections using {@literal Proj.4} wrappers.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.8
  * @module
  */
@@ -96,7 +96,6 @@ public class TransformTest extends ParameterizedTransformTest {
                     "Mercator (variant C)",                     // Need to verify if Proj4 handles easting/northing correctly.
                     "Polar Stereographic (variant C)",          // Need to verify if Proj4 handles northing correctly.
                     "Popular Visualisation Pseudo Mercator",
-                    "Polyconic",                                // No OperationMethod in SIS yet.
                     "Transverse Mercator (South Orientated)"), FAILURES);
             FAILURES.clear();
         }


Mime
View raw message