From b4230ebb3c2d5019fdf9468607c1e8b1e7205910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Misiewicz?= Date: Thu, 20 Jul 2017 09:12:46 +0200 Subject: [PATCH] PolygonBound.contains() fix (#4553) * PolygonBound.contains() fix * style fix * code refactor and dependency-reduced-pom.xml deletion * refactor bug fix * requested changes * method extraction * formatting issues fix --- .../spatial/search/PolygonBound.java | 34 ++++++++++++++++--- .../spatial/search/PolygonBoundTest.java | 31 +++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/bytebuffer-collections/src/main/java/io/druid/collections/spatial/search/PolygonBound.java b/bytebuffer-collections/src/main/java/io/druid/collections/spatial/search/PolygonBound.java index 6bc9bb26eed..fbca73dc255 100755 --- a/bytebuffer-collections/src/main/java/io/druid/collections/spatial/search/PolygonBound.java +++ b/bytebuffer-collections/src/main/java/io/druid/collections/spatial/search/PolygonBound.java @@ -124,11 +124,21 @@ public class PolygonBound extends RectangularBound int j = polyCorners - 1; boolean oddNodes = false; for (int i = 0; i < polyCorners; i++) { - if ((ordinate[i] < coords[1] && ordinate[j] >= coords[1] - || ordinate[j] < coords[1] && ordinate[i] >= coords[1]) - && (abscissa[i] <= coords[0] || abscissa[j] <= coords[0])) { - if (abscissa[i] + (coords[1] - ordinate[i]) / (ordinate[j] - ordinate[i]) * (abscissa[j] - abscissa[i]) - < coords[0]) { + + if (abscissa[i] == coords[0] && ordinate[i] == coords[1]) { + return true; + } + + if (isPointLayingOnHorizontalBound(i, j, coords)) { + return true; + } + + if (between(ordinate[i], ordinate[j], coords[1]) && (abscissa[j] <= coords[0] || abscissa[i] <= coords[0])) { + float intersectionPointX = abscissa[i] + (coords[1] - ordinate[i]) / (ordinate[j] - ordinate[i]) * (abscissa[j] - abscissa[i]); + + if (intersectionPointX == coords[0]) { + return true; + } else if (intersectionPointX < coords[0]) { oddNodes = !oddNodes; } } @@ -137,6 +147,20 @@ public class PolygonBound extends RectangularBound return oddNodes; } + private boolean isPointLayingOnHorizontalBound(int i, int j, float[] coords) + { + return ordinate[i] == ordinate[j] && ordinate[j] == coords[1] && between(abscissa[i], abscissa[j], coords[0]); + } + + private static boolean between(float a, float b, float x) + { + if (a <= b) { + return a <= x && x <= b; + } else { + return b <= x && x <= a; + } + } + @Override public Iterable filter(Iterable points) { diff --git a/bytebuffer-collections/src/test/java/io/druid/collections/spatial/search/PolygonBoundTest.java b/bytebuffer-collections/src/test/java/io/druid/collections/spatial/search/PolygonBoundTest.java index 73ac85e6580..b9c3812e427 100755 --- a/bytebuffer-collections/src/test/java/io/druid/collections/spatial/search/PolygonBoundTest.java +++ b/bytebuffer-collections/src/test/java/io/druid/collections/spatial/search/PolygonBoundTest.java @@ -46,4 +46,35 @@ public class PolygonBoundTest PolygonBound.from(new float[]{1F, 2F, 3F}, new float[]{0F, 2F, 0F}, 2).getCacheKey() )); } + + @Test + public void testContains() + { + final PolygonBound triangle = PolygonBound.from(new float[]{1f, 4f, 7f}, new float[]{ 1f, 4f, 1f}); + final float delta = 1e-5f; + + Assert.assertTrue(triangle.contains(new float[]{1f, 1f})); + Assert.assertFalse(triangle.contains(new float[]{1f, 1f - delta})); + Assert.assertFalse(triangle.contains(new float[]{1f, 1f + delta})); + Assert.assertTrue(triangle.contains(new float[]{1f + delta, 1f})); + Assert.assertFalse(triangle.contains(new float[]{1f - delta, 1f})); + Assert.assertTrue(triangle.contains(new float[]{1f + delta, 1f})); + Assert.assertFalse(triangle.contains(new float[]{1f - delta, 1f})); + Assert.assertTrue(triangle.contains(new float[]{5f, 1f})); + Assert.assertFalse(triangle.contains(new float[]{1f, 5f})); + Assert.assertTrue(triangle.contains(new float[]{3f, 2f})); + + final PolygonBound rightTriangle = PolygonBound.from(new float[]{1f, 1f, 5f}, new float[]{ 1f, 5f, 1f}); + + Assert.assertTrue(rightTriangle.contains(new float[]{1f, 5f})); + Assert.assertTrue(rightTriangle.contains(new float[]{2f, 4f})); + Assert.assertTrue(rightTriangle.contains(new float[]{2f - delta , 4f})); + Assert.assertFalse(rightTriangle.contains(new float[]{2f + delta, 4f})); + Assert.assertTrue(rightTriangle.contains(new float[]{2f, 4f - delta})); + Assert.assertFalse(rightTriangle.contains(new float[]{2f, 4f + delta})); + Assert.assertTrue(rightTriangle.contains(new float[]{3f - delta, 3f})); + Assert.assertFalse(rightTriangle.contains(new float[]{3f + delta, 3f})); + Assert.assertTrue(rightTriangle.contains(new float[]{3f, 3f - delta})); + Assert.assertFalse(rightTriangle.contains(new float[]{3f, 3f + delta})); + } }