From 37d795cf7b8806cedfdba2518c257f3ae997eaab Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Sat, 6 Mar 2021 01:55:08 +0200 Subject: [PATCH] improve the readability of the algorithm for checking that one region is inside another --- .../main/java/net/osmand/map/WorldRegion.java | 43 ++++++++----------- .../main/java/net/osmand/util/Algorithms.java | 41 ++++++++++++++++++ 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java index 45bd14f600..b1be29d5fa 100644 --- a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java +++ b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java @@ -3,6 +3,7 @@ package net.osmand.map; import net.osmand.data.LatLon; import net.osmand.data.QuadRect; import net.osmand.util.Algorithms; +import net.osmand.util.Algorithms.Point2D; import java.io.Serializable; import java.util.LinkedList; @@ -187,37 +188,27 @@ public class WorldRegion implements Serializable { } public boolean containsRegion(WorldRegion region) { - boolean isBoundingAvailable = this.boundingBox != null && region.boundingBox != null; - boolean isPolygonsAvailable = this.polygon != null && region.polygon != null; - - boolean containsBox = false; - if (isBoundingAvailable) { - containsBox = this.boundingBox.contains(region.boundingBox); - } - if (containsBox && isPolygonsAvailable) { - boolean allPointsInsideThePolygon = true; - List regionPolygon = region.polygon; - for (int i = 0; i < regionPolygon.size(); i++) { - allPointsInsideThePolygon = isPointInsideThePolygon(regionPolygon.get(i)); - if (!allPointsInsideThePolygon) { - return false; - } - } - return true; + if (containsBoundingBox(region.boundingBox)) { + // check polygon only if bounding box match + return containsPolygon(region.polygon); } return false; } - private boolean isPointInsideThePolygon(LatLon test) { - boolean result = false; - for (int i = 0, j = polygon.size() - 1; i < polygon.size(); j = i++) { - if ((polygon.get(i).getLongitude() > test.getLongitude()) != (polygon.get(j).getLongitude() > test.getLongitude()) && - (test.getLatitude() < (polygon.get(j).getLatitude() - polygon.get(i).getLatitude()) * (test.getLongitude() - polygon.get(i).getLongitude()) - / (polygon.get(j).getLongitude()-polygon.get(i).getLongitude()) + polygon.get(i).getLatitude())) { - result = !result; - } + private boolean containsBoundingBox(QuadRect rectangle) { + if (boundingBox != null && rectangle != null) { + return boundingBox.contains(rectangle); } - return result; + return false; + } + + private boolean containsPolygon(List another) { + if (polygon != null && another != null) { + Point2D[] inner = Algorithms.createPoint2DArrayFromLatLon(polygon); + Point2D[] outer = Algorithms.createPoint2DArrayFromLatLon(another); + return Algorithms.isFirstPolygonInsideTheSecond(outer, inner); + } + return false; } public boolean isContinent() { diff --git a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java index 36c0034a26..b539ca8363 100644 --- a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java +++ b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java @@ -2,6 +2,7 @@ package net.osmand.util; import net.osmand.IProgress; import net.osmand.PlatformUtil; +import net.osmand.data.LatLon; import org.apache.commons.logging.Log; import org.xmlpull.v1.XmlPullParser; @@ -117,6 +118,46 @@ public class Algorithms { } return def; } + + public static class Point2D { + public double x; + public double y; + } + + public static Point2D[] createPoint2DArrayFromLatLon(List latLons) { + Point2D[] array = new Point2D[latLons.size()]; + for (int i = 0; i < array.length; i++) { + Point2D point = new Point2D(); + point.x = latLons.get(i).getLatitude(); + point.y = latLons.get(i).getLongitude(); + array[i] = point; + } + return array; + } + + public static boolean isFirstPolygonInsideTheSecond(Point2D[] first, + Point2D[] second) { + for (Point2D point : first) { + if (!isPointInsideTheBoundary(point, second)) { + // if at least one point is not inside the boundary, return false + return false; + } + } + return true; + } + + public static boolean isPointInsideTheBoundary(Point2D point, + Point2D[] polygon) { + boolean result = false; + for (int i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { + if ((polygon[i].y > point.y) != (polygon[j].y > point.y) + && (point.x < (polygon[j].x - polygon[i].x) * (point.y - polygon[i].y) / + (polygon[j].y-polygon[i].y) + polygon[i].x)) { + result = !result; + } + } + return result; + } public static int parseIntSilently(String input, int def) { if (input != null && input.length() > 0) {