Improve latitude and longitude normalization

This commit is contained in:
Olivier Favre 2012-01-10 17:21:54 +01:00 committed by Shay Banon
parent 97b5c100ce
commit 8f0ecbcc0b
2 changed files with 189 additions and 24 deletions

View File

@ -24,32 +24,20 @@ package org.elasticsearch.index.search.geo;
public class GeoUtils {
public static double normalizeLon(double lon) {
double delta = 0;
if (lon < 0) {
delta = 360;
} else if (lon >= 0) {
delta = -360;
}
double newLng = lon;
while (newLng < -180 || newLng > 180) {
newLng += delta;
}
return newLng;
return centeredModulus(lon, 360);
}
public static double normalizeLat(double lat) {
double delta = 0;
if (lat < 0) {
delta = 180;
} else if (lat >= 0) {
delta = -180;
return centeredModulus(lat, 180);
}
double newLat = lat;
while (newLat < -90 || newLat > 90) {
newLat += delta;
}
return newLat;
private static double centeredModulus(double dividend, double divisor) {
double rtn = dividend % divisor;
if (rtn <= 0)
rtn += divisor;
if (rtn > divisor/2)
rtn -= divisor;
return rtn;
}
}

View File

@ -0,0 +1,177 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.unit.index.search.geo;
import org.elasticsearch.index.search.geo.GeoUtils;
import org.testng.annotations.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
/**
*
*/
public class GeoUtilsTests {
/**
* Test special values like inf, NaN and -0.0.
*/
@Test
public void testSpecials() {
assertThat(GeoUtils.normalizeLon(Double.POSITIVE_INFINITY), equalTo(Double.NaN));
assertThat(GeoUtils.normalizeLat(Double.POSITIVE_INFINITY), equalTo(Double.NaN));
assertThat(GeoUtils.normalizeLon(Double.NEGATIVE_INFINITY), equalTo(Double.NaN));
assertThat(GeoUtils.normalizeLat(Double.NEGATIVE_INFINITY), equalTo(Double.NaN));
assertThat(GeoUtils.normalizeLon(Double.NaN), equalTo(Double.NaN));
assertThat(GeoUtils.normalizeLat(Double.NaN), equalTo(Double.NaN));
assertThat(0.0, not(equalTo(-0.0)));
assertThat(GeoUtils.normalizeLon(-0.0), equalTo(0.0));
assertThat(GeoUtils.normalizeLat(-0.0), equalTo(0.0));
assertThat(GeoUtils.normalizeLon( 0.0), equalTo(0.0));
assertThat(GeoUtils.normalizeLat( 0.0), equalTo(0.0));
}
/**
* Test bounding values.
*/
@Test
public void testBounds() {
assertThat(GeoUtils.normalizeLon(-360.0), equalTo(0.0));
assertThat(GeoUtils.normalizeLat(-180.0), equalTo(0.0));
assertThat(GeoUtils.normalizeLon( 360.0), equalTo(0.0));
assertThat(GeoUtils.normalizeLat( 180.0), equalTo(0.0));
// and halves
assertThat(GeoUtils.normalizeLon(-180.0), equalTo(180.0));
assertThat(GeoUtils.normalizeLat(- 90.0), equalTo( 90.0));
assertThat(GeoUtils.normalizeLon( 180.0), equalTo(180.0));
assertThat(GeoUtils.normalizeLat( 90.0), equalTo( 90.0));
}
/**
* Test normal values.
*/
@Test
public void testNormal() {
// Near bounds
assertThat(GeoUtils.normalizeLon(-360.5), equalTo(-0.5));
assertThat(GeoUtils.normalizeLat(-180.5), equalTo(-0.5));
assertThat(GeoUtils.normalizeLon( 360.5), equalTo( 0.5));
assertThat(GeoUtils.normalizeLat( 180.5), equalTo( 0.5));
// and near halves
assertThat(GeoUtils.normalizeLon(-180.5), equalTo( 179.5));
assertThat(GeoUtils.normalizeLat(- 90.5), equalTo( 89.5));
assertThat(GeoUtils.normalizeLon( 180.5), equalTo(-179.5));
assertThat(GeoUtils.normalizeLat( 90.5), equalTo(- 89.5));
// Every 10-units, multiple full turns
for (int shift = -20 ; shift <= 20 ; ++shift) {
assertThat(GeoUtils.normalizeLon(shift*360.0+ 0.0), equalTo( 0.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 10.0), equalTo( 10.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 20.0), equalTo( 20.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 30.0), equalTo( 30.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 40.0), equalTo( 40.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 50.0), equalTo( 50.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 60.0), equalTo( 60.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 70.0), equalTo( 70.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 80.0), equalTo( 80.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 90.0), equalTo( 90.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 100.0), equalTo( 100.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 110.0), equalTo( 110.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 120.0), equalTo( 120.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 130.0), equalTo( 130.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 140.0), equalTo( 140.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 150.0), equalTo( 150.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 160.0), equalTo( 160.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 170.0), equalTo( 170.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 180.0), equalTo( 180.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 190.0), equalTo(-170.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 200.0), equalTo(-160.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 210.0), equalTo(-150.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 220.0), equalTo(-140.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 230.0), equalTo(-130.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 240.0), equalTo(-120.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 250.0), equalTo(-110.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 260.0), equalTo(-100.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 270.0), equalTo(- 90.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 280.0), equalTo(- 80.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 290.0), equalTo(- 70.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 300.0), equalTo(- 60.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 310.0), equalTo(- 50.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 320.0), equalTo(- 40.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 330.0), equalTo(- 30.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 340.0), equalTo(- 20.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 350.0), equalTo(- 10.0));
assertThat(GeoUtils.normalizeLon(shift*360.0+ 360.0), equalTo( 0.0));
}
for (int shift = -20 ; shift <= 20 ; ++shift) {
assertThat(GeoUtils.normalizeLat(shift*180.0+ 0.0), equalTo( 0.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 10.0), equalTo( 10.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 20.0), equalTo( 20.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 30.0), equalTo( 30.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 40.0), equalTo( 40.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 50.0), equalTo( 50.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 60.0), equalTo( 60.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 70.0), equalTo( 70.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 80.0), equalTo( 80.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 90.0), equalTo( 90.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 100.0), equalTo(-80.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 110.0), equalTo(-70.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 120.0), equalTo(-60.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 130.0), equalTo(-50.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 140.0), equalTo(-40.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 150.0), equalTo(-30.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 160.0), equalTo(-20.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 170.0), equalTo(-10.0));
assertThat(GeoUtils.normalizeLat(shift*180.0+ 180.0), equalTo( 0.0));
}
}
/**
* Test huge values.
*/
@Test
public void testHuge() {
assertThat(GeoUtils.normalizeLon(-36000000000181.0), equalTo(GeoUtils.normalizeLon(-181.0)));
assertThat(GeoUtils.normalizeLon(-36000000000180.0), equalTo(GeoUtils.normalizeLon(-180.0)));
assertThat(GeoUtils.normalizeLon(-36000000000179.0), equalTo(GeoUtils.normalizeLon(-179.0)));
assertThat(GeoUtils.normalizeLon(-36000000000178.0), equalTo(GeoUtils.normalizeLon(-178.0)));
assertThat(GeoUtils.normalizeLon(-36000000000001.0), equalTo(GeoUtils.normalizeLon(-001.0)));
assertThat(GeoUtils.normalizeLon(+36000000000000.0), equalTo(GeoUtils.normalizeLon(+000.0)));
assertThat(GeoUtils.normalizeLon(+36000000000001.0), equalTo(GeoUtils.normalizeLon(+001.0)));
assertThat(GeoUtils.normalizeLon(+36000000000002.0), equalTo(GeoUtils.normalizeLon(+002.0)));
assertThat(GeoUtils.normalizeLon(+36000000000178.0), equalTo(GeoUtils.normalizeLon(+178.0)));
assertThat(GeoUtils.normalizeLon(+36000000000179.0), equalTo(GeoUtils.normalizeLon(+179.0)));
assertThat(GeoUtils.normalizeLon(+36000000000180.0), equalTo(GeoUtils.normalizeLon(+180.0)));
assertThat(GeoUtils.normalizeLon(+36000000000181.0), equalTo(GeoUtils.normalizeLon(+181.0)));
assertThat(GeoUtils.normalizeLat(-18000000000091.0), equalTo(GeoUtils.normalizeLat(-091.0)));
assertThat(GeoUtils.normalizeLat(-18000000000090.0), equalTo(GeoUtils.normalizeLat(-090.0)));
assertThat(GeoUtils.normalizeLat(-18000000000089.0), equalTo(GeoUtils.normalizeLat(-089.0)));
assertThat(GeoUtils.normalizeLat(-18000000000088.0), equalTo(GeoUtils.normalizeLat(-088.0)));
assertThat(GeoUtils.normalizeLat(-18000000000001.0), equalTo(GeoUtils.normalizeLat(-001.0)));
assertThat(GeoUtils.normalizeLat(+18000000000000.0), equalTo(GeoUtils.normalizeLat(+000.0)));
assertThat(GeoUtils.normalizeLat(+18000000000001.0), equalTo(GeoUtils.normalizeLat(+001.0)));
assertThat(GeoUtils.normalizeLat(+18000000000002.0), equalTo(GeoUtils.normalizeLat(+002.0)));
assertThat(GeoUtils.normalizeLat(+18000000000088.0), equalTo(GeoUtils.normalizeLat(+088.0)));
assertThat(GeoUtils.normalizeLat(+18000000000089.0), equalTo(GeoUtils.normalizeLat(+089.0)));
assertThat(GeoUtils.normalizeLat(+18000000000090.0), equalTo(GeoUtils.normalizeLat(+090.0)));
assertThat(GeoUtils.normalizeLat(+18000000000091.0), equalTo(GeoUtils.normalizeLat(+091.0)));
}
}