From 4ab711166886c0ec3b14909feb06123247fdfa04 Mon Sep 17 00:00:00 2001 From: Igor Motov Date: Wed, 11 Sep 2019 14:53:10 -0400 Subject: [PATCH] Geo: fix indexing of west to east linestrings crossing the antimeridian (#46601) Fixes that way linestrings that are crossing the antimeridian are indexed due to a normalization bug these lines were decomposed into a line segment that was stretching entire globe. Fixes #43775 --- .../index/mapper/GeoShapeIndexer.java | 13 +++++++--- .../common/geo/GeometryIndexerTests.java | 24 ++++++++++++++++--- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeIndexer.java b/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeIndexer.java index e3de485fc7a32..54fb9a97a8658 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeIndexer.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeIndexer.java @@ -229,7 +229,7 @@ private List decomposeGeometry(Line line, List lines) { double[] lons = new double[partMinus.length()]; for (int i = 0; i < partMinus.length(); i++) { lats[i] = normalizeLat(partMinus.getY(i)); - lons[i] = normalizeLon(partMinus.getX(i)); + lons[i] = normalizeLonMinus180Inclusive(partMinus.getX(i)); } lines.add(new Line(lons, lats)); } @@ -274,7 +274,7 @@ private List decompose(double dateline, double[] lons, double[] lats) { lons[offset + i - 1] = intersection.getX(); lats[offset + i - 1] = intersection.getY(); - shift(shift, lons); + shift(shift, partLons); offset = i - 1; shift = lons[i] > DATELINE ? DATELINE : (lons[i] < -DATELINE ? -DATELINE : 0); } else { @@ -926,7 +926,7 @@ private static Polygon buildPolygon(List polygon) { for (int i = 0; i < shell.length; ++i) { //Lucene Tessellator treats different +180 and -180 and we should keep the sign. //normalizeLon method excludes -180. - x[i] = Math.abs(shell[i].getX()) > 180 ? normalizeLon(shell[i].getX()) : shell[i].getX(); + x[i] = normalizeLonMinus180Inclusive(shell[i].getX()); y[i] = normalizeLat(shell[i].getY()); } @@ -1043,4 +1043,11 @@ public static org.apache.lucene.geo.Polygon toLucenePolygon(Polygon polygon) { } return new org.apache.lucene.geo.Polygon(polygon.getPolygon().getY(), polygon.getPolygon().getX(), holes); } + + /** + * Normalizes longitude while accepting -180 degrees as a valid value + */ + private static double normalizeLonMinus180Inclusive(double lon) { + return Math.abs(lon) > 180 ? normalizeLon(lon) : lon; + } } diff --git a/server/src/test/java/org/elasticsearch/common/geo/GeometryIndexerTests.java b/server/src/test/java/org/elasticsearch/common/geo/GeometryIndexerTests.java index 5e5b2b688ea17..47b02ea698112 100644 --- a/server/src/test/java/org/elasticsearch/common/geo/GeometryIndexerTests.java +++ b/server/src/test/java/org/elasticsearch/common/geo/GeometryIndexerTests.java @@ -72,7 +72,7 @@ public void testCollection() { new Point(2, 1), new Point(4, 3), new MultiLine(Arrays.asList( new Line(new double[]{160, 180}, new double[]{10, 15}), - new Line(new double[]{180, -160}, new double[]{15, 20})) + new Line(new double[]{-180, -160}, new double[]{15, 20})) )) ); assertEquals(indexed, indexer.prepareForIndexing(collection)); @@ -87,7 +87,25 @@ public void testLine() { line = new Line(new double[]{160, 200}, new double[]{10, 20}); indexed = new MultiLine(Arrays.asList( new Line(new double[]{160, 180}, new double[]{10, 15}), - new Line(new double[]{180, -160}, new double[]{15, 20})) + new Line(new double[]{-180, -160}, new double[]{15, 20})) + ); + + assertEquals(indexed, indexer.prepareForIndexing(line)); + + line = new Line(new double[]{200, 160}, new double[]{10, 20}); + indexed = new MultiLine(Arrays.asList( + new Line(new double[]{-160, -180}, new double[]{10, 15}), + new Line(new double[]{180, 160}, new double[]{15, 20})) + ); + + assertEquals(indexed, indexer.prepareForIndexing(line)); + + line = new Line(new double[]{160, 200, 160}, new double[]{0, 10, 20}); + indexed = new MultiLine(Arrays.asList( + new Line(new double[]{160, 180}, new double[]{0, 5}), + new Line(new double[]{-180, -160, -180}, new double[]{5, 10, 15}), + new Line(new double[]{180, 160}, new double[]{15, 20}) + ) ); assertEquals(indexed, indexer.prepareForIndexing(line)); @@ -106,7 +124,7 @@ line, new Line(new double[]{160, 200}, new double[]{10, 20}) indexed = new MultiLine(Arrays.asList( line, new Line(new double[]{160, 180}, new double[]{10, 15}), - new Line(new double[]{180, -160}, new double[]{15, 20})) + new Line(new double[]{-180, -160}, new double[]{15, 20})) ); assertEquals(indexed, indexer.prepareForIndexing(multiLine));