From cf568904005ca203076186820b9a7876f7cb1882 Mon Sep 17 00:00:00 2001 From: Ignacio Vera Date: Wed, 4 Apr 2018 13:33:42 +0200 Subject: [PATCH] LUCENE-8236: Filter duplicated points when creating GeoPath shapes to avoid creation of bogus planes. --- lucene/CHANGES.txt | 3 +++ .../lucene/spatial3d/geom/GeoPathFactory.java | 22 ++++++++++++++++-- .../lucene/spatial3d/geom/GeoPathTest.java | 23 +++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 1f839801433..95d8738cf8b 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -120,6 +120,9 @@ Bug Fixes * LUCENE-8234: Fixed bug in how spatial relationship is computed for GeoStandardCircle when it covers the whole world. (Ignacio Vera) +* LUCENE-8236: Filter duplicated points when creating GeoPath shapes to + avoid creation of bogus planes. (Ignacio Vera) + Other * LUCENE-8228: removed obsolete IndexDeletionPolicy clone() requirements from diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPathFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPathFactory.java index 2ca132f1244..6389f57b70a 100644 --- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPathFactory.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPathFactory.java @@ -16,6 +16,9 @@ */ package org.apache.lucene.spatial3d.geom; +import java.util.ArrayList; +import java.util.List; + /** * Class which constructs a GeoPath representing an arbitrary path. * @@ -34,9 +37,24 @@ public class GeoPathFactory { */ public static GeoPath makeGeoPath(final PlanetModel planetModel, final double maxCutoffAngle, final GeoPoint[] pathPoints) { if (maxCutoffAngle < Vector.MINIMUM_ANGULAR_RESOLUTION) { - return new GeoDegeneratePath(planetModel, pathPoints); + return new GeoDegeneratePath(planetModel, filterPoints(pathPoints)); } - return new GeoStandardPath(planetModel, maxCutoffAngle, pathPoints); + return new GeoStandardPath(planetModel, maxCutoffAngle, filterPoints(pathPoints)); + } + + /** Filter duplicate points. + * @param pathPoints with the arras of points. + * @return the filtered array. + */ + private static GeoPoint[] filterPoints(final GeoPoint[] pathPoints) { + final List noIdenticalPoints = new ArrayList<>(pathPoints.length); + for (int i = 0; i < pathPoints.length - 1; i++) { + if (!pathPoints[i].isNumericallyIdentical(pathPoints[i + 1])) { + noIdenticalPoints.add(pathPoints[i]); + } + } + noIdenticalPoints.add(pathPoints[pathPoints.length - 1]); + return noIdenticalPoints.toArray(new GeoPoint[noIdenticalPoints.size()]); } } diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java index f6d14f2b6a0..93f90f4a67f 100755 --- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java +++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java @@ -379,4 +379,27 @@ public class GeoPathTest { } + @Test + public void testIdenticalPoints() { + PlanetModel planetModel = PlanetModel.WGS84; + GeoPoint point1 = new GeoPoint(planetModel, 1.5707963267948963, -2.4818290647609542E-148); + GeoPoint point2 = new GeoPoint(planetModel, 1.570796326794895, -3.5E-323); + GeoPoint point3 = new GeoPoint(planetModel,4.4E-323, -3.1415926535897896); + GeoPath path = GeoPathFactory.makeGeoPath(planetModel, 0, new GeoPoint[] {point1, point2, point3}); + GeoPoint point = new GeoPoint(planetModel, -1.5707963267948952,2.369064805649877E-284); + //If not filtered the point is wrongly in set + assertFalse(path.isWithin(point)); + //If not filtered it throws error + path = GeoPathFactory.makeGeoPath(planetModel, 1e-6, new GeoPoint[] {point1, point2, point3}); + assertFalse(path.isWithin(point)); + + GeoPoint point4 = new GeoPoint(planetModel, 1.5, 0); + GeoPoint point5 = new GeoPoint(planetModel, 1.5, 0); + GeoPoint point6 = new GeoPoint(planetModel,4.4E-323, -3.1415926535897896); + //If not filtered creates a degenerated Vector + path = GeoPathFactory.makeGeoPath(planetModel, 0, new GeoPoint[] {point4, point5, point6}); + path = GeoPathFactory.makeGeoPath(planetModel, 0.5, new GeoPoint[] {point4, point5, point6}); + + } + }