Skip to content

Commit 3a3bb23

Browse files
authored
Spherical mercator transformation should handle properly out of bounds latitudes (#81145)
Handle properly latitudes close to -90.
1 parent 66dc626 commit 3a3bb23

File tree

2 files changed

+25
-6
lines changed

2 files changed

+25
-6
lines changed

server/src/main/java/org/elasticsearch/common/geo/SphericalMercatorUtils.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public class SphericalMercatorUtils {
1717

1818
public static final double MERCATOR_BOUNDS = 20037508.34;
1919
private static final double MERCATOR_FACTOR = MERCATOR_BOUNDS / 180.0;
20+
// latitude lower limit. Below this limit the transformation might result in -Infinity
21+
private static final double LAT_LOWER_LIMIT = Math.nextUp(-90.0);
2022

2123
/**
2224
* Transforms WGS84 longitude to a Spherical mercator longitude
@@ -29,7 +31,7 @@ public static double lonToSphericalMercator(double lon) {
2931
* Transforms WGS84 latitude to a Spherical mercator latitude
3032
*/
3133
public static double latToSphericalMercator(double lat) {
32-
double y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
34+
double y = Math.log(Math.tan((90 + Math.max(lat, LAT_LOWER_LIMIT)) * Math.PI / 360)) / (Math.PI / 180);
3335
return y * MERCATOR_FACTOR;
3436
}
3537

server/src/test/java/org/elasticsearch/common/geo/SphericalMercatorUtilTests.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,28 @@ public void testLat() {
3434
assertThat(latToSphericalMercator(GeoTileUtils.LATITUDE_MASK), Matchers.closeTo(MERCATOR_BOUNDS, 1e-7));
3535
assertThat(latToSphericalMercator(-GeoTileUtils.LATITUDE_MASK), Matchers.closeTo(-MERCATOR_BOUNDS, 1e-7));
3636
assertThat(latToSphericalMercator(0.0), Matchers.closeTo(0, 1e-7));
37-
final double lat = latToSphericalMercator(
38-
randomValueOtherThanMany(l -> l >= GeoTileUtils.LATITUDE_MASK || l <= -GeoTileUtils.LATITUDE_MASK, GeometryTestUtils::randomLat)
39-
);
40-
assertThat(lat, Matchers.greaterThanOrEqualTo(-MERCATOR_BOUNDS));
41-
assertThat(lat, Matchers.lessThanOrEqualTo(MERCATOR_BOUNDS));
37+
{
38+
final double lat = latToSphericalMercator(
39+
randomValueOtherThanMany(
40+
l -> l >= GeoTileUtils.LATITUDE_MASK || l <= -GeoTileUtils.LATITUDE_MASK,
41+
GeometryTestUtils::randomLat
42+
)
43+
);
44+
assertThat(lat, Matchers.greaterThanOrEqualTo(-MERCATOR_BOUNDS));
45+
assertThat(lat, Matchers.lessThanOrEqualTo(MERCATOR_BOUNDS));
46+
}
47+
{
48+
// out of bounds values
49+
final double lat = latToSphericalMercator(randomDoubleBetween(GeoTileUtils.LATITUDE_MASK, 90, false));
50+
assertThat(lat, Matchers.greaterThan(MERCATOR_BOUNDS));
51+
assertTrue(Double.isFinite(latToSphericalMercator(90)));
52+
}
53+
{
54+
// out of bounds values
55+
final double lat = latToSphericalMercator(-randomDoubleBetween(GeoTileUtils.LATITUDE_MASK, 90, false));
56+
assertThat(lat, Matchers.lessThan(-MERCATOR_BOUNDS));
57+
assertTrue(Double.isFinite(latToSphericalMercator(-90)));
58+
}
4259
}
4360

4461
public void testRectangle() {

0 commit comments

Comments
 (0)