This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit fc7eca86b224889013a1f2d368e6ba87300c376a Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Fri Apr 26 11:38:49 2024 +0200 Initial version of Equidistant Cylindrical (EPSG:1028) map projection with formulas as published in EPSG guidance notes. https://issues.apache.org/jira/browse/SIS-233 --- .../main/module-info.java | 1 + .../operation/projection/CylindricalEqualArea.java | 4 +- .../projection/EquidistantCylindrical.java | 194 +++++++++++++++++++++ .../operation/projection/NormalizedProjection.java | 5 +- .../operation/provider/EquidistantCylindrical.java | 81 +++++++++ .../operation/provider/Equirectangular.java | 24 ++- .../operation/transform/MathTransformProvider.java | 2 +- .../apache/sis/referencing/ClenshawSummation.java | 11 +- .../operation/projection/CassiniSoldnerTest.java | 6 +- .../projection/EquidistantCylindricalTest.java | 90 ++++++++++ .../operation/provider/ProvidersTest.java | 1 + geoapi/snapshot | 2 +- 12 files changed, 407 insertions(+), 14 deletions(-) diff --git a/endorsed/src/org.apache.sis.referencing/main/module-info.java b/endorsed/src/org.apache.sis.referencing/main/module-info.java index 70b0b34ee3..d79c190aac 100644 --- a/endorsed/src/org.apache.sis.referencing/main/module-info.java +++ b/endorsed/src/org.apache.sis.referencing/main/module-info.java @@ -127,6 +127,7 @@ module org.apache.sis.referencing { org.apache.sis.referencing.operation.provider.Orthographic, org.apache.sis.referencing.operation.provider.ModifiedAzimuthalEquidistant, org.apache.sis.referencing.operation.provider.AzimuthalEquidistantSpherical, + org.apache.sis.referencing.operation.provider.EquidistantCylindrical, org.apache.sis.referencing.operation.provider.ZonedTransverseMercator, org.apache.sis.referencing.operation.provider.Sinusoidal, org.apache.sis.referencing.operation.provider.PseudoSinusoidal, diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java index e27c23a72f..24cbefaf78 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java @@ -122,8 +122,8 @@ public class CylindricalEqualArea extends AuthalicConversion { /** * Creates a Cylindrical Equal Area projection from the given parameters. * - * @param method Description of the projection parameters. - * @param parameters The parameter values of the projection to create. + * @param method description of the projection parameters. + * @param parameters the parameter values of the projection to create. */ public CylindricalEqualArea(final OperationMethod method, final Parameters parameters) { this(initializer(method, parameters)); diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/EquidistantCylindrical.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/EquidistantCylindrical.java new file mode 100644 index 0000000000..de2edd02df --- /dev/null +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/EquidistantCylindrical.java @@ -0,0 +1,194 @@ +/* + * 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 static java.lang.Math.sin; +import static java.lang.Math.cos; +import static java.lang.Math.toRadians; +import org.opengis.util.FactoryException; +import org.opengis.parameter.ParameterDescriptor; +import org.opengis.referencing.operation.Matrix; +import org.opengis.referencing.operation.MathTransform; +import org.opengis.referencing.operation.OperationMethod; +import org.apache.sis.util.Workaround; +import org.apache.sis.util.privy.DoubleDouble; +import org.apache.sis.parameter.Parameters; +import org.apache.sis.referencing.operation.matrix.Matrix2; +import org.apache.sis.referencing.operation.matrix.MatrixSIS; +import org.apache.sis.referencing.operation.provider.Equirectangular; +import org.apache.sis.referencing.operation.transform.ContextualParameters; +import org.apache.sis.referencing.operation.transform.MathTransformProvider; + + +/** + * <cite>Equidistant Cylindrical</cite> projection (EPSG code 1028). + * This class implements only the ellipsoidal case. There is no specialization for the spherical case, + * because the latter can be implemented by an affine transform instead of {@code NormalizedProjection}. + * + * <h4>Limitations</h4> + * The trigonometric series used in this implementation is adequate for a flattening of 1/290 or less. + * The series has not yet been optimized with Clenshaw summation. + * + * @author Martin Desruisseaux (Geomatys) + */ +public class EquidistantCylindrical extends NormalizedProjection { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = 6598912212024442670L; + + /** + * Coefficients for the forward (f) and inverse (i) projection. + * This is used in a trigonometric series with multiple angles. + * + * <h4>Missed optimization</h4> + * We should replace the multiple angles by power polynomials using the Clenshaw summation algorithm. + * However the {@code org.apache.sis.referencing.ClenshawSummation} class (in test packages) that we + * used for this purpose in other map projections is limited to 6 terms, and we have 7 terms here. + */ + private final double cf0, cf2, cf4, cf6, cf8, cf10, cf12, cf14, + ci2, ci4, ci6, ci8, ci10, ci12, ci14; + + /** + * Creates an Equidistant Cylindrical projection from the given parameters. + * + * @param method description of the projection parameters. + * @param parameters the parameter values of the projection to create. + */ + public EquidistantCylindrical(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"). + */ + @SuppressWarnings("fallthrough") + @Workaround(library="JDK", version="1.7") + private static Initializer initializer(final OperationMethod method, final Parameters parameters) { + final EnumMap<ParameterRole, ParameterDescriptor<Double>> roles = new EnumMap<>(ParameterRole.class); + roles.put(ParameterRole.FALSE_EASTING, Equirectangular.FALSE_EASTING); + roles.put(ParameterRole.FALSE_NORTHING, Equirectangular.FALSE_NORTHING); + roles.put(ParameterRole.CENTRAL_MERIDIAN, Equirectangular.LONGITUDE_OF_ORIGIN); + return new Initializer(method, parameters, roles, null); + } + + /** + * Work around for RFE #4093999 in Sun's bug database + * ("Relax constraint on placement of this()/super() call in constructors"). + */ + @Workaround(library="JDK", version="1.7") + private EquidistantCylindrical(final Initializer initializer) { + super(initializer, null); + final double φ1 = toRadians(initializer.getAndStore(Equirectangular.STANDARD_PARALLEL)); + final DoubleDouble sx = initializer.rν2(sin(φ1)).sqrt().multiply(cos(φ1), false); + final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION); + denormalize.convertBefore(0, sx, null); + + // Coefficients for the forward projection. + final double e2 = eccentricitySquared; + final double e4 = e2*e2; + final double e6 = e2*e4; + final double e8 = e4*e4; + cf0 = 1 - e2*(1./4 + e2*( 3./64 + e2*( 5./256 + e2*(175./16384 + e2*( 441./65536 + e2*( 4851./1048576 + e2*( 14157./4194304 ))))))); + cf2 = - e2*(3./8 + e2*( 3./32 + e2*(45./1024 + e2*(105./4096 + e2*(2205./131072 + e2*( 6237./524288 + e2*(297297./33554432))))))); + cf4 = e4*(15./256 + e2*(45./1024 + e2*(525./16384 + e2*(1575./65536 + e2*(155925./8388608 + e2*(495495./33554432)))))); + cf6 = - e6*(35./3072 + e2*(175./12288 + e2*(3675./262144 + e2*( 13475./1048576 + e2*(385385./33554432))))); + cf8 = + e8*(315./131072 + e2*(2205./524288 + e2*( 43659./8388608 + e2*(189189./33554432)))); + cf10 = - (e4*e6)*( 693./1310720 + e2*( 6237./5242880 + e2*(297297./167772160))); + cf12 = (e6*e6)*( 1001./8388608 + e2*( 11011./33554432)); + cf14 = - (e6*e8)*( 6435./234881024); + + // Coefficients for the inverse projection. + final double n = initializer.axisLengthRatio().ratio_1m_1p().doubleValue(); + final double n2 = n*n; + final double n3 = n*n2; + final double n4 = n2*n2; + ci2 = n*(3./2 + n2*(-27./32 + n2*(269./512 + n2*( -6607./24576)))); + ci4 = n2*( 21./16 + n2*( -55./32 + n2*( 6759./4096))); + ci6 = n3*(151./96 + n2*(-417./128 + n2*( 87963./20480))); + ci8 = n4*(1097./512 + n2*( -15543./2560)); + ci10 = (n3*n2)*(8011./2560 + n2*( -69119./6144)); + ci12 = (n3*n3)*( 293393./61440); + ci14 = (n3*n4)*(6845701./860160); + } + + /** + * Returns the sequence of <i>normalization</i> → {@code this} → <i>denormalization</i> 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>. + * If the ellipsoid is spherical, this map projection is replaced by an affine transform. + * + * @param parameters parameters and 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 MathTransformProvider.Context parameters) throws FactoryException { + if (eccentricity == 0) { + return Equirectangular.provider().createMathTransform(parameters); + } + return completeWithWraparound(parameters); + } + + /** + * Projects the specified (λ,φ) coordinates (units in radians) and stores the result in {@code dstPts}. + * In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}. + * The results must be multiplied by the denormalization matrix before to get linear distances. + * + * @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 cannot 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+1]; + if (dstPts != null) { + dstPts[dstOff] = srcPts[srcOff]; + dstPts[dstOff+1] = cf14*sin(14*φ) + cf12*sin(12*φ) + cf10*sin(10*φ) + cf8*sin(8*φ) + + cf6*sin( 6*φ) + cf4*sin( 4*φ) + cf2*sin( 2*φ) + cf0*φ; + } + if (!derivate) { + return null; + } + final var derivative = new Matrix2(); + derivative.m11 = cf14*cos(14*φ)*14 + cf12*cos(12*φ)*12 + cf10*cos(10*φ)*10 + cf8*cos(8*φ)*8 + + cf6*cos( 6*φ)*6 + cf4*cos( 4*φ)*4 + cf2*cos( 2*φ)*2 + cf0; + return derivative; + } + + /** + * Converts the specified (<var>x</var>,<var>y</var>) coordinates + * and stores the result in {@code dstPts} (angles in radians). + * + * @throws ProjectionException if the point cannot be converted. + */ + @Override + protected void inverseTransform(final double[] srcPts, final int srcOff, + final double[] dstPts, final int dstOff) + throws ProjectionException + { + final double μ = srcPts[srcOff+1] / cf0; + dstPts[dstOff] = srcPts[srcOff]; + dstPts[dstOff+1] = ci14*sin(14*μ) + ci12*sin(12*μ) + ci10*sin(10*μ) + ci8*sin(8*μ) + + ci6*sin( 6*μ) + ci4*sin( 4*μ) + ci2*sin( 2*μ) + μ; + } +} diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/NormalizedProjection.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/NormalizedProjection.java index 8b22d9f146..1226a486e1 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/NormalizedProjection.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/NormalizedProjection.java @@ -718,11 +718,12 @@ public abstract class NormalizedProjection extends AbstractMathTransform2D imple * If this assumption is not applicable to a particular subclass, then it is implementer responsibility to check * the range. * - * @param srcPts the array containing the source point coordinates, as (<var>longitude</var>, <var>latitude</var>) - * angles in <strong>radians</strong>. + * @param srcPts the array containing the source point coordinates, + * as (<var>longitude</var>, <var>latitude</var>) angles in <strong>radians</strong>. * @param srcOff the offset of the single coordinate tuple to be converted in the source array. * @param dstPts the array into which the converted coordinates is returned (may be the same as {@code srcPts}). * Coordinates will be expressed in a dimensionless unit, as a linear distance on a unit sphere or ellipse. + * This array may be {@code null} if the caller is interested only in the derivative. * @param dstOff the offset of the location of the converted coordinates that is stored in the destination array. * @param derivate {@code true} for computing the derivative, or {@code false} if not needed. * @return the matrix of the projection derivative at the given source position, diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/EquidistantCylindrical.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/EquidistantCylindrical.java new file mode 100644 index 0000000000..c03e4859c3 --- /dev/null +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/EquidistantCylindrical.java @@ -0,0 +1,81 @@ +/* + * 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.provider; + +import jakarta.xml.bind.annotation.XmlTransient; +import org.opengis.parameter.ParameterDescriptorGroup; +import org.apache.sis.parameter.Parameters; +import org.apache.sis.parameter.ParameterBuilder; +import org.apache.sis.metadata.iso.citation.Citations; +import org.apache.sis.referencing.operation.projection.NormalizedProjection; + + +/** + * The provider for <q>Equidistant Cylindrical</q> projection + * (EPSG:1028, <span class="deprecated">EPSG:9842</span>). + * + * <h2>Note</h2> + * EPSG:1028 is the current codes, while EPSG:9842 is a deprecated code. + * The new and deprecated definitions differ only by their parameters. In the Apache SIS implementation, + * both current and legacy definitions are known, but the legacy names are marked as deprecated. + * + * @author Martin Desruisseaux (Geomatys) + */ +@XmlTransient +public final class EquidistantCylindrical extends MapProjection { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = -1180656445349342258L; + + /** + * The group of all parameters expected by this coordinate operation. + */ + private static final ParameterDescriptorGroup PARAMETERS; + static { + final ParameterBuilder builder = builder(); + PARAMETERS = addIdentifierAndLegacy(builder, "1028", "9842") // 9842 uses deprecated parameter names. + .addName( "Equidistant Cylindrical") + .addName(Citations.ESRI, "Equidistant_Cylindrical") + .addName(Citations.GEOTIFF, "CT_Equirectangular") + .addName(Citations.PROJ4, "eqc") + .addIdentifier(Citations.GEOTIFF, "17") + .createGroupForMapProjection( + Equirectangular.STANDARD_PARALLEL, + Equirectangular.LATITUDE_OF_ORIGIN, // Not formally an Equidistant Cylindrical parameter. + Equirectangular.LONGITUDE_OF_ORIGIN, + Equirectangular.FALSE_EASTING, + Equirectangular.FALSE_NORTHING); + } + + /** + * Constructs a new provider. + */ + public EquidistantCylindrical() { + super(PARAMETERS); + } + + /** + * Creates a map projection on an ellipsoid having a semi-major axis length of 1. + * + * @return the map projection created from the given parameter values. + */ + @Override + protected NormalizedProjection createProjection(final Parameters parameters) { + return new org.apache.sis.referencing.operation.projection.EquidistantCylindrical(this, parameters); + } +} diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/Equirectangular.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/Equirectangular.java index e0b023c68f..42d25915da 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/Equirectangular.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/Equirectangular.java @@ -248,14 +248,11 @@ public final class Equirectangular extends AbstractProvider { // Do not declare the ESRI "Equidistant_Cylindrical" projection name below, // for avoiding confusion with EPSG "Equidistant Cylindrical" ellipsoidal projection. - PARAMETERS = addIdentifierAndLegacy(builder, "1029", "9823") // 9823 uses deprecated parameter names + PARAMETERS = addIdentifierAndLegacy(builder, "1029", "9823") // 9823 uses deprecated parameter names. .addName( NAME) .addName( "Plate Carrée") // Not formally defined by EPSG, but cited in documentation. .addName(Citations.OGC, "Equirectangular") .addName(Citations.ESRI, "Plate_Carree") - .addName(Citations.GEOTIFF, "CT_Equirectangular") - .addName(Citations.PROJ4, "eqc") - .addIdentifier(Citations.GEOTIFF, "17") .createGroupForMapProjection( STANDARD_PARALLEL, LATITUDE_OF_ORIGIN, // Not formally an Equirectangular parameter. @@ -264,10 +261,29 @@ public final class Equirectangular extends AbstractProvider { FALSE_NORTHING); } + /** + * The canonical instance of this map projection. + * + * @see #provider() + */ + private static final Equirectangular INSTANCE = new Equirectangular(); + + /** + * Returns the canonical instance of this map projection. + * This method is invoked by {@link java.util.ServiceLoader} using reflection. + * + * @return the canonical instance of this map projection. + */ + public static Equirectangular provider() { + return INSTANCE; + } + /** * Constructs a new provider. * * @see MapProjection#MapProjection(Class, ParameterDescriptorGroup) + * + * @todo Make this constructor private after we stop class-path support. */ public Equirectangular() { super(Conversion.class, PARAMETERS, diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/MathTransformProvider.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/MathTransformProvider.java index a215ab8718..2b4a1d69a9 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/MathTransformProvider.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/MathTransformProvider.java @@ -122,7 +122,7 @@ public interface MathTransformProvider { { return createMathTransform(new MathTransformProvider.Context() { @Override public MathTransformFactory getFactory() { - return (factory != null) ? factory : DefaultMathTransformFactory.provider(); + return (factory != null) ? factory : Context.super.getFactory(); } @Override public ParameterValueGroup getCompletedParameters() { return parameters; diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/ClenshawSummation.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/ClenshawSummation.java index 6a40477726..c50951578b 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/ClenshawSummation.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/ClenshawSummation.java @@ -55,7 +55,15 @@ import org.apache.sis.pending.jdk.JDK21; * <a href="https://svn.apache.org/repos/asf/sis/analysis/Map%20projection%20formulas.ods">Subversion</a>. * This class is used for more complex formulas where the use of spreadsheet become too difficult. * + * <h2>Limitations</h2> + * Current implementation can handle a maximum of 6 terms in the trigonometric series (see {@link #compute()}). + * This limit is too short for {@link org.apache.sis.referencing.operation.projection.EquidistantCylindrical}. + * It would be possible to generalize using an iterative algorithm. Given that {@code EquidistantCylindrical} + * is used less often than Mercator or Lambert projections, we have not done this optimization yet. + * * @author Martin Desruisseaux (Geomatys) + * + * @see <a href="https://issues.apache.org/jira/browse/SIS-465">SIS-465</a> */ public final class ClenshawSummation { /** @@ -339,7 +347,8 @@ public final class ClenshawSummation { /** * Performs the Clenshaw summation. Current implementation uses hard-coded coefficients for 6 terms. - * See Karney (2010) equation 59 if generalization to an arbitrary number of coefficients is desired. + * See Charles F. F. Karney, Geodesics on an ellipsoid of revolution (2011) equation 59 + * if generalization to an arbitrary number of coefficients is desired. * * @see <a href="https://issues.apache.org/jira/browse/SIS-465">SIS-465</a> */ diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/projection/CassiniSoldnerTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/projection/CassiniSoldnerTest.java index c9af252c22..9a89d6076c 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/projection/CassiniSoldnerTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/projection/CassiniSoldnerTest.java @@ -86,7 +86,7 @@ public final class CassiniSoldnerTest extends MapProjectionTestCase { * Fix φ=45°, which implies tan(φ)=1. * Test using the CassiniSoldner spherical equation. */ - final DirectPosition2D point = new DirectPosition2D(); + final var point = new DirectPosition2D(); final double domain = toRadians(5); final double step = domain / 20; for (double λ = -domain; λ <= domain; λ += step) { @@ -122,7 +122,7 @@ public final class CassiniSoldnerTest extends MapProjectionTestCase { final double λ = -62; final double φ = 10; - final DirectPosition2D p = new DirectPosition2D(λ, φ); + final var p = new DirectPosition2D(λ, φ); assertSame(p, transform.transform(p, p)); assertEquals(66644.94, p.x, 0.005); assertEquals(82536.22, p.y, 0.005); @@ -155,7 +155,7 @@ public final class CassiniSoldnerTest extends MapProjectionTestCase { final double λ = 179 + (59 + 39.6115/60)/60; // 179°59′39.6115″E final double φ = -(16 + (50 + 29.2435/60)/60); // 16°50′29.2435″S - final DirectPosition2D p = new DirectPosition2D(λ, φ); + final var p = new DirectPosition2D(λ, φ); assertSame(p, transform.transform(p, p)); assertEquals(16015.2890, p.x, 0.00005); assertEquals(13369.6601, p.y, 0.00005); diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/projection/EquidistantCylindricalTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/projection/EquidistantCylindricalTest.java new file mode 100644 index 0000000000..cf14b0a4d0 --- /dev/null +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/projection/EquidistantCylindricalTest.java @@ -0,0 +1,90 @@ +/* + * 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.util.FactoryException; +import org.opengis.referencing.operation.TransformException; +import org.apache.sis.parameter.Parameters; +import org.apache.sis.geometry.DirectPosition2D; +import org.apache.sis.referencing.privy.Formulas; +import org.apache.sis.referencing.operation.provider.MapProjection; + +// Test dependencies +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + + +/** + * Tests the {@link EquidistantCylindrical} projection. + * + * @author Martin Desruisseaux (Geomatys) + */ +public final class EquidistantCylindricalTest extends MapProjectionTestCase { + /** + * Creates a new test case. + */ + public EquidistantCylindricalTest() { + } + + /** + * Returns the provider for the "Equidistant Cylindrical" projection. + */ + private static MapProjection provider() { + return new org.apache.sis.referencing.operation.provider.EquidistantCylindrical(); + } + + /** + * Tests the point given in EPSG example. + * This is the same test as {@link #runGeoapiTest()} but is repeated here for easier debugging. + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + */ + @Test + public void testSinglePoint() throws FactoryException, TransformException { + final MapProjection provider = provider(); + final Parameters pg = Parameters.castOrWrap(provider.getParameters().createValue()); + pg.parameter("semi-major").setValue(WGS84_A); + pg.parameter("semi-minor").setValue(WGS84_B); + transform = provider.createMathTransform(null, pg); + + final double λ = 10; + final double φ = 55; + final var p = new DirectPosition2D(λ, φ); + assertSame(p, transform.transform(p, p)); + assertEquals(1113194.91, p.x, 0.005); + assertEquals(6097230.31, p.y, 0.005); + + assertSame(p, transform.inverse().transform(p, p)); + assertEquals(λ, p.x, Formulas.ANGULAR_TOLERANCE); + assertEquals(φ, p.y, Formulas.ANGULAR_TOLERANCE); + } + + /** + * Tests the <q>Equidistant Cylindrical</q> (EPSG:1028) projection. + * 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#testEquidistantCylindrical() + */ + @Test + public void runGeoapiTest() throws FactoryException, TransformException { + createGeoApiTest(provider()).testEquidistantCylindrical(); + } +} diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/ProvidersTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/ProvidersTest.java index aedf86cd9a..72e3e25d60 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/ProvidersTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/ProvidersTest.java @@ -106,6 +106,7 @@ public final class ProvidersTest extends TestCase { Orthographic.class, ModifiedAzimuthalEquidistant.class, AzimuthalEquidistantSpherical.class, + EquidistantCylindrical.class, ZonedTransverseMercator.class, SatelliteTracking.class, Sinusoidal.class, diff --git a/geoapi/snapshot b/geoapi/snapshot index 42382222dc..41a6799cb2 160000 --- a/geoapi/snapshot +++ b/geoapi/snapshot @@ -1 +1 @@ -Subproject commit 42382222dc30ef4158fb58cc96e1a517d2c44a6b +Subproject commit 41a6799cb2940149f5f034db64365241198da439