This is an automated email from the ASF dual-hosted git repository. bchapuis pushed a commit to branch gdal in repository https://gitbox.apache.org/repos/asf/incubator-baremaps.git
commit e7626452710c40bd9a4e0d976a6d25ffe2076736 Author: Bertil Chapuis <[email protected]> AuthorDate: Sun Oct 8 16:42:11 2023 +0200 Improve contour generation --- baremaps-core/pom.xml.versionsBackup | 177 +++++++++++ .../apache/baremaps/raster/ContourTileStore.java | 328 ++++++++++++++------- .../baremaps/vectortile/VectorTileEncoder.java | 4 +- basemap/config.js | 6 +- examples/contour/dem.xml | 29 -- examples/contour/style.json | 33 +-- examples/contour/tileset.json | 11 +- 7 files changed, 430 insertions(+), 158 deletions(-) diff --git a/baremaps-core/pom.xml.versionsBackup b/baremaps-core/pom.xml.versionsBackup new file mode 100644 index 00000000..fe924eec --- /dev/null +++ b/baremaps-core/pom.xml.versionsBackup @@ -0,0 +1,177 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to you under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.baremaps</groupId> + <artifactId>baremaps</artifactId> + <version>0.7.2-SNAPSHOT</version> + </parent> + + <artifactId>baremaps-core</artifactId> + + <dependencies> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.dataformat</groupId> + <artifactId>jackson-dataformat-csv</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.dataformat</groupId> + <artifactId>jackson-dataformat-yaml</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.datatype</groupId> + <artifactId>jackson-datatype-jdk8</artifactId> + </dependency> + <dependency> + <groupId>com.github.ben-manes.caffeine</groupId> + <artifactId>caffeine</artifactId> + </dependency> + <dependency> + <groupId>com.github.jsqlparser</groupId> + <artifactId>jsqlparser</artifactId> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protobuf-java</artifactId> + </dependency> + <dependency> + <groupId>com.zaxxer</groupId> + <artifactId>HikariCP</artifactId> + </dependency> + <dependency> + <groupId>de.bytefish</groupId> + <artifactId>pgbulkinsert</artifactId> + </dependency> + <dependency> + <groupId>it.unimi.dsi</groupId> + <artifactId>fastutil</artifactId> + </dependency> + <dependency> + <groupId>mil.nga.geopackage</groupId> + <artifactId>geopackage</artifactId> + </dependency> + <dependency> + <groupId>net.ripe.ipresource</groupId> + <artifactId>ipresource</artifactId> + </dependency> + <dependency> + <groupId>org.apache.calcite</groupId> + <artifactId>calcite-core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-compress</artifactId> + </dependency> + <dependency> + <groupId>org.apache.lucene</groupId> + <artifactId>lucene-core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.lucene</groupId> + <artifactId>lucene-expressions</artifactId> + </dependency> + <dependency> + <groupId>org.apache.lucene</groupId> + <artifactId>lucene-queryparser</artifactId> + </dependency> + <dependency> + <groupId>org.apache.lucene</groupId> + <artifactId>lucene-spatial-extras</artifactId> + </dependency> + <dependency> + <groupId>org.graalvm.js</groupId> + <artifactId>js</artifactId> + </dependency> + <dependency> + <groupId>org.graalvm.sdk</groupId> + <artifactId>graal-sdk</artifactId> + </dependency> + <dependency> + <groupId>org.locationtech.jts</groupId> + <artifactId>jts-core</artifactId> + </dependency> + <dependency> + <groupId>org.locationtech.proj4j</groupId> + <artifactId>proj4j</artifactId> + </dependency> + <!-- TODO: Remove this dependency due to license incompatibility --> + <dependency> + <groupId>org.locationtech.proj4j</groupId> + <artifactId>proj4j-epsg</artifactId> + </dependency> + <dependency> + <groupId>org.postgresql</groupId> + <artifactId>postgresql</artifactId> + </dependency> + <dependency> + <groupId>org.wololo</groupId> + <artifactId>flatgeobuf</artifactId> + <version>3.24.0</version> + </dependency> + <dependency> + <groupId>org.xerial</groupId> + <artifactId>sqlite-jdbc</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.xolstice.maven.plugins</groupId> + <artifactId>protobuf-maven-plugin</artifactId> + <version>${version.plugin.protobuf-maven-plugin}</version> + <extensions>true</extensions> + <executions> + <execution> + <goals> + <goal>compile</goal> + <goal>test-compile</goal> + </goals> + <configuration> + <protocArtifact>com.google.protobuf:protoc:3.19.3:exe:${os.detected.classifier}</protocArtifact> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + <extensions> + <extension> + <groupId>kr.motd.maven</groupId> + <artifactId>os-maven-plugin</artifactId> + <version>${version.plugin.os-maven-plugin}</version> + </extension> + </extensions> + </build> +</project> diff --git a/baremaps-core/src/main/java/org/apache/baremaps/raster/ContourTileStore.java b/baremaps-core/src/main/java/org/apache/baremaps/raster/ContourTileStore.java index 62d95ce8..bb5e98d0 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/raster/ContourTileStore.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/raster/ContourTileStore.java @@ -24,36 +24,30 @@ import org.gdal.gdal.Dataset; import org.gdal.gdal.WarpOptions; import org.gdal.gdal.gdal; import org.gdal.gdalconst.gdalconstConstants; +import org.gdal.ogr.FieldDefn; import org.gdal.ogr.ogr; import org.gdal.osr.SpatialReference; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.GeometryFactory; -import org.locationtech.jts.geom.LineString; -import org.locationtech.jts.simplify.DouglasPeuckerSimplifier; +import org.locationtech.jts.geom.*; import org.locationtech.jts.simplify.TopologyPreservingSimplifier; import org.locationtech.proj4j.ProjCoordinate; -import java.io.IOException; import java.nio.ByteBuffer; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Vector; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.IntStream; -import java.util.stream.LongStream; public class ContourTileStore implements TileStore, AutoCloseable { static { + // Register the gdal and ogr drivers gdal.AllRegister(); ogr.RegisterAll(); } - private final String dem = """ + /** + * The definition of the digital elevation model. + */ + private static final String DEM = """ <GDAL_WMS> <Service name="TMS"> <ServerUrl>https://s3.amazonaws.com/elevation-tiles-prod/geotiff/${z}/${x}/${y}.tif</ServerUrl> @@ -81,122 +75,247 @@ public class ContourTileStore implements TileStore, AutoCloseable { </GDAL_WMS> """; + + private static final Map<Integer, String> CONTOUR_LEVELS_BY_ZOOM_LEVELS_IN_METERS = IntStream.range(0, 20).mapToObj(zoomLevel -> { + var contourLevels = IntStream.range(1, 10000) + .mapToObj(i -> (double) i) + .filter(l -> { + if (zoomLevel <= 8) { + return l % 1000 == 0; + } else if (zoomLevel == 9) { + return l % 500 == 0; + } else if (zoomLevel == 10) { + return l % 200 == 0; + } else if (zoomLevel == 11) { + return l % 100 == 0; + } else if (zoomLevel == 12) { + return l % 50 == 0; + } else if (zoomLevel == 13) { + return l % 20 == 0; + } else if (zoomLevel == 14) { + return l % 10 == 0; + } else { + return false; + } + }) + .map(Object::toString) + .collect(Collectors.joining(",")); + return Map.entry(zoomLevel, contourLevels); + }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + private static final Map<Integer, String> CONTOUR_LEVELS_BY_ZOOM_LEVELS_IN_FEETS = IntStream.range(0, 20).mapToObj(zoomLevel -> { + var contourLevels = IntStream.range(1, 30000) + .mapToObj(i -> (double) i) + .filter(l -> { + if (zoomLevel <= 9) { + return l % 1000 == 0; + } else if (zoomLevel == 10) { + return l % 500 == 0; + } else if (zoomLevel == 11) { + return l % 200 == 0; + } else if (zoomLevel == 12) { + return l % 100 == 0; + } else if (zoomLevel == 13) { + return l % 50 == 0; + } else if (zoomLevel == 14) { + return l % 20 == 0; + } else { + return false; + } + }) + .map(l -> l * 0.3048) + .map(Object::toString) + .collect(Collectors.joining(",")); + return Map.entry(zoomLevel, contourLevels); + }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + private final Map<Integer, Dataset> datasets = new HashMap<>(); public ContourTileStore() { } - public Dataset initDataset(Integer zoom) { - var dem = this.dem.replace("<TileLevel>0</TileLevel>", "<TileLevel>" + zoom + "</TileLevel>"); + public Dataset initRasterDatasetAtZoomLevel(Integer zoom) { + var dem = DEM.replace("<TileLevel>0</TileLevel>", "<TileLevel>" + zoom + "</TileLevel>"); return gdal.Open(dem, gdalconstConstants.GA_ReadOnly); } - @Override - public synchronized ByteBuffer read(TileCoord tile) throws TileStoreException { - var dataset = datasets.computeIfAbsent(tile.z(), this::initDataset); - var sourceBand = dataset.GetRasterBand(1); - var envelope = tile.envelope(); - - // Transform the extent to the source projection + public ByteBuffer read(TileCoord tile) throws TileStoreException { + // Transform the tile envelope to the raster projection + var tileEnvelope = tile.envelope(); var transformer = GeometryUtils.coordinateTransform(4326, 3857); - var min = transformer.transform(new ProjCoordinate(envelope.getMinX(), envelope.getMinY()), + var rasterMin = transformer.transform( + new ProjCoordinate(tileEnvelope.getMinX(), tileEnvelope.getMinY()), new ProjCoordinate()); - var max = transformer.transform(new ProjCoordinate(envelope.getMaxX(), envelope.getMaxY()), + var rasterMax = transformer.transform( + new ProjCoordinate(tileEnvelope.getMaxX(), tileEnvelope.getMaxY()), new ProjCoordinate()); - var buffer = (max.x - min.x) / 4096 * 16; - - var targetEnvelope = new GeometryFactory().createPolygon(new Coordinate[]{ - new Coordinate(min.x, min.y), - new Coordinate(min.x, max.y), - new Coordinate(max.x, max.y), - new Coordinate(max.x, min.y), - new Coordinate(min.x, min.y) + var rasterBuffer = (rasterMax.x - rasterMin.x) / 4096 * 128; + var rasterEnvelope = new GeometryFactory().createPolygon(new Coordinate[]{ + new Coordinate(rasterMin.x, rasterMin.y), + new Coordinate(rasterMin.x, rasterMax.y), + new Coordinate(rasterMax.x, rasterMax.y), + new Coordinate(rasterMax.x, rasterMin.y), + new Coordinate(rasterMin.x, rasterMin.y) }); - var bufferedEnvelope = targetEnvelope.buffer(buffer); + var rasterEnvelopeWithBuffer = rasterEnvelope.buffer(rasterBuffer); - // Warp the raster to the requested extent - var rasterOptions = new WarpOptions(new Vector<>(List.of( + // Load the raster data for the tile into the memory + // The cache used by gdal is not thread safe, so we need to synchronize the access to the dataset + // Otherwise, some tiles would be corrupted + Dataset rasterDataset1; + synchronized (this) { + var dataset = datasets.computeIfAbsent(tile.z(), this::initRasterDatasetAtZoomLevel); + var rasterOptions1 = new WarpOptions(new Vector<>(List.of( + "-of", "MEM", + "-te", + Double.toString(rasterEnvelopeWithBuffer.getEnvelopeInternal().getMinX()), + Double.toString(rasterEnvelopeWithBuffer.getEnvelopeInternal().getMinY()), + Double.toString(rasterEnvelopeWithBuffer.getEnvelopeInternal().getMaxX()), + Double.toString(rasterEnvelopeWithBuffer.getEnvelopeInternal().getMaxY()), + "-te_srs", "EPSG:3857"))); + rasterDataset1 = gdal.Warp("", new Dataset[]{dataset}, rasterOptions1); + } + + // Reduce the resolution of the raster by a factor of 4 to remove artifacts + var rasterOptions2 = new WarpOptions(new Vector<>(List.of( "-of", "MEM", - "-te", Double.toString(bufferedEnvelope.getEnvelopeInternal().getMinX()), Double.toString(bufferedEnvelope.getEnvelopeInternal().getMinY()), - Double.toString(bufferedEnvelope.getEnvelopeInternal().getMaxX()), Double.toString(bufferedEnvelope.getEnvelopeInternal().getMaxY()), - "-te_srs", "EPSG:3857"))); - var rasterDataset = gdal.Warp("", new Dataset[]{dataset}, rasterOptions); - var rasterBand = rasterDataset.GetRasterBand(1); + "-ts", + String.valueOf(rasterDataset1.getRasterXSize() / 4), + String.valueOf(rasterDataset1.getRasterYSize() / 4), + "-r", "cubicspline"))); + var rasterDataset2 = gdal.Warp("", new Dataset[]{rasterDataset1}, rasterOptions2); - // Generate the contours - var wkt = rasterDataset.GetProjection(); - var srs = new SpatialReference(wkt); - var vectorDriver = ogr.GetDriverByName("Memory"); - var vectorDataSource = vectorDriver.CreateDataSource("vector"); - var vectorLayer = vectorDataSource.CreateLayer("vector", srs, ogr.wkbLineString, new Vector(List.of("ADVERTIZE_UTF8=YES"))); + // Increase the resolution of the raster by a factor of 2 to smooth the contours + var rasterOptions3 = new WarpOptions(new Vector<>(List.of( + "-of", "MEM", + "-ts", String.valueOf(rasterDataset1.getRasterXSize() * 2), String.valueOf(rasterDataset1.getRasterYSize() * 2), + "-r", "cubicspline"))); + var rasterDataset3 = gdal.Warp("", new Dataset[]{rasterDataset2}, rasterOptions3); - vectorLayer.CreateField(new org.gdal.ogr.FieldDefn("elevation", ogr.OFTReal)); + // Generate the contours in meters + var contourLevelsInMeters = CONTOUR_LEVELS_BY_ZOOM_LEVELS_IN_METERS.get(tile.z()); + var featuresInMeters = generateContours(rasterDataset3, rasterEnvelope, rasterEnvelopeWithBuffer, contourLevelsInMeters); - String levels = IntStream.range(1, 1000) - .mapToObj(i -> i * 10) - .filter(l -> { - if (tile.z() <= 4) { - return l == 1000 || l == 3000 || l == 5000 || l == 7000 || l == 9000; - } else if (tile.z() <= 8) { - return l % 800 == 0; - } else if (tile.z() == 9) { - return l % 400 == 0; - } else if (tile.z() == 10) { - return l % 400 == 0; - } else if (tile.z() == 11) { - return l % 200 == 0; - } else if (tile.z() == 12) { - return l % 200 == 0; - } else if (tile.z() == 13) { - return l % 100 == 0; - } else if (tile.z() == 14) { - return l % 50 == 0; - } else { - return false; - } - }) - .map(Object::toString) - .collect(Collectors.joining(",")); + // Generate the contours in feets + var contourLevelsInFeets = CONTOUR_LEVELS_BY_ZOOM_LEVELS_IN_FEETS.get(tile.z()); + var featuresInFeets = generateContours(rasterDataset3, rasterEnvelope, rasterEnvelopeWithBuffer, contourLevelsInFeets); + + // Release the resources + rasterDataset1.delete(); + rasterDataset2.delete(); + rasterDataset3.delete(); - gdal.ContourGenerateEx(rasterBand, vectorLayer, new Vector<>(List.of("ELEV_FIELD=elevation", "FIXED_LEVELS=" + levels))); + // Create the vector tile + return VectorTileFunctions + .asVectorTile(new VectorTile(List.of( + new Layer("contours_m", 4096, featuresInMeters), + new Layer("contours_ft", 4096, featuresInFeets)))); + } + + + public List<Feature> generateContours(Dataset rasterDataset, Geometry rasterEnvelope, Geometry rasterEnvelopeWithBuffer, String contourLevels) { + // Initialize the vector dataset and layer to store the contours + var vectorProjection = rasterDataset.GetProjection(); + var vectorSpatialReferenceSystem = new SpatialReference(vectorProjection); + var vectorMemoryDriver = ogr.GetDriverByName("Memory"); + var vectorDataSource = vectorMemoryDriver.CreateDataSource("vector"); + var vectorLayer = vectorDataSource.CreateLayer("vector", vectorSpatialReferenceSystem, ogr.wkbLineString, new Vector(List.of("ADVERTIZE_UTF8=YES"))); + vectorLayer.CreateField(new FieldDefn("elevation", ogr.OFTReal)); + + // Get the raster band to generate the contours from + var rasterBand = rasterDataset.GetRasterBand(1); + + // Generate the contours and store them in the vector layer + gdal.ContourGenerateEx(rasterBand, vectorLayer, new Vector<>(List.of("ELEV_FIELD=elevation", "FIXED_LEVELS=" + contourLevels))); // return the contours - var featureCount = vectorLayer.GetFeatureCount(); - var features = LongStream.range(0, featureCount).mapToObj(featureIndex -> { - var feature = vectorLayer.GetFeature(featureIndex); - var id = feature.GetFID(); - var properties = new HashMap<String, Object>(); - var fieldCount = feature.GetFieldCount(); - for (int i = 0; i < fieldCount; i++) { - var field = feature.GetFieldDefnRef(i); - var name = field.GetName(); - var value = feature.GetFieldAsString(name); - properties.put(name, value); - field.delete(); - } - var ref = feature.GetGeometryRef(); - var wkb = ref.ExportToWkb(); - var geometry = GeometryUtils.deserialize(wkb); - var tileGeometry = targetEnvelope.intersection(geometry); - var mvtGeometry = VectorTileFunctions - .asVectorTileGeom(tileGeometry, targetEnvelope.getEnvelopeInternal(), 4096, 0, true); - - feature.delete(); - return new Feature(id, properties, mvtGeometry); - }) - .filter(feature -> feature.getGeometry().getCoordinates().length >= 2) - .toList(); + var features = new ArrayList<Feature>(); + for (var i = 0; i < vectorLayer.GetFeatureCount(); i++) { + var vectorFeature = vectorLayer.GetFeature(i); - var vectorTile = VectorTileFunctions - .asVectorTile(new VectorTile(List.of(new Layer("contours", 4096, features)))); + // Get the feature id + var id = vectorFeature.GetFID(); + // Get the feature properties + var properties = new HashMap<String, Object>(); + for (int j = 0; j < vectorFeature.GetFieldCount(); j++) { + var field = vectorFeature.GetFieldDefnRef(j); + var name = field.GetName(); + var value = vectorFeature.GetFieldAsString(name); + + // Parse the elevation + if (name.equals("elevation")) { + var elevationInMeters = Double.parseDouble(value); + var elevationInFeet = Math.round(elevationInMeters * 3.28084 * 100) / 100.0; + properties.put("elevation_m", elevationInMeters); + properties.put("elevation_ft", elevationInFeet); + } + + // Release the field resources + field.delete(); + } + + // Get the wkb geometry + var vectorGeometry = vectorFeature.GetGeometryRef(); + var wkb = vectorGeometry.ExportToWkb(); + + // Release the geometry and feature resources + vectorGeometry.delete(); + vectorFeature.delete(); + + // Deserialize the wkb geometry and clip it to the raster envelope with buffer + var geometry = GeometryUtils.deserialize(wkb); + geometry = rasterEnvelopeWithBuffer.intersection(geometry); + + // Create the vector tile geometry with the correct buffer + var mvtGeometry = VectorTileFunctions + .asVectorTileGeom(geometry, rasterEnvelope.getEnvelopeInternal(), 4096, 128, true); + + // The following code is used to simplify the geometry at the tile boundaries, + // which is necessary to prevent artifacts from appearing at the intersections + // of the vector tiles. + + // Create the vector tile envelope to simplify the geometry at the tile boundaries + var mvtEnvelope = new GeometryFactory().createPolygon(new Coordinate[]{ + new Coordinate(0, 0), + new Coordinate(0, 4096), + new Coordinate(4096, 4096), + new Coordinate(4096, 0), + new Coordinate(0, 0) + }); + + // The tolerance to use when simplifying the geometry at the tile boundaries. + // This value is a good balance between preserving the accuracy of the geometry + // and minimizing the size of the vector tiles. + var tolerance = 10; + + // Simplify the inside of the vector tile at the tile boundaries + var insideGeom = mvtGeometry.intersection(mvtEnvelope); + var insideSimplifier = new TopologyPreservingSimplifier(insideGeom); + insideSimplifier.setDistanceTolerance(tolerance); + insideGeom = insideSimplifier.getResultGeometry(); + + // Simplify the outside of the vector tile at the tile boundaries + var outsideGeom = mvtGeometry.difference(mvtEnvelope); + var outsideSimplifier = new TopologyPreservingSimplifier(outsideGeom); + outsideSimplifier.setDistanceTolerance(tolerance); + outsideGeom = outsideSimplifier.getResultGeometry(); + + // Merge the simplified geometries back together + mvtGeometry = insideGeom.union(outsideGeom); + + // Add the feature to the list of features if it is valid and has more than one coordinate + if (mvtGeometry.isValid() && mvtGeometry.getCoordinates().length > 1) { + features.add(new Feature(id, properties, mvtGeometry)); + } + } + + // Release the resources vectorLayer.delete(); rasterBand.delete(); - rasterDataset.delete(); - sourceBand.delete(); - return vectorTile; + return features; } @Override @@ -218,5 +337,4 @@ public class ContourTileStore implements TileStore, AutoCloseable { var store = new ContourTileStore(); store.read(new TileCoord(8492, 5792, 14).parent()); } - } diff --git a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileEncoder.java b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileEncoder.java index 45a1d6d0..7dc93987 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileEncoder.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileEncoder.java @@ -58,7 +58,9 @@ public class VectorTileEncoder { */ public Tile encodeTile(VectorTile tile) { Tile.Builder builder = Tile.newBuilder(); - tile.getLayers().forEach(layer -> builder.addLayers(encodeLayer(layer))); + for (var layer : tile.getLayers()) { + builder.addLayers(encodeLayer(layer)); + } return builder.build(); } diff --git a/basemap/config.js b/basemap/config.js index 9b69b989..62263a13 100644 --- a/basemap/config.js +++ b/basemap/config.js @@ -17,8 +17,8 @@ export default { "host": "http://localhost:9000", "database": "jdbc:postgresql://localhost:5432/baremaps?&user=baremaps&password=baremaps", - "osmPbfUrl": "https://download.geofabrik.de/europe/switzerland-latest.osm.pbf", - "center": [6.6323, 46.5197], - "bounds": [6.02260949059, 45.7769477403, 10.4427014502, 47.8308275417], + "osmPbfUrl": "https://download.geofabrik.de/europe/new-york-latest.osm.pbf", + "center": [-74.0060, 40.7128], + "bounds": [-180, -85, 180, 85], "zoom": 14, } diff --git a/examples/contour/dem.xml b/examples/contour/dem.xml deleted file mode 100644 index ac8b8e1d..00000000 --- a/examples/contour/dem.xml +++ /dev/null @@ -1,29 +0,0 @@ -<GDAL_WMS> - <!-- - Generate contour lines for the planet. - gdal_contour -a elevation -nln contour -i 10 -f GPKG dem.xml dem.gpkg - --> - <Service name="TMS"> - <ServerUrl>https://s3.amazonaws.com/elevation-tiles-prod/geotiff/${z}/${x}/${y}.tif</ServerUrl> - </Service> - <DataWindow> - <UpperLeftX>-20037508.34</UpperLeftX> - <UpperLeftY>20037508.34</UpperLeftY> - <LowerRightX>20037508.34</LowerRightX> - <LowerRightY>-20037508.34</LowerRightY> - <TileLevel>0</TileLevel> - <TileCountX>1</TileCountX> - <TileCountY>1</TileCountY> - <YOrigin>top</YOrigin> - </DataWindow> - <Projection>EPSG:3857</Projection> - <BlockSizeX>512</BlockSizeX> - <BlockSizeY>512</BlockSizeY> - <BandsCount>1</BandsCount> - <DataType>Int16</DataType> - <ZeroBlockHttpCodes>403,404</ZeroBlockHttpCodes> - <DataValues> - <NoData>-32768</NoData> - </DataValues> - <Cache/> -</GDAL_WMS> \ No newline at end of file diff --git a/examples/contour/style.json b/examples/contour/style.json index 90d99d22..ff7e81d5 100644 --- a/examples/contour/style.json +++ b/examples/contour/style.json @@ -4,16 +4,6 @@ "baremaps" : { "type" : "vector", "url" : "http://localhost:9000/tiles.json" - }, - "dem": { - "type": "raster-dem", - "encoding": "terrarium", - "tiles": [ - "https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png" - ], - "tileSize": 256, - "maxzoom": 13, - "minzoom": 0 } }, "layers" : [ { @@ -23,24 +13,29 @@ "paint" : { "background-color" : "rgba(255, 255, 255, 1)" } - },{ - "id": "hills", - "type": "hillshade", - "source": "dem", - "paint": { - "hillshade-exaggeration": 0.25 + }, { + "id" : "contours_m", + "type" : "line", + "source" : "baremaps", + "source-layer" : "contours_m", + "layout" : { + "line-cap" : "round", + "line-join" : "round" + }, + "paint" : { + "line-color" : "rgba(0, 0, 0, 1)" } }, { - "id" : "contours", + "id" : "contours_ft", "type" : "line", "source" : "baremaps", - "source-layer" : "contours", + "source-layer" : "contours_ft", "layout" : { "line-cap" : "round", "line-join" : "round" }, "paint" : { - "line-color" : "rgba(181, 169, 152, 1)" + "line-color" : "rgba(100, 100, 100, 1)" } } ], "center" : [ 9.5554, 47.166 ], diff --git a/examples/contour/tileset.json b/examples/contour/tileset.json index 2d729bdb..baebaa18 100644 --- a/examples/contour/tileset.json +++ b/examples/contour/tileset.json @@ -11,7 +11,16 @@ "database": "jdbc:postgresql://localhost:5432/baremaps?&user=baremaps&password=baremaps", "vector_layers": [ { - "id": "contours", + "id": "contours_m", + "queries": [ + { + "minzoom": 0, + "maxzoom": 20 + } + ] + }, + { + "id": "contours_ft", "queries": [ { "minzoom": 0,
