blob: 40953a450ef7923963598b5b55423d3aeb6c8d75 [file] [log] [blame]
/*
* 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.Random;
import org.apache.sis.parameter.Parameters;
import org.apache.sis.internal.referencing.provider.LambertCylindricalEqualArea;
import org.apache.sis.referencing.operation.DefaultOperationMethod;
import org.apache.sis.internal.util.Constants;
import org.apache.sis.test.TestUtilities;
import org.apache.sis.test.DependsOn;
import org.junit.Test;
import static java.lang.StrictMath.*;
import static org.apache.sis.math.MathFunctions.atanh;
import static org.junit.Assert.assertEquals;
/**
* Tests {@link EqualAreaProjection}.
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.0
* @since 1.0
* @module
*/
@DependsOn(NormalizedProjectionTest.class)
public final strictfp class EqualAreaProjectionTest extends MapProjectionTestCase {
/**
* Creates the projection to be tested.
*
* @param ellipsoidal {@code false} for a sphere, or {@code true} for WGS84 ellipsoid.
* @return a test instance of the projection.
*/
private EqualAreaProjection create(final boolean ellipsoidal) {
final DefaultOperationMethod provider = new LambertCylindricalEqualArea();
final CylindricalEqualArea projection = new CylindricalEqualArea(provider, parameters(provider, ellipsoidal));
tolerance = NormalizedProjection.ANGULAR_TOLERANCE; // = linear tolerance on a sphere of radius 1.
return projection;
}
/**
* Computes φ using equation given in EPSG guidance notes, which is also from Snyder book.
* We use this equation as a reference for testing validity of other forms.
*
* @param y in the cylindrical case, this is northing on the normalized ellipsoid.
* @return the latitude in radians.
*/
private static double reference(final EqualAreaProjection projection, final double y) {
final double e = projection.eccentricity;
final double e2 = projection.eccentricitySquared;
final double e4 = e2 * e2;
final double e6 = e2 * e4;
final double c2β = 517./5040 * e6 + 31./180 * e4 + 1./3 * e2;
final double c4β = 251./3780 * e6 + 23./360 * e4;
final double c6β = 761./45360 * e6;
final double qmp = (1/(1 - e*e) + atanh(e)/e);
final double sinβ = y / qmp;
final double β = asin(sinβ);
return c6β * sin(6*β)
+ c4β * sin(4*β)
+ c2β * sin(2*β)
+ β; // Snyder 3-18
}
/**
* Compares {@link EqualAreaProjection#φ(double)} with formula taken as references.
*
* @throws ProjectionException if the function does not converge.
*/
@Test
public void compareWithReference() throws ProjectionException {
final EqualAreaProjection projection = create(true);
final Random random = TestUtilities.createRandomNumberGenerator();
for (int i=0; i<100; i++) {
final double y = random.nextDouble() * 3 - 1.5;
final double reference = reference(projection, y);
final double actual = projection.φ(y);
assertEquals(reference, actual, NormalizedProjection.ITERATION_TOLERANCE);
}
}
/**
* Searches a value for {@link EqualAreaProjection#ECCENTRICITY_THRESHOLD}.
* This method is not part of test suite. Steps to enable:
*
* <ol>
* <li>In {@link EqualAreaProjection#φ(double)} method, for {@code useIterations} to {@code false}.</li>
* <li>Add a {@link Test} annotation on this method.
* </ol>
*
* @throws ProjectionException if {@link EqualAreaProjection#φ(double)} did not converge.
*/
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public void searchThreshold() throws ProjectionException {
tolerance = NormalizedProjection.ANGULAR_TOLERANCE;
final DefaultOperationMethod provider = new LambertCylindricalEqualArea();
final Parameters parameters = parameters(provider, true);
for (double e = 0.05; e <= 0.2; e += 0.001) {
final double a = parameters.parameter(Constants.SEMI_MAJOR).doubleValue();
parameters.parameter(Constants.SEMI_MINOR).setValue(a * sqrt(1 - e*e));
final CylindricalEqualArea projection = new CylindricalEqualArea(provider, parameters);
for (double y = -1.25; y <= 1.25; y += 0.01) {
final double reference = reference(projection, y);
final double actual = projection.φ(y);
if (abs(actual - reference) > NormalizedProjection.ANGULAR_TOLERANCE) {
System.out.println("Error exceeds tolerance threshold at eccentricity " + e);
return;
}
}
}
}
}