/*
* Copyright ThinkTank Maths Limited 2006 - 2008
*
* This file 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, either version 3 of the License, or (at your option)
* any later version.
*
* This file 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this file. If not, see <http://www.gnu.org/licenses/>.
*/
package com.openlapi;
/**
*
*/
class CoordinatesTest extends ALAPITest {
public void runTests() throws LAPIException {
testConstructor();
testDistance();
testAzimuthTo();
testConvertToStringType1();
testConvertToStringType2();
testConvertFromString();
}
public void testAzimuthTo() throws LAPIException {
// test exception handling
boolean caught = false;
Coordinates test = new Coordinates(0.0, 0.0, Float.NaN);
try {
test.azimuthTo(null);
} catch (NullPointerException e) {
caught = true;
}
assertion(caught);
// test correct behaviour when coordinates are the same
testAzimuthTo2(0.0, 0.0, 0.0, 0.0, 0.0);
testAzimuthTo2(90.0, 0.0, 90.0, 0.0, 0.0);
testAzimuthTo2(-90.0, 0.0, -90.0, 0.0, 0.0);
/*
* When the origin is the North pole and the destination is not the North pole,
* this method returns 180.0.
*/
testAzimuthTo2(90.0, 0.0, 0.0, 0.0, 180.0);
testAzimuthTo2(90.0, 0.0, -90.0, 0.0, 180.0);
testAzimuthTo2(90.0, 0.0, -33.966667, 18.4166667, 180.0);
/*
* When the origin is the South pole and the destination is not the South pole,
* this method returns 0.0.
*/
testAzimuthTo2(-90.0, 0.0, 0.0, 0.0, 0.0);
testAzimuthTo2(-90.0, 0.0, 90.0, 0.0, 0.0);
testAzimuthTo2(-90.0, 0.0, -33.966667, 18.4166667, 0.0);
// Table Mountain, South Africa (Mountain, Western Cape)
// Edinburgh Castle, United Kingdom (Castle, United Kingdom)
testAzimuthTo2(-33.966667, 18.4166667, 55.95, -3.2, 348.0);
// Crude Glasgow <-> London calculation to sanity check
testAzimuthTo2(55, -4, 51, 0, 147.35);
// Gibraltar, Gibraltar (Mountain, Gibraltar)
// Auckland Island, New Zealand (Island, New Zealand)
testAzimuthTo2(36.11666666667, -5.31666666667, -50.71666666667,
166.11666666667, 160.0);
// this tests behaviour on two close locations
// 4.6km apart
testAzimuthTo2(-33, 18, -33, 18.05, 90);
// 9cm apart
testAzimuthTo2(-33, 18, -33, 18.000001, 90);
// 1cm apart
testAzimuthTo2(-33, 18, -33, 18.0000001, 90);
// 1mm apart
testAzimuthTo2(-33, 18, -33, 18.00000001, 90);
// this tests equatorial behaviour
testAzimuthTo2(0.0, 0.0, 0.0, 45.0, 90);
testAzimuthTo2(0.0, 0.0, 0.0, -45.0, 270);
// ?? more Coordinates.azimuthTo() tests
// Especially to test correct quadrant
}
public void testConstructor() throws LAPIException {
// check if the bounds are being checked on init
assertion(testConstructor2(90.000001, 0));
assertion(testConstructor2(-90.000001, 0));
assertion(!testConstructor2(90, 0));
assertion(!testConstructor2(-90, 0));
assertion(testConstructor2(0, 180));
assertion(!testConstructor2(0, -180));
assertion(testConstructor2(0, 180.000001));
}
public void testConvertFromString() throws LAPIException {
// some Strings that should throw exceptions
boolean caught = false;
try {
Coordinates.convert(null);
} catch (NullPointerException e) {
caught = true;
}
assertion(caught);
caught = false;
try {
Coordinates.convert("blah");
} catch (IllegalArgumentException e) {
caught = true;
}
assertion(caught);
caught = false;
try {
Coordinates.convert("61:30::");
} catch (IllegalArgumentException e) {
caught = true;
}
assertion(caught);
caught = false;
try {
Coordinates.convert("61.30:6");
} catch (IllegalArgumentException e) {
caught = true;
}
assertion(caught);
assertEquals(61.51d, Coordinates.convert("61:30.6"), 0.001);
assertEquals(-61.51d, Coordinates.convert("-61:30.6"), 0.001);
assertEquals(61.51d, Coordinates.convert("61:30:36"), 0.001);
assertEquals(10.83535, Coordinates.convert("10:50:07.2"), 0.0001);
assertEquals(10.83535, Coordinates.convert("10:50.120"),0.0001);
assertEquals(32 + 0.0006/60, Coordinates.convert("32:00.0006"), 0.0001);
// ?? more Coordinates.convert() tests
}
public void testConvertToStringType1() throws LAPIException {
assertEquals("61:30:36", Coordinates.convert(61.51, Coordinates.DD_MM_SS));
assertEquals("-61:30:36", Coordinates.convert(-61.51, Coordinates.DD_MM_SS));
assertEquals("10:50:07.2", Coordinates.convert(10.8353333, Coordinates.DD_MM_SS));
}
public void testConvertToStringType2() throws LAPIException {
assertEquals("61:30.6", Coordinates.convert(61.51, Coordinates.DD_MM));
assertEquals("-61:30.6", Coordinates.convert(-61.51, Coordinates.DD_MM));
assertEquals("10:50.12", Coordinates.convert(10.8353333, Coordinates.DD_MM));
assertEquals("32:00.0006", Coordinates.convert(32 + 0.0006/60, Coordinates.DD_MM));
}
/**
* Test the accuracy of the distance() method, using several extreme situations known
* to break most algorithms.
* <p>
* Note that all my test distances have been gathered by comparing website calculators
* and the Nokia implementation... none of these 'measured' distances are actually
* empirical.
*
* @throws LAPIException
*/
public void testDistance() throws LAPIException {
// test exception handling
boolean caught = false;
Coordinates test = new Coordinates(0.0, 0.0, Float.NaN);
try {
test.distance(null);
} catch (NullPointerException e) {
caught = true;
}
assertion(caught);
// Table Mountain, South Africa (Mountain, Western Cape)
// Edinburgh Castle, United Kingdom (Castle, United Kingdom)
testDistance2(-33.966667, 18.4166667, 55.95, -3.2, 10172500.0);
// Cramond to ThinkTank offices
testDistance2(55.973894, -3.305984, 55.923648, -3.172259, 10050);
// same latitude
testDistance2(55.973894, -3.305984, 55.973894, -3.172259, 8329);
testDistance2(55.923648, -3.305984, 55.923648, -3.172259, 8349);
testDistance2(55.923648, 0, 55.923648, -0.133725, 8349);
testDistance2(55.973894, 0, 55.973894, -0.133725, 8329);
// this tests behaviour on two close locations
// 4.6km apart
testDistance2(-33, 18, -33, 18.05, 4672.661);
// 9cm apart
testDistance2(-33, 18, -33, 18.000001, 0.0932);
// 1cm apart
testDistance2(-33, 18, -33, 18.0000001, 0.00932);
// 1mm apart
testDistance2(-33, 18, -33, 18.00000001, 0.000932);
// this tests behaviour on the same two locations
testDistance2(0.0, 0.0, 0.0, 0.0, 0.0);
// this tests equatorial behaviour
testDistance2(0.0, 0.0, 0.0, 45.0, 5009377.086);
// near-antipode behaviour
// Gibraltar, Gibraltar (Mountain, Gibraltar)
// Auckland Island, New Zealand (Island, New Zealand)
testDistance2(36.11666666667, -5.31666666667, -50.71666666667,
166.11666666667, 18247900.0);
// this tests actual anti-podal behaviour
testDistance2(90.0, 0.0, -90.0, 0.0, 20020000);
testDistance2(0.0, 0.0, 0.0, -180.0, 20037502);
}
private void testAzimuthTo2(double latitude1, double longitude1,
double latitude2, double longitude2, double measured)
throws LAPIException {
// Specification says 1 degree precision is required, small bit added
// for same-point checks
double error = 1.0;
Coordinates a = new Coordinates(latitude1, longitude1, Float.NaN);
Coordinates b = new Coordinates(latitude2, longitude2, Float.NaN);
double azimuth = a.azimuthTo(b);
assertion((azimuth < (measured + error))
&& (azimuth > (measured - error)));
}
/**
* @param latitude
* @param longitude
* @return true if the arguments were out of bounds
*/
private boolean testConstructor2(double latitude, double longitude) {
boolean caught = false;
try {
new Coordinates(latitude, longitude, Float.NaN);
} catch (IllegalArgumentException e) {
caught = true;
}
return caught;
}
/**
* Convenience method for testing the distance calculated between two coordinates is
* correct within 0.36%.
*
* @param latitude1
* of first coordinate.
* @param longitude1
* of first coordinate.
* @param latitude2
* of second coordinate.
* @param longitude2
* of second coordinate.
* @param measured
* distance between the coordinates, across the Earth's surface ignoring
* altitude.
* @throws LAPIException
*/
private void testDistance2(double latitude1, double longitude1,
double latitude2, double longitude2, double measured)
throws LAPIException {
// Specification says 0.36% precision is required, small bit added for
// same-point checks
double error = measured * 0.0036 + 0.000000001;
Coordinates a = new Coordinates(latitude1, longitude1, Float.NaN);
Coordinates b = new Coordinates(latitude2, longitude2, Float.NaN);
double distance = a.distance(b);
assertion((distance < (measured + error))
&& (distance > (measured - error)),
"Distance test failed, should be " + measured + ", but was "
+ distance);
}
}