/* * 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.lucene.spatial3d.geom; import org.apache.lucene.util.LuceneTestCase; import org.junit.Test; import static com.carrotsearch.randomizedtesting.RandomizedTest.randomFloat; /** * Test basic GeoPoint functionality. */ public class GeoPointTest extends LuceneTestCase { static final double DEGREES_TO_RADIANS = Math.PI / 180; @Test public void testConversion() { testPointRoundTrip(PlanetModel.SPHERE, 90 * DEGREES_TO_RADIANS, 0, 1e-6); testPointRoundTrip(PlanetModel.SPHERE, -90 * DEGREES_TO_RADIANS, 0, 1e-6); testPointRoundTrip(PlanetModel.WGS84, 90 * DEGREES_TO_RADIANS, 0, 1e-6); testPointRoundTrip(PlanetModel.WGS84, -90 * DEGREES_TO_RADIANS, 0, 1e-6); final int times = atLeast(100); for (int i = 0; i < times; i++) { final double pLat = (randomFloat() * 180.0 - 90.0) * DEGREES_TO_RADIANS; final double pLon = (randomFloat() * 360.0 - 180.0) * DEGREES_TO_RADIANS; testPointRoundTrip(PlanetModel.SPHERE, pLat, pLon, 1e-6);//1e-6 since there's a square root in there (Karl says) testPointRoundTrip(PlanetModel.WGS84, pLat, pLon, 1e-6); } } protected void testPointRoundTrip(PlanetModel planetModel, double pLat, double pLon, double epsilon) { final GeoPoint p1 = new GeoPoint(planetModel, pLat, pLon); // In order to force the reverse conversion, we have to construct a geopoint from just x,y,z final GeoPoint p2 = new GeoPoint(p1.x, p1.y, p1.z); // Now, construct the final point based on getLatitude() and getLongitude() final GeoPoint p3 = new GeoPoint(planetModel, p2.getLatitude(), p2.getLongitude()); double dist = p1.arcDistance(p3); assertEquals(0, dist, epsilon); } @Test public void testSurfaceDistance() { final int times = atLeast(100); for (int i = 0; i < times; i++) { final double p1Lat = (randomFloat() * 180.0 - 90.0) * DEGREES_TO_RADIANS; final double p1Lon = (randomFloat() * 360.0 - 180.0) * DEGREES_TO_RADIANS; final double p2Lat = (randomFloat() * 180.0 - 90.0) * DEGREES_TO_RADIANS; final double p2Lon = (randomFloat() * 360.0 - 180.0) * DEGREES_TO_RADIANS; final GeoPoint p1 = new GeoPoint(PlanetModel.SPHERE, p1Lat, p1Lon); final GeoPoint p2 = new GeoPoint(PlanetModel.SPHERE, p2Lat, p2Lon); final double arcDistance = p1.arcDistance(p2); // Compute ellipsoid distance; it should agree for a sphere final double surfaceDistance = PlanetModel.SPHERE.surfaceDistance(p1,p2); assertEquals(arcDistance, surfaceDistance, 1e-6); } // Now try some WGS84 points (taken randomly and compared against a known-good implementation) assertEquals(1.1444648695765323, PlanetModel.WGS84.surfaceDistance( new GeoPoint(PlanetModel.WGS84, 0.038203808753702884, -0.6701260455506466), new GeoPoint(PlanetModel.WGS84, -0.8453720422675458, 0.1737353153814496)), 1e-6); assertEquals(1.4345148695890722, PlanetModel.WGS84.surfaceDistance( new GeoPoint(PlanetModel.WGS84, 0.5220926323378574, 0.6758041581907408), new GeoPoint(PlanetModel.WGS84, -0.8453720422675458, 0.1737353153814496)), 1e-6); assertEquals(2.32418144616446, PlanetModel.WGS84.surfaceDistance( new GeoPoint(PlanetModel.WGS84, 0.09541335760967473, 1.2091829760623236), new GeoPoint(PlanetModel.WGS84, -0.8501591797459979, -2.3044806381627594)), 1e-6); assertEquals(2.018421047005435, PlanetModel.WGS84.surfaceDistance( new GeoPoint(PlanetModel.WGS84, 0.3402853531962009, -0.43544195327249957), new GeoPoint(PlanetModel.WGS84, -0.8501591797459979, -2.3044806381627594)), 1e-6); } @Test public void testBisection() { final int times = atLeast(100); for (int i = 0; i < times; i++) { final double p1Lat = (randomFloat() * 180.0 - 90.0) * DEGREES_TO_RADIANS; final double p1Lon = (randomFloat() * 360.0 - 180.0) * DEGREES_TO_RADIANS; final double p2Lat = (randomFloat() * 180.0 - 90.0) * DEGREES_TO_RADIANS; final double p2Lon = (randomFloat() * 360.0 - 180.0) * DEGREES_TO_RADIANS; final GeoPoint p1 = new GeoPoint(PlanetModel.WGS84, p1Lat, p1Lon); final GeoPoint p2 = new GeoPoint(PlanetModel.WGS84, p2Lat, p2Lon); final GeoPoint pMid = PlanetModel.WGS84.bisection(p1, p2); if (pMid != null) { final double arcDistance = p1.arcDistance(p2); final double sum = pMid.arcDistance(p1) + pMid.arcDistance(p2); assertEquals(arcDistance, sum, 1e-6); } } } @Test(expected = IllegalArgumentException.class) public void testBadLatLon() { new GeoPoint(PlanetModel.SPHERE, 50.0, 32.2); } }