From 011bf25adc89e35ab9d6e3ebfeaf668eeaa8ea06 Mon Sep 17 00:00:00 2001 From: Brandon Liu Date: Thu, 24 Oct 2024 10:44:46 -0700 Subject: [PATCH] precise filtering of country coder --- .../basemap/feature/CountryCoder.java | 25 +++++++++++++++---- .../com/protomaps/basemap/layers/Roads.java | 14 +++++------ .../basemap/feature/CountryCoderTest.java | 24 ++++++++++++++---- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/tiles/src/main/java/com/protomaps/basemap/feature/CountryCoder.java b/tiles/src/main/java/com/protomaps/basemap/feature/CountryCoder.java index fa4507db..db69c66d 100644 --- a/tiles/src/main/java/com/protomaps/basemap/feature/CountryCoder.java +++ b/tiles/src/main/java/com/protomaps/basemap/feature/CountryCoder.java @@ -38,9 +38,19 @@ public static CountryCoder fromJsonString(String s) throws IOException { for (var feature : features) { JsonNode properties = feature.get("properties"); - if (!feature.has("geometry") || feature.get("geometry").isNull() || !properties.has("country")) { + if (!feature.has("geometry") || feature.get("geometry").isNull()) { continue; } + + String country; + if (properties.has("iso1A2")) { + country = properties.get("iso1A2").asText(); + } else if (properties.has("country")) { + country = properties.get("country").asText(); + } else { + continue; + } + List polygons = new ArrayList<>(); for (var polygon : feature.get("geometry").get("coordinates")) { ArrayNode outerRingNode = (ArrayNode) polygon.get(0); @@ -59,7 +69,7 @@ public static CountryCoder fromJsonString(String s) throws IOException { MultiPolygon multiPolygon = GeoUtils.createMultiPolygon(polygons); multiPolygon.getEnvelopeInternal(); tree.insert(multiPolygon.getEnvelopeInternal(), - new Record(properties.get("country").asText(), properties.get("nameEn").asText(), multiPolygon)); + new Record(country, properties.get("nameEn").asText(), multiPolygon)); } return new CountryCoder(tree); } @@ -75,10 +85,15 @@ private static Coordinate[] parseCoordinates(ArrayNode coordinateArray) { return coordinates; } - public Optional getCountryCode(Point point) { - List results = tree.query(point.getEnvelopeInternal()); + public Optional getCountryCode(Geometry geom) { + List results = tree.query(geom.getEnvelopeInternal()); if (results.isEmpty()) return Optional.empty(); - return Optional.of(results.getFirst().country); + var filtered = results.stream().filter(record -> record.multiPolygon.contains(geom) + ).toList(); + if (filtered.isEmpty()) { + return Optional.empty(); + } + return Optional.of(filtered.getFirst().country); } } diff --git a/tiles/src/main/java/com/protomaps/basemap/layers/Roads.java b/tiles/src/main/java/com/protomaps/basemap/layers/Roads.java index 7787caef..49da0539 100644 --- a/tiles/src/main/java/com/protomaps/basemap/layers/Roads.java +++ b/tiles/src/main/java/com/protomaps/basemap/layers/Roads.java @@ -6,7 +6,6 @@ import com.onthegomap.planetiler.FeatureMerge; import com.onthegomap.planetiler.ForwardingProfile; import com.onthegomap.planetiler.VectorTile; -import com.onthegomap.planetiler.geo.GeoUtils; import com.onthegomap.planetiler.geo.GeometryException; import com.onthegomap.planetiler.reader.SourceFeature; import com.protomaps.basemap.feature.CountryCoder; @@ -44,12 +43,6 @@ public void processOsm(SourceFeature sf, FeatureCollector features) { int minZoomShieldText = 10; int minZoomNames = 14; - try { - var code = countryCoder.getCountryCode(GeoUtils.JTS_FACTORY.createPoint(sf.latLonGeometry().getCoordinate())); - } catch (Exception e) { - - } - String highway = sf.getString("highway"); String service = ""; @@ -161,6 +154,13 @@ public void processOsm(SourceFeature sf, FeatureCollector features) { .setPixelTolerance(0) .setZoomRange(minZoom, maxZoom); + try { + var code = countryCoder.getCountryCode(sf.latLonGeometry()); + feat.setAttr("country_code", code); + } catch (Exception e) { + + } + if (!kindDetail.isEmpty()) { feat.setAttr("kind_detail", kindDetail); } else { diff --git a/tiles/src/test/java/com/protomaps/basemap/feature/CountryCoderTest.java b/tiles/src/test/java/com/protomaps/basemap/feature/CountryCoderTest.java index 1a43a285..3d1c9d1e 100644 --- a/tiles/src/test/java/com/protomaps/basemap/feature/CountryCoderTest.java +++ b/tiles/src/test/java/com/protomaps/basemap/feature/CountryCoderTest.java @@ -12,28 +12,42 @@ class CountryCoderTest { @Test void testLookupByPoint() throws IOException { CountryCoder c = CountryCoder.fromJsonString( - "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"country\":\"GB\",\"nameEn\":\"Great Britain\"},\"geometry\":{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0,0],[0,1],[1,1],[0,0]]]]}}]}"); - assertEquals(Optional.of("GB"), c.getCountryCode(newPoint(0.1, 0.1))); + "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"iso1A2\":\"GB\",\"nameEn\":\"Great Britain\"},\"geometry\":{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0,0],[0,1],[1,1],[0,0]]]]}}]}"); + assertEquals(Optional.of("GB"), c.getCountryCode(newPoint(0.1, 0.9))); + } + + @Test + void testLookupByPointActuallyContains() throws IOException { + CountryCoder c = CountryCoder.fromJsonString( + "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"iso1A2\":\"GB\",\"nameEn\":\"Great Britain\"},\"geometry\":{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0,0],[0,1],[1,1],[0,0]]]]}}]}"); + assertEquals(Optional.empty(), c.getCountryCode(newPoint(0.9, 0.1))); } @Test void testNullGeometry() throws IOException { CountryCoder c = CountryCoder.fromJsonString( - "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"country\":\"xx\",\"nameEn\":\"Iberia\"},\"geometry\":null}]}"); + "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"iso1A2\":\"xx\",\"nameEn\":\"Iberia\"},\"geometry\":null}]}"); assertEquals(Optional.empty(), c.getCountryCode(newPoint(0.1, 0.1))); } @Test void testNoGeometry() throws IOException { CountryCoder c = CountryCoder.fromJsonString( - "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"country\":\"xx\",\"nameEn\":\"Iberia\"}}]}"); + "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"iso1A2\":\"xx\",\"nameEn\":\"Iberia\"}}]}"); assertEquals(Optional.empty(), c.getCountryCode(newPoint(0.1, 0.1))); } @Test void testNoCountry() throws IOException { CountryCoder c = CountryCoder.fromJsonString( - "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"nameEn\":\"Iberia\"},\"geometry\":null}]}"); + "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"nameEn\":\"Iberia\"},\"geometry\":{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0,0],[0,1],[1,1],[0,0]]]]}}]}"); assertEquals(Optional.empty(), c.getCountryCode(newPoint(0.1, 0.1))); } + + @Test + void testDependency() throws IOException { + CountryCoder c = CountryCoder.fromJsonString( + "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"country\":\"GB\",\"nameEn\":\"Great Britain\"},\"geometry\":{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0,0],[0,1],[1,1],[0,0]]]]}}]}"); + assertEquals(Optional.of("GB"), c.getCountryCode(newPoint(0.1, 0.9))); + } }