From 62de454cf769e5bf2832f32d6b1f707860d442cf Mon Sep 17 00:00:00 2001 From: Michael Barry Date: Mon, 6 Feb 2023 06:02:56 -0500 Subject: [PATCH] Add `--boundary-osm-only` flag to use OSM instead of NE at low zooms (#71) --- .../org/openmaptiles/layers/Boundary.java | 15 +++++- .../org/openmaptiles/layers/BoundaryTest.java | 48 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/openmaptiles/layers/Boundary.java b/src/main/java/org/openmaptiles/layers/Boundary.java index a506e51..f20ee7e 100644 --- a/src/main/java/org/openmaptiles/layers/Boundary.java +++ b/src/main/java/org/openmaptiles/layers/Boundary.java @@ -120,6 +120,7 @@ public class Boundary implements private static final double COUNTRY_TEST_OFFSET = GeoUtils.metersToPixelAtEquator(0, 10) / 256d; private final Stats stats; private final boolean addCountryNames; + private final boolean onlyOsmBoundaries; // may be updated concurrently by multiple threads private final Map regionNames = new ConcurrentHashMap<>(); // need to synchronize updates to these shared data structures: @@ -134,6 +135,11 @@ public class Boundary implements "boundary layer: add left/right codes of neighboring countries", true ); + this.onlyOsmBoundaries = config.arguments().getBoolean( + "boundary_osm_only", + "boundary layer: only use OSM, even at low zoom levels", + false + ); this.stats = stats; } @@ -160,6 +166,9 @@ public class Boundary implements @Override public void processNaturalEarth(String table, SourceFeature feature, FeatureCollector features) { + if (onlyOsmBoundaries) { + return; + } boolean disputed = feature.getString("featurecla", "").startsWith("Disputed"); record BoundaryInfo(int adminLevel, int minzoom, int maxzoom) {} BoundaryInfo info = switch (table) { @@ -253,6 +262,9 @@ public class Boundary implements minAdminLevel <= 4 ? 5 : minAdminLevel <= 6 ? 9 : minAdminLevel <= 8 ? 11 : 12; + if (onlyOsmBoundaries && minAdminLevel <= 4) { + minzoom = minAdminLevel == 2 ? (maritime ? 4 : 0) : 1; + } if (addCountryNames && !regionIds.isEmpty()) { // save for later try { @@ -340,7 +352,8 @@ public class Boundary implements @Override public List postProcess(int zoom, List items) { - double minLength = config.minFeatureSize(zoom); + // only omit a segment if it is shorter than a pixel + double minLength = config.minFeatureSizeAtMaxZoom(); double tolerance = config.tolerance(zoom); return FeatureMerge.mergeLineStrings(items, attrs -> minLength, tolerance, BUFFER_SIZE); } diff --git a/src/test/java/org/openmaptiles/layers/BoundaryTest.java b/src/test/java/org/openmaptiles/layers/BoundaryTest.java index 4274b69..931371b 100644 --- a/src/test/java/org/openmaptiles/layers/BoundaryTest.java +++ b/src/test/java/org/openmaptiles/layers/BoundaryTest.java @@ -6,11 +6,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import com.onthegomap.planetiler.FeatureCollector; +import com.onthegomap.planetiler.config.Arguments; +import com.onthegomap.planetiler.config.PlanetilerConfig; import com.onthegomap.planetiler.geo.GeoUtils; import com.onthegomap.planetiler.geo.GeometryException; import com.onthegomap.planetiler.reader.SimpleFeature; +import com.onthegomap.planetiler.reader.SourceFeature; import com.onthegomap.planetiler.reader.osm.OsmElement; import com.onthegomap.planetiler.reader.osm.OsmReader; +import com.onthegomap.planetiler.stats.Stats; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -666,4 +670,48 @@ class BoundaryTest extends AbstractLayerTest { )), features); } + + FeatureCollector processOsmOnly(SourceFeature feature) { + var collector = featureCollectorFactory.get(feature); + new OpenMapTilesProfile(translations, PlanetilerConfig.from(Arguments.fromArgs("--boundary-osm-only=true")), + Stats.inMemory()).processFeature(feature, collector); + return collector; + } + + @Test + void testOsmBoundariesOnly() { + assertFeatures(0, List.of(), processOsmOnly(SimpleFeature.create( + newLineString(0, 0, 1, 1), + Map.of( + "featurecla", "International boundary (verify)" + ), + OpenMapTilesProfile.NATURAL_EARTH_SOURCE, + "ne_110m_admin_0_boundary_lines_land", + 0 + ))); + assertFeatures(0, List.of(), processOsmOnly(SimpleFeature.create( + newLineString(0, 0, 1, 1), + Map.of( + "min_zoom", 7d + ), + OpenMapTilesProfile.NATURAL_EARTH_SOURCE, + "ne_10m_admin_1_states_provinces_lines", + 0 + ))); + + var relation = new OsmElement.Relation(1); + relation.setTag("type", "boundary"); + relation.setTag("admin_level", "2"); + relation.setTag("boundary", "administrative"); + + assertFeatures(14, List.of(Map.of("_minzoom", 0)), + processOsmOnly(lineFeatureWithRelation(profile.preprocessOsmRelation(relation), Map.of()))); + + assertFeatures(14, List.of(Map.of("_minzoom", 4)), + processOsmOnly(lineFeatureWithRelation(profile.preprocessOsmRelation(relation), Map.of("maritime", 1)))); + + relation.setTag("admin_level", "4"); + assertFeatures(14, List.of(Map.of("_minzoom", 1)), + processOsmOnly(lineFeatureWithRelation(profile.preprocessOsmRelation(relation), Map.of()))); + } }