/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2004-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.referencing;
import java.awt.Shape;
import java.awt.geom.IllegalPathStateException;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import javax.measure.unit.SI;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.operation.TransformException;
import org.opengis.geometry.DirectPosition;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.referencing.cs.DefaultEllipsoidalCS;
import org.geotools.referencing.cs.DefaultCoordinateSystemAxis;
import org.geotools.referencing.datum.DefaultEllipsoid;
import org.geotools.referencing.datum.DefaultGeodeticDatum;
import org.junit.*;
import static org.junit.Assert.*;
/**
* Tests the geodetic calculator.
*
* @source $URL$
* @version $Id$
*/
public final class GeodeticCalculatorTest {
/**
* Tests some trivial azimuth directions.
*/
@Test
public void testAzimuth() {
final double EPS = 2E-1;
final GeodeticCalculator calculator = new GeodeticCalculator();
assertTrue(calculator.getCoordinateReferenceSystem() instanceof GeographicCRS);
calculator.setStartingGeographicPoint(12, 20);
calculator.setDestinationGeographicPoint(13, 20); assertEquals("East", 90, calculator.getAzimuth(), EPS);
calculator.setDestinationGeographicPoint(12, 21); assertEquals("North", 0, calculator.getAzimuth(), EPS);
calculator.setDestinationGeographicPoint(11, 20); assertEquals("West", -90, calculator.getAzimuth(), EPS);
calculator.setDestinationGeographicPoint(12, 19); assertEquals("South", 180, calculator.getAzimuth(), EPS);
}
/**
* Test path on the 45th parallel. Data for this test come from the
* <A HREF="http://www.univ-lemans.fr/~hainry/articles/loxonavi.html">Orthodromie et
* loxodromie</A> page.
*/
@Test
@SuppressWarnings("fallthrough")
public void testParallel45() {
// Column 1: Longitude difference in degrees.
// Column 2: Orthodromic distance in kilometers
// Column 3: Loxodromic distance in kilometers
final double[] DATA = {
0.00, 0, 0,
11.25, 883, 884,
22.50, 1762, 1768,
33.75, 2632, 2652,
45.00, 3489, 3536,
56.25, 4327, 4419,
67.50, 5140, 5303,
78.75, 5923, 6187,
90.00, 6667, 7071,
101.25, 7363, 7955,
112.50, 8002, 8839,
123.75, 8573, 9723,
135.00, 9064, 10607,
146.25, 9463, 11490,
157.50, 9758, 12374,
168.75, 9939, 13258,
180.00, 10000, 14142
};
final double R = 20000/Math.PI;
final DefaultEllipsoid ellipsoid = DefaultEllipsoid.createEllipsoid("Test",R,R,SI.KILO(SI.METER));
final GeodeticCalculator calculator = new GeodeticCalculator(ellipsoid);
calculator.setStartingGeographicPoint(0, 45);
for (int i=0; i<DATA.length; i+=3) {
calculator.setDestinationGeographicPoint(DATA[i], 45);
final double orthodromic = calculator.getOrthodromicDistance();
// final double loxodromic = calculator. getLoxodromicDistance();
assertEquals("Orthodromic distance", DATA[i+1], orthodromic, 0.75);
// assertEquals( "Loxodromic distance", DATA[i+2], loxodromic, 0.75);
/*
* Test the orthodromic path. We compare its length with the expected length.
*/
int count=0;
double length=0, lastX=Double.NaN, lastY=Double.NaN;
final Shape path = calculator.getGeodeticCurve(1000);
final PathIterator iterator = path.getPathIterator(null, 0.1);
final double[] buffer = new double[6];
while (!iterator.isDone()) {
switch (iterator.currentSegment(buffer)) {
case PathIterator.SEG_LINETO: {
count++;
length += ellipsoid.orthodromicDistance(lastX, lastY, buffer[0], buffer[1]);
// Fall through
}
case PathIterator.SEG_MOVETO: {
lastX = buffer[0];
lastY = buffer[1];
break;
}
default: {
throw new IllegalPathStateException();
}
}
iterator.next();
}
assertEquals("Segment count", 1000, count); // Implementation check; will no longer be
// valid when the path will contains curves.
assertEquals("Orthodromic path length", orthodromic, length, 1E-4);
}
}
/**
* Tests geodetic calculator involving a coordinate operation.
* Our test uses a simple geographic CRS with only the axis order interchanged.
*/
@Test
public void testUsingTransform() throws FactoryException, TransformException {
final GeographicCRS crs = new DefaultGeographicCRS("Test", DefaultGeodeticDatum.WGS84,
new DefaultEllipsoidalCS("Test", DefaultCoordinateSystemAxis.LATITUDE,
DefaultCoordinateSystemAxis.LONGITUDE));
final GeodeticCalculator calculator = new GeodeticCalculator(crs);
assertSame(crs, calculator.getCoordinateReferenceSystem());
final double x = 45;
final double y = 30;
calculator.setStartingPosition(new DirectPosition2D(x,y));
Point2D point = calculator.getStartingGeographicPoint();
assertEquals(y, point.getX(), 1E-5);
assertEquals(x, point.getY(), 1E-5);
calculator.setDirection(10, 100);
DirectPosition position = calculator.getDestinationPosition();
point = calculator.getDestinationGeographicPoint();
assertEquals(point.getX(), position.getOrdinate(1), 1E-5);
assertEquals(point.getY(), position.getOrdinate(0), 1E-5);
}
/**
* Tests orthrodromic distance on the equator. The main purpose of this method is actually
* to get Java assertions to be run, which will compare the Geodetic Calculator results with
* the Default Ellipsoid computations.
*/
@Test
public void testEquator() {
assertTrue(GeodeticCalculator.class.desiredAssertionStatus());
final GeodeticCalculator calculator = new GeodeticCalculator();
calculator.setStartingGeographicPoint(0, 0);
double last = Double.NaN;
for (double x=0; x<=180; x+=0.125) {
calculator.setDestinationGeographicPoint(x, 0);
final double distance = calculator.getOrthodromicDistance() / 1000; // In kilometers
/*
* Checks that the increment is constant. It is not for x>179 unless
* GeodeticCalculator switch to DefaultEllipsoid algorithm, which is
* what we want to ensure with this test.
*/
assertFalse(Math.abs(Math.abs(distance - last) - 13.914935) > 2E-6);
last = distance;
}
}
/**
* Tests the points reported in
* <a href="http://jira.codehaus.org/browse/GEOT-1535">GEOT-1535</a>.
*
* @todo Disabled for now, because the error still presents.
*/
@Test
@Ignore
public void testGEOT1535() {
final GeodeticCalculator calculator = new GeodeticCalculator();
calculator.setStartingGeographicPoint(10, 40);
calculator.setDestinationGeographicPoint(-175, -30);
System.out.println(calculator.getOrthodromicDistance());
System.out.println(calculator.getAzimuth());
calculator.setStartingGeographicPoint(180, 40);
calculator.setDestinationGeographicPoint(-5, -30);
System.out.println(calculator.getOrthodromicDistance());
System.out.println(calculator.getAzimuth());
}
}