diff --git a/CHANGELOG.md b/CHANGELOG.md index b2f771d6..cab50a0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +Tiles 4.15.1 +------ +- Change to generic Geopackage source for Natural Earth via @mxzinke and @wipfli [#626] + Tiles 4.15.0 ------ - derive road shields from route relations instead of way `ref` tags diff --git a/tiles/src/main/java/com/protomaps/basemap/Basemap.java b/tiles/src/main/java/com/protomaps/basemap/Basemap.java index 28fcbbb8..a71ce5f7 100644 --- a/tiles/src/main/java/com/protomaps/basemap/Basemap.java +++ b/tiles/src/main/java/com/protomaps/basemap/Basemap.java @@ -134,7 +134,7 @@ public String description() { @Override public String version() { - return "4.15.0"; + return "4.15.1"; } @Override @@ -284,8 +284,8 @@ static void run(Arguments args) throws IOException { } var planetiler = Planetiler.create(args) - .addNaturalEarthSource("ne", sourcesDir.resolve("natural_earth_vector.sqlite.zip"), - "https://naciscdn.org/naturalearth/packages/natural_earth_vector.sqlite.zip"); + .addGeoPackageSource("ne", sourcesDir.resolve("natural_earth_vector.gpkg.zip"), + "https://naciscdn.org/naturalearth/packages/natural_earth_vector.gpkg.zip"); if (!overtureFile.isEmpty()) { Path base = args.inputFile("overture", "overture base directory", Path.of("data", "overture")); diff --git a/tiles/src/main/java/com/protomaps/basemap/layers/Boundaries.java b/tiles/src/main/java/com/protomaps/basemap/layers/Boundaries.java index fb9c1ade..8a1625fd 100644 --- a/tiles/src/main/java/com/protomaps/basemap/layers/Boundaries.java +++ b/tiles/src/main/java/com/protomaps/basemap/layers/Boundaries.java @@ -12,6 +12,7 @@ import com.protomaps.basemap.feature.FeatureId; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.OptionalInt; @SuppressWarnings("java:S1192") @@ -25,25 +26,40 @@ public String name() { return LAYER_NAME; } + /** + * Reads a Natural Earth attribute, falling back to the upper case spelling of the column. + *
+ * Column name casing is not consistent across the Natural Earth distributions: the sqlite package is entirely lower
+ * case, while the GeoPackage package preserves whatever the source shapefiles use. That is lower case for most
+ * physical layers but upper case for the admin layers this handler reads, and some tables mix both.
+ */
+ private static String getNeString(SourceFeature sf, String key) {
+ Object value = sf.getTag(key);
+ if (value == null) {
+ value = sf.getTag(key.toUpperCase(Locale.ROOT));
+ }
+ return value == null ? null : value.toString();
+ }
+
public void processNe(SourceFeature sf, FeatureCollector features) {
String sourceLayer = sf.getSourceLayer();
String kind = "";
int adminLevel = 2;
boolean disputed = false;
- int themeMinZoom = 0;
int themeMaxZoom = 0;
if (sourceLayer.equals("ne_10m_admin_0_boundary_lines_land") ||
sourceLayer.equals("ne_10m_admin_0_boundary_lines_map_units") ||
sourceLayer.equals("ne_10m_admin_0_boundary_lines_disputed_areas") ||
sourceLayer.equals("ne_10m_admin_1_states_provinces_lines")) {
- themeMinZoom = 4;
themeMaxZoom = 5;
kind = "tz_boundary";
}
+ String featureClass = getNeString(sf, "featurecla");
+
if (!kind.isEmpty()) {
- switch (sf.getString("featurecla")) {
+ switch (featureClass == null ? "" : featureClass) {
case "Disputed (please verify)" -> {
kind = "country";
disputed = true;
@@ -130,8 +146,10 @@ public void processNe(SourceFeature sf, FeatureCollector features) {
}
}
- if (sf.canBeLine() && sf.getString("min_zoom") != null && (!kind.isEmpty() && !kind.equals("tz_boundary"))) {
- var minZoom = Double.parseDouble(sf.getString("min_zoom")) - 1.0;
+ String minZoomString = getNeString(sf, "min_zoom");
+
+ if (sf.canBeLine() && minZoomString != null && (!kind.isEmpty() && !kind.equals("tz_boundary"))) {
+ var minZoom = Double.parseDouble(minZoomString) - 1.0;
int sortRank = 289 - (disputed ? 1 : 0);
features.line(this.name())
.setAttr("kind", kind)
@@ -139,10 +157,8 @@ public void processNe(SourceFeature sf, FeatureCollector features) {
.setAttr("sort_rank", sortRank)
.setSortKey(sortRank)
.setAttr("disputed", disputed ? true : null)
- .setAttr("brk_a3", sf.getString("brk_a3"))
- .setZoomRange(
- sf.getString("min_zoom") == null ? themeMinZoom : (int) minZoom,
- themeMaxZoom)
+ .setAttr("brk_a3", getNeString(sf, "brk_a3"))
+ .setZoomRange((int) minZoom, themeMaxZoom)
.setMinPixelSize(0)
.setBufferPixels(8);
}
diff --git a/tiles/src/test/java/com/protomaps/basemap/layers/BoundariesTest.java b/tiles/src/test/java/com/protomaps/basemap/layers/BoundariesTest.java
index 9f103599..16b071b6 100644
--- a/tiles/src/test/java/com/protomaps/basemap/layers/BoundariesTest.java
+++ b/tiles/src/test/java/com/protomaps/basemap/layers/BoundariesTest.java
@@ -1,7 +1,9 @@
package com.protomaps.basemap.layers;
import static com.onthegomap.planetiler.TestUtils.newLineString;
+import static com.onthegomap.planetiler.TestUtils.newPolygon;
+import com.onthegomap.planetiler.FeatureCollector;
import com.onthegomap.planetiler.reader.SimpleFeature;
import com.onthegomap.planetiler.reader.osm.OsmElement;
import com.onthegomap.planetiler.reader.osm.OsmReader;
@@ -11,6 +13,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.ValueSource;
class BoundariesTest extends LayerTest {
@Test
@@ -103,4 +106,159 @@ void testDisputedOsmWay(String key, String value) {
List.of(Map.of("disputed", true)),
collector);
}
+
+ private static final String NE_ADMIN_1_LINES = "ne_10m_admin_1_states_provinces_lines";
+
+ private FeatureCollector processNe(String sourceLayer, Map