diff --git a/planetiler-core/src/main/java/com/onthegomap/planetiler/archive/TileArchiveWriter.java b/planetiler-core/src/main/java/com/onthegomap/planetiler/archive/TileArchiveWriter.java index 708f96e079..ee1e651dd9 100644 --- a/planetiler-core/src/main/java/com/onthegomap/planetiler/archive/TileArchiveWriter.java +++ b/planetiler-core/src/main/java/com/onthegomap/planetiler/archive/TileArchiveWriter.java @@ -220,7 +220,7 @@ private String getLastTileLogDetails() { lastTile.z(), lastTile.x(), lastTile.y(), lastTile.z(), Format.defaultInstance().percent(archive.tileOrder().progressOnLevel(lastTile, config.bounds().tileExtents())), - lastTile.getDebugUrl() + lastTile.getDebugUrl(config.debugUrlPattern()) ); } return "last tile: " + blurb; @@ -389,7 +389,7 @@ private void tileWriter(Iterable tileBatches) throws ExecutionExcepti private void printTileStats() { if (LOGGER.isDebugEnabled()) { Format format = Format.defaultInstance(); - tileStats.printStats(); + tileStats.printStats(config.debugUrlPattern()); LOGGER.debug(" # features: {}", format.integer(featuresProcessed.get())); } } diff --git a/planetiler-core/src/main/java/com/onthegomap/planetiler/config/PlanetilerConfig.java b/planetiler-core/src/main/java/com/onthegomap/planetiler/config/PlanetilerConfig.java index 959240fc0e..a04c6f6ce0 100644 --- a/planetiler-core/src/main/java/com/onthegomap/planetiler/config/PlanetilerConfig.java +++ b/planetiler-core/src/main/java/com/onthegomap/planetiler/config/PlanetilerConfig.java @@ -54,7 +54,8 @@ public record PlanetilerConfig( Boolean color, boolean keepUnzippedSources, TileCompression tileCompression, - boolean outputLayerStats + boolean outputLayerStats, + String debugUrlPattern ) { public static final int MIN_MINZOOM = 0; @@ -192,7 +193,9 @@ public static PlanetilerConfig from(Arguments arguments) { "the tile compression, one of " + TileCompression.availableValues().stream().map(TileCompression::id).toList(), "gzip")), - arguments.getBoolean("output_layerstats", "output a tsv.gz file for each tile/layer size", false) + arguments.getBoolean("output_layerstats", "output a tsv.gz file for each tile/layer size", false), + arguments.getString("debug_url", "debug url to use for displaying tiles with ${z} ${lat} ${lon} placeholders", + "https://onthegomap.github.io/planetiler-demo/#${z}/${lat}/${lon}") ); } diff --git a/planetiler-core/src/main/java/com/onthegomap/planetiler/geo/TileCoord.java b/planetiler-core/src/main/java/com/onthegomap/planetiler/geo/TileCoord.java index 902128805c..58144226af 100644 --- a/planetiler-core/src/main/java/com/onthegomap/planetiler/geo/TileCoord.java +++ b/planetiler-core/src/main/java/com/onthegomap/planetiler/geo/TileCoord.java @@ -2,9 +2,11 @@ import static com.onthegomap.planetiler.config.PlanetilerConfig.MAX_MAXZOOM; -import com.onthegomap.planetiler.util.Format; import com.onthegomap.planetiler.util.Hilbert; +import java.text.DecimalFormat; +import java.util.Map; import javax.annotation.concurrent.Immutable; +import org.apache.commons.text.StringSubstitutor; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.CoordinateXY; import org.locationtech.jts.geom.Envelope; @@ -126,19 +128,32 @@ public int compareTo(TileCoord o) { } /** Returns the latitude/longitude of the northwest corner of this tile. */ - public Coordinate getLatLon() { + public Envelope getEnvelope() { double worldWidthAtZoom = Math.pow(2, z); - return new CoordinateXY( + return new Envelope( GeoUtils.getWorldLon(x / worldWidthAtZoom), + GeoUtils.getWorldLon((x + 1) / worldWidthAtZoom), + GeoUtils.getWorldLat((y + 1) / worldWidthAtZoom), GeoUtils.getWorldLat(y / worldWidthAtZoom) ); } /** Returns a URL that displays the openstreetmap data for this tile. */ - public String getDebugUrl() { - Coordinate coord = getLatLon(); - return Format.osmDebugUrl(z, coord); + public String getDebugUrl(String pattern) { + Coordinate center = getEnvelope().centre(); + DecimalFormat format = new DecimalFormat("0.#####"); + String lat = format.format(center.y); + String lon = format.format(center.x); + String zoom = z + ".5"; + return StringSubstitutor.replace(pattern, Map.of( + "lat", lat, + "latitude", lat, + "lon", lon, + "longitude", lon, + "zoom", zoom, + "z", zoom + )); } /** Returns the pixel coordinate on this tile of a given latitude/longitude (assuming 256x256 px tiles). */ diff --git a/planetiler-core/src/main/java/com/onthegomap/planetiler/util/TileStats.java b/planetiler-core/src/main/java/com/onthegomap/planetiler/util/TileStats.java index 159820a38f..570981db44 100644 --- a/planetiler-core/src/main/java/com/onthegomap/planetiler/util/TileStats.java +++ b/planetiler-core/src/main/java/com/onthegomap/planetiler/util/TileStats.java @@ -46,6 +46,9 @@ public class TileStats { private static final int BATCH_SIZE = 1_000; + private static final int WARN_BYTES = 100_000; + private static final int ERROR_BYTES = 500_000; + private static final Logger LOGGER = LoggerFactory.getLogger(TileStats.class); private static final CsvMapper MAPPER = new CsvMapper(); @@ -155,7 +158,7 @@ record Batch(List tiles, CompletableFuture> stats) {} timer.stop(); if (LOGGER.isDebugEnabled()) { - tileStats.printStats(); + tileStats.printStats(config.debugUrlPattern()); } stats.printSummary(); } @@ -225,7 +228,7 @@ public static List computeTileStats(VectorTileProto.Tile proto) { return result; } - public void printStats() { + public void printStats(String debugUrlPattern) { if (LOGGER.isDebugEnabled()) { Summary result = summary(); var overallStats = result.get(); @@ -241,7 +244,7 @@ public void printStats() { tile.coord.x(), tile.coord.y(), formatter.storage(tile.size), - tile.coord.getDebugUrl(), + tile.coord.getDebugUrl(debugUrlPattern), tileBiggestLayers(formatter, tile) ); }).collect(Collectors.joining("\n")) @@ -249,7 +252,7 @@ public void printStats() { var alreadyListed = biggestTiles.stream().map(TileSummary::coord).collect(Collectors.toSet()); var otherTiles = result.layers().stream() .flatMap(layer -> result.get(layer).biggestTiles().stream().limit(1)) - .filter(tile -> !alreadyListed.contains(tile.coord) && tile.size > 100_000) + .filter(tile -> !alreadyListed.contains(tile.coord) && tile.size > WARN_BYTES) .toList(); if (!otherTiles.isEmpty()) { LOGGER.info("Other tiles with large layers:\n{}", @@ -259,7 +262,7 @@ public void printStats() { tile.coord.x(), tile.coord.y(), formatter.storage(tile.size), - tile.coord.getDebugUrl(), + tile.coord.getDebugUrl(debugUrlPattern), tileBiggestLayers(formatter, tile) )).collect(Collectors.joining("\n"))); } @@ -267,8 +270,8 @@ public void printStats() { LOGGER.debug("Max tile sizes:\n{}\n{}\n{}", writeStatsTable(result, n -> { String string = " " + formatter.storage(n, true); - return n.intValue() > 500_000 ? AnsiColors.red(string) : - n.intValue() > 100_000 ? AnsiColors.yellow(string) : + return n.intValue() > ERROR_BYTES ? AnsiColors.red(string) : + n.intValue() > WARN_BYTES ? AnsiColors.yellow(string) : string; }, SummaryCell::maxSize), writeStatsRow(result, "full tile", @@ -291,10 +294,9 @@ public void printStats() { } private static String tileBiggestLayers(Format formatter, TileSummary tile) { + int minSize = tile.layers.stream().mapToInt(l -> l.layerBytes).max().orElse(0); return tile.layers.stream() - .filter( - d -> d.layerBytes > Math.min(100_000, - tile.layers.stream().mapToInt(l -> l.layerBytes).max().orElse(0))) + .filter(d -> d.layerBytes >= minSize) .sorted(Comparator.comparingInt(d -> -d.layerBytes)) .map(d -> d.layer + ":" + formatter.storage(d.layerBytes)) .collect(Collectors.joining(", ")); diff --git a/planetiler-core/src/test/java/com/onthegomap/planetiler/geo/TileCoordTest.java b/planetiler-core/src/test/java/com/onthegomap/planetiler/geo/TileCoordTest.java index 433b126658..c1136a3852 100644 --- a/planetiler-core/src/test/java/com/onthegomap/planetiler/geo/TileCoordTest.java +++ b/planetiler-core/src/test/java/com/onthegomap/planetiler/geo/TileCoordTest.java @@ -120,4 +120,14 @@ void testTileProgressOnLevelHilbert(int x, int y, int z, double p) { TileExtents.computeFromWorldBounds(15, GeoUtils.WORLD_BOUNDS)); assertEquals(p, progress); } + + @ParameterizedTest + @CsvSource({ + "0,0,0,0.5/0/0", + "0,0,1,1.5/42.52556/-90", + "123,123,14,14.5/84.81142/-177.28638", + }) + void testDebugUrl(int x, int y, int z, String expected) { + assertEquals(expected, TileCoord.ofXYZ(x, y, z).getDebugUrl("${z}/${lat}/${lon}")); + } }