From 1af5de16306cac25d33cecb982072208cc9091cc Mon Sep 17 00:00:00 2001 From: iverase Date: Tue, 25 Oct 2022 08:50:05 +0200 Subject: [PATCH 1/3] Fix handling indexed envelopes crossing the dateline in mvt API --- .../GeoShapeWithDocValuesFieldTypeTests.java | 90 ++++++++++++------- .../vectortile/feature/FeatureFactory.java | 11 ++- 2 files changed, 68 insertions(+), 33 deletions(-) diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java index 22033b2108ad6..f526c64ae349a 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java @@ -150,7 +150,61 @@ private Geometry normalize(Geometry geometry) { } } - public void testFetchSourceValueDateLine() throws IOException { + public void testFetchSourcePolygonDateLine() throws IOException { + assertFetchSourceGeometry( + "POLYGON((170 -10, -170 -10, -170 10, 170 10, 170 -10))", + "MULTIPOLYGON (((180.0 -10.0, 180.0 10.0, 170.0 10.0, 170.0 -10.0, 180.0 -10.0))," + + "((-180.0 10.0, -180.0 -10.0, -170.0 -10.0, -170.0 10.0, -180.0 10.0)))", + Map.of( + "type", + "MultiPolygon", + "coordinates", + List.of( + List.of( + List.of( + List.of(180.0, -10.0), + List.of(180.0, 10.0), + List.of(170.0, 10.0), + List.of(170.0, -10.0), + List.of(180.0, -10.0) + ) + ), + List.of( + List.of( + List.of(-180.0, 10.0), + List.of(-180.0, -10.0), + List.of(-170.0, -10.0), + List.of(-170.0, 10.0), + List.of(-180.0, 10.0) + ) + ) + ) + ), + "MULTIPOLYGON (((180.0 -10.0, 180.0 10.0, 170.0 10.0, 170.0 -10.0, 180.0 -10.0))," + + "((-180.0 10.0, -180.0 -10.0, -170.0 -10.0, -170.0 10.0, -180.0 10.0)))" + ); + } + + public void testFetchSourceEnvelope() throws IOException { + assertFetchSourceGeometry( + "BBOX(-10, 10, 10, -10)", + "BBOX (-10.0, 10.0, 10.0, -10.0)", + Map.of("type", "Envelope", "coordinates", List.of(List.of(-10.0, 10.0), List.of(10.0, -10.0))), + "POLYGON ((-10 -10, 10 -10, 10 10, -10 10, -10 -10)))" + ); + } + + public void testFetchSourceEnvelopeDateLine() throws IOException { + assertFetchSourceGeometry( + "BBOX(10, -10, 10, -10)", + "BBOX (10.0, -10.0, 10.0, -10.0)", + Map.of("type", "Envelope", "coordinates", List.of(List.of(10.0, 10.0), List.of(-10.0, -10.0))), + "MULTIPOLYGON (((-180 -10, -10 -10, -10 10, -180 10, -180 -10)), ((10 -10, 180 -10, 180 10, 10 10, 10 -10)))" + ); + } + + private void assertFetchSourceGeometry(Object sourceValue, String wktValue, Map jsonValue, String mvtEquivalentAsWKT) + throws IOException { final GeoFormatterFactory geoFormatterFactory = new GeoFormatterFactory<>( new SpatialGeometryFormatterExtension().getGeometryFormatterFactories() ); @@ -161,38 +215,12 @@ public void testFetchSourceValueDateLine() throws IOException { false, geoFormatterFactory ).build(MapperBuilderContext.ROOT).fieldType(); - // Test a polygon crossing the dateline - Object sourceValue = "POLYGON((170 -10, -170 -10, -170 10, 170 10, 170 -10))"; - String polygonDateLine = "MULTIPOLYGON (((180.0 -10.0, 180.0 10.0, 170.0 10.0, 170.0 -10.0, 180.0 -10.0))," - + "((-180.0 10.0, -180.0 -10.0, -170.0 -10.0, -170.0 10.0, -180.0 10.0)))"; - Map jsonPolygonDateLine = Map.of( - "type", - "MultiPolygon", - "coordinates", - List.of( - List.of( - List.of(List.of(180.0, -10.0), List.of(180.0, 10.0), List.of(170.0, 10.0), List.of(170.0, -10.0), List.of(180.0, -10.0)) - ), - List.of( - List.of( - List.of(-180.0, 10.0), - List.of(-180.0, -10.0), - List.of(-170.0, -10.0), - List.of(-170.0, 10.0), - List.of(-180.0, 10.0) - ) - ) - ) - ); - - assertEquals(List.of(jsonPolygonDateLine), fetchSourceValue(mapper, sourceValue, null)); - assertEquals(List.of(polygonDateLine), fetchSourceValue(mapper, sourceValue, "wkt")); - String mvtPolygonDateLine = "MULTIPOLYGON (((180.0 -10.0, 180.0 10.0, 170.0 10.0, 170.0 -10.0, 180.0 -10.0))," - + "((-180.0 10.0, -180.0 -10.0, -170.0 -10.0, -170.0 10.0, -180.0 10.0)))"; + assertEquals(List.of(jsonValue), fetchSourceValue(mapper, sourceValue, null)); + assertEquals(List.of(wktValue), fetchSourceValue(mapper, sourceValue, "wkt")); - List mvtExpected = fetchSourceValue(mapper, mvtPolygonDateLine, "mvt(0/0/0@256)"); - List mvt = fetchSourceValue(mapper, sourceValue, "mvt(0/0/0@256)"); + List mvtExpected = fetchSourceValue(mapper, mvtEquivalentAsWKT, "mvt(0/0/0@4096)"); + List mvt = fetchSourceValue(mapper, sourceValue, "mvt(0/0/0@4096)"); assertThat(mvt.size(), Matchers.equalTo(1)); assertThat(mvt.size(), Matchers.equalTo(mvtExpected.size())); assertThat(mvtExpected.get(0), Matchers.instanceOf(byte[].class)); diff --git a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java index aaf23de2a77e2..5eedd73aa888b 100644 --- a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java +++ b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java @@ -288,8 +288,15 @@ public org.locationtech.jts.geom.Geometry visit(Rectangle rectangle) throws Runt final double yMin = SphericalMercatorUtils.latToSphericalMercator(rectangle.getMinY()); final double xMax = SphericalMercatorUtils.lonToSphericalMercator(rectangle.getMaxX()); final double yMax = SphericalMercatorUtils.latToSphericalMercator(rectangle.getMaxY()); - final Envelope envelope = new Envelope(xMin, xMax, yMin, yMax); - return geomFactory.toGeometry(envelope); + if (rectangle.getMinX() > rectangle.getMaxX()) { + // crosses dateline + final Envelope westEnvelope = new Envelope(-SphericalMercatorUtils.MERCATOR_BOUNDS, xMax, yMin, yMax); + final Envelope eastEnvelope = new Envelope(xMin, SphericalMercatorUtils.MERCATOR_BOUNDS, yMin, yMax); + return geomFactory.buildGeometry(List.of(geomFactory.toGeometry(westEnvelope), geomFactory.toGeometry(eastEnvelope))); + } else { + final Envelope envelope = new Envelope(xMin, xMax, yMin, yMax); + return geomFactory.toGeometry(envelope); + } } } From 56b8d945910c0f9c1e5297904b3d99030e40daeb Mon Sep 17 00:00:00 2001 From: Ignacio Vera Date: Tue, 25 Oct 2022 08:54:33 +0200 Subject: [PATCH 2/3] Update docs/changelog/91105.yaml --- docs/changelog/91105.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 docs/changelog/91105.yaml diff --git a/docs/changelog/91105.yaml b/docs/changelog/91105.yaml new file mode 100644 index 0000000000000..138200e919bb3 --- /dev/null +++ b/docs/changelog/91105.yaml @@ -0,0 +1,6 @@ +pr: 91105 +summary: Fix handling indexed envelopes crossing the dateline in mvt API +area: Geo +type: bug +issues: + - 91060 From c2b7d952a1025402fd8caf45fc1e7fb760517e49 Mon Sep 17 00:00:00 2001 From: iverase Date: Wed, 2 Nov 2022 14:50:51 +0100 Subject: [PATCH 3/3] make extent random in test --- .../index/mapper/GeoShapeWithDocValuesFieldTypeTests.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java index f526c64ae349a..eca19e9bfdd70 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java @@ -219,8 +219,9 @@ private void assertFetchSourceGeometry(Object sourceValue, String wktValue, Map< assertEquals(List.of(jsonValue), fetchSourceValue(mapper, sourceValue, null)); assertEquals(List.of(wktValue), fetchSourceValue(mapper, sourceValue, "wkt")); - List mvtExpected = fetchSourceValue(mapper, mvtEquivalentAsWKT, "mvt(0/0/0@4096)"); - List mvt = fetchSourceValue(mapper, sourceValue, "mvt(0/0/0@4096)"); + final int extent = randomIntBetween(256, 4096); + List mvtExpected = fetchSourceValue(mapper, mvtEquivalentAsWKT, "mvt(0/0/0@" + extent + ")"); + List mvt = fetchSourceValue(mapper, sourceValue, "mvt(0/0/0@" + extent + ")"); assertThat(mvt.size(), Matchers.equalTo(1)); assertThat(mvt.size(), Matchers.equalTo(mvtExpected.size())); assertThat(mvtExpected.get(0), Matchers.instanceOf(byte[].class));