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 f63e7f12ec6a6b17760931e3ae226ef4bcfe44e9 Author: Bertil Chapuis <[email protected]> AuthorDate: Sun Apr 23 12:44:02 2023 +0200 Serve contour tiles --- .../java/org/apache/baremaps/cli/map/Contour.java | 91 ++++++++++++++++++++++ .../main/java/org/apache/baremaps/cli/map/Map.java | 2 +- .../apache/baremaps/raster/ContourTileStore.java | 33 +++++--- .../org/apache/baremaps/vectortile/Feature.java | 8 +- .../baremaps/vectortile/VectorTileEncoder.java | 5 +- .../baremaps/vectortile/VectorTileUtils.java | 20 ++++- .../apache/baremaps/vectortile/VectorTileTest.java | 4 +- .../baremaps/vectortile/VectorTileViewer.java | 13 +++- .../apache/baremaps/server/ServerResources.java | 7 +- examples/contour/style.json | 4 +- examples/contour/tileset.json | 11 +-- 11 files changed, 160 insertions(+), 38 deletions(-) diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Contour.java b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Contour.java new file mode 100644 index 00000000..b301876b --- /dev/null +++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Contour.java @@ -0,0 +1,91 @@ +/* + * Licensed 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. + */ + +package org.apache.baremaps.cli.map; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.benmanes.caffeine.cache.CaffeineSpec; +import io.servicetalk.http.netty.HttpServers; +import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder; +import org.apache.baremaps.cli.Options; +import org.apache.baremaps.database.PostgresUtils; +import org.apache.baremaps.database.tile.PostgresTileStore; +import org.apache.baremaps.database.tile.TileCache; +import org.apache.baremaps.database.tile.TileStore; +import org.apache.baremaps.mvt.tileset.Tileset; +import org.apache.baremaps.raster.ContourTileStore; +import org.apache.baremaps.server.ConfigReader; +import org.apache.baremaps.server.CorsFilter; +import org.apache.baremaps.server.ServerResources; +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.server.ResourceConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import picocli.CommandLine.Command; +import picocli.CommandLine.Mixin; +import picocli.CommandLine.Option; + +import java.nio.file.Path; +import java.util.concurrent.Callable; + +import static io.servicetalk.data.jackson.jersey.ServiceTalkJacksonSerializerFeature.contextResolverFor; +import static org.apache.baremaps.server.DefaultObjectMapper.defaultObjectMapper; + +@Command(name = "contour", description = "Start a tile server with caching capabilities.") +public class Contour implements Callable<Integer> { + + private static final Logger logger = LoggerFactory.getLogger(Contour.class); + + @Option(names = {"--cache"}, paramLabel = "CACHE", description = "The caffeine cache directive.") + private String cache = ""; + + @Option(names = {"--tileset"}, paramLabel = "TILESET", description = "The tileset file.", + required = true) + private Path tileset; + + @Option(names = {"--style"}, paramLabel = "STYLE", description = "The style file.", + required = true) + private Path style; + + @Option(names = {"--host"}, paramLabel = "HOST", description = "The host of the server.") + private String host = "localhost"; + + @Option(names = {"--port"}, paramLabel = "PORT", description = "The port of the server.") + private int port = 9000; + + @Override + public Integer call() throws Exception { + var objectMapper = defaultObjectMapper(); + var tileStore = new ContourTileStore(); + + // Configure the application + var application = + new ResourceConfig().register(CorsFilter.class).register(ServerResources.class) + .register(contextResolverFor(objectMapper)).register(new AbstractBinder() { + @Override + protected void configure() { + bind(Contour.this.tileset).to(Path.class).named("tileset"); + bind(style).to(Path.class).named("style"); + bind(objectMapper).to(ObjectMapper.class); + bind(tileStore).to(TileStore.class); + } + }); + + var httpService = new HttpJerseyRouterBuilder().buildBlockingStreaming(application); + var serverContext = HttpServers.forPort(port).listenBlockingStreamingAndAwait(httpService); + + logger.info("Listening on {}", serverContext.listenAddress()); + + serverContext.awaitShutdown(); + return 0; + } +} diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java index 9ed602d0..e1d1a3e5 100644 --- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java +++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java @@ -18,7 +18,7 @@ import picocli.CommandLine; import picocli.CommandLine.Command; @Command(name = "map", description = "Map commands.", - subcommands = {Init.class, Export.class, Serve.class, Dev.class}, sortOptions = false) + subcommands = {Init.class, Export.class, Serve.class, Dev.class, Contour.class}, sortOptions = false) public class Map implements Runnable { @Override 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 9e2b093b..bd206eee 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 @@ -15,6 +15,7 @@ package org.apache.baremaps.raster; import java.nio.ByteBuffer; import java.nio.file.Paths; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.stream.IntStream; import java.util.stream.LongStream; @@ -24,6 +25,10 @@ import org.apache.baremaps.database.tile.TileStore; import org.apache.baremaps.database.tile.TileStoreException; import org.apache.baremaps.openstreetmap.utils.GeometryUtils; import org.apache.baremaps.openstreetmap.utils.ProjectionTransformer; +import org.apache.baremaps.vectortile.Feature; +import org.apache.baremaps.vectortile.Layer; +import org.apache.baremaps.vectortile.VectorTileEncoder; +import org.apache.baremaps.vectortile.VectorTileUtils; import org.gdal.gdal.Dataset; import org.gdal.gdal.WarpOptions; import org.gdal.gdal.gdal; @@ -31,6 +36,8 @@ 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.Envelope; +import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.util.GeometryTransformer; import org.locationtech.proj4j.ProjCoordinate; @@ -53,6 +60,12 @@ public class ContourTileStore implements TileStore, AutoCloseable { var sourceBand = sourceDataset.GetRasterBand(1); var envelope = tile.envelope(); + // Transform the extent to the source projection + var transformer = GeometryUtils.coordinateTransform(4326, 3857); + var min = transformer.transform(new ProjCoordinate(envelope.getMinX(), envelope.getMinY()), new ProjCoordinate()); + var max = transformer.transform(new ProjCoordinate(envelope.getMaxX(), envelope.getMaxY()), new ProjCoordinate()); + var targetEnvelope = new Envelope(min.x, max.x, min.y, max.y); + // Warp the raster to the requested extent var rasterOptions = new WarpOptions(new Vector<>(List.of( "-of", "MEM", @@ -62,30 +75,30 @@ public class ContourTileStore implements TileStore, AutoCloseable { var rasterBand = rasterDataset.GetRasterBand(1); // Generate the contours - //var wkt = rasterDataset.GetProjection(); - //var srs = new SpatialReference(wkt); - var srs = new SpatialReference("EPSG:4326"); + 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); - gdal.ContourGenerateEx(rasterBand, vectorLayer, new Vector<>(List.of("LEVEL_INTERVAL=" + 10))); + gdal.ContourGenerateEx(rasterBand, vectorLayer, new Vector<>(List.of("LEVEL_INTERVAL=" + 50))); // return the contours - var geometries = LongStream.range(0, vectorLayer.GetFeatureCount()) + var features = LongStream.range(0, vectorLayer.GetFeatureCount()) .mapToObj(vectorLayer::GetFeature) .map(feature -> feature.GetGeometryRef()) .map(geometry -> GeometryUtils.deserialize(geometry.ExportToWkb())) + .map(geometry -> VectorTileUtils.asVectorTileGeom(geometry, targetEnvelope, 4096, 0, true)) + .map(geometry -> new Feature(null, Map.of(), geometry)) .toList(); - var transformer = GeometryUtils.coordinateTransform(4326, 3857); - var min = transformer.transform(new ProjCoordinate(envelope.getMinX(), envelope.getMinY()), new ProjCoordinate()); - var max = transformer.transform(new ProjCoordinate(envelope.getMaxX(), envelope.getMaxY()), new ProjCoordinate()); + var vectorTile = VectorTileUtils.asVectorTile(new org.apache.baremaps.vectortile.Tile(List.of(new Layer("contours", 4096, features)))); + rasterBand.delete(); rasterDataset.delete(); sourceBand.delete(); - return null; + return vectorTile; } @Override @@ -106,7 +119,7 @@ public class ContourTileStore implements TileStore, AutoCloseable { public static void main(String[] args) throws Exception { var store = new ContourTileStore(); store.read(new Tile(8492, 5792, 14).parent()); - } + } } diff --git a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/Feature.java b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/Feature.java index c9d7dccb..71ba3fb9 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/Feature.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/Feature.java @@ -21,7 +21,7 @@ import org.locationtech.jts.geom.Geometry; */ public class Feature { - private long id; + private Long id; private Map<String, Object> tags; @@ -39,7 +39,7 @@ public class Feature { * @param tags The tags of the feature. * @param geometry The geometry of the feature. */ - public Feature(long id, Map<String, Object> tags, Geometry geometry) { + public Feature(Long id, Map<String, Object> tags, Geometry geometry) { this.id = id; this.tags = tags; this.geometry = geometry; @@ -50,7 +50,7 @@ public class Feature { * * @return The id of the feature. */ - public long getId() { + public Long getId() { return id; } @@ -59,7 +59,7 @@ public class Feature { * * @param id The id of the feature. */ - public void setId(long id) { + public void setId(Long id) { this.id = id; } 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 7dcad1f7..4e4b427d 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 @@ -120,9 +120,10 @@ public class VectorTileEncoder { cy = 0; VectorTile.Tile.Feature.Builder builder = VectorTile.Tile.Feature.newBuilder(); - builder.setId(feature.getId()); + if (feature.getId() != null) { + builder.setId(feature.getId()); + } builder.setType(encodeGeometryType(feature.getGeometry())); - encodeTag(feature.getTags(), builder::addTags); encodeGeometry(feature.getGeometry(), builder::addGeometry); diff --git a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileUtils.java b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileUtils.java index f3d48a29..3ab24f53 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileUtils.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileUtils.java @@ -88,10 +88,18 @@ public class VectorTileUtils { * @return The transformed tile */ public static ByteBuffer asVectorTile(Tile vectorTile) { - return new VectorTileEncoder() + ByteBuffer original = new VectorTileEncoder() .encodeTile(vectorTile) .toByteString() .asReadOnlyByteBuffer(); + + ByteBuffer clone = ByteBuffer.allocate(original.capacity()); + original.rewind();//copy from the beginning + clone.put(original); + original.rewind(); + clone.flip(); + + return clone; } /** @@ -101,10 +109,18 @@ public class VectorTileUtils { * @return The transformed layer */ public static ByteBuffer asVectorTileLayer(Layer layer) { - return new VectorTileEncoder() + ByteBuffer original = new VectorTileEncoder() .encodeLayer(layer) .toByteString() .asReadOnlyByteBuffer(); + + ByteBuffer clone = ByteBuffer.allocate(original.capacity()); + original.rewind();//copy from the beginning + clone.put(original); + original.rewind(); + clone.flip(); + + return clone; } /** diff --git a/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileTest.java b/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileTest.java index 1fb353bc..db66f294 100644 --- a/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileTest.java +++ b/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileTest.java @@ -36,9 +36,9 @@ public class VectorTileTest { public void endToEnd() { var tile = new Tile(List.of( new Layer("layer", 256, List.of( - new Feature(1, Map.of("a", 1.0, "b", "2"), + new Feature(1l, Map.of("a", 1.0, "b", "2"), GEOMETRY_FACTORY.createPoint(new Coordinate(1, 2))), - new Feature(2, Map.of("c", 3.0, "d", "4"), + new Feature(2l, Map.of("c", 3.0, "d", "4"), GEOMETRY_FACTORY.createPoint(new Coordinate(2, 3))))))); var encoded = new VectorTileEncoder().encodeTile(tile); diff --git a/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileViewer.java b/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileViewer.java index 079d70a1..349c666c 100644 --- a/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileViewer.java +++ b/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileViewer.java @@ -14,6 +14,7 @@ package org.apache.baremaps.vectortile; import java.awt.*; import java.awt.Dimension; +import java.net.URL; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; @@ -29,10 +30,14 @@ import org.locationtech.jts.geom.Polygon; public class VectorTileViewer { public static void main(String... args) throws Exception { - String arg = - args.length > 0 ? args[0] : "baremaps-core/src/test/resources/vectortile/14-8493-5795.mvt"; - var path = Path.of(arg); - try (var input = new GZIPInputStream(Files.newInputStream(path))) { +// String arg = +// args.length > 0 ? args[0] : "baremaps-core/src/test/resources/vectortile/14-8493-5795.mvt"; +// var path = Path.of(arg); +// try (var input = new GZIPInputStream(Files.newInputStream(path))) { + + var url = new URL("http://localhost:9000/tiles/14/8628/5750.mvt"); + + try (var input = url.openStream()) { var buffer = ByteBuffer.wrap(input.readAllBytes()); var parsed = org.apache.baremaps.mvt.binary.VectorTile.Tile.parseFrom(buffer); var tile = new VectorTileDecoder().decodeTile(parsed); diff --git a/baremaps-server/src/main/java/org/apache/baremaps/server/ServerResources.java b/baremaps-server/src/main/java/org/apache/baremaps/server/ServerResources.java index 0300046d..3a495ca9 100644 --- a/baremaps-server/src/main/java/org/apache/baremaps/server/ServerResources.java +++ b/baremaps-server/src/main/java/org/apache/baremaps/server/ServerResources.java @@ -85,9 +85,12 @@ public class ServerResources { try { ByteBuffer blob = tileStore.read(tile); if (blob != null) { + var array = blob.array(); return Response.status(200) // lgtm [java/xss] - .header(ACCESS_CONTROL_ALLOW_ORIGIN, "*").header(CONTENT_TYPE, TILE_TYPE) - .header(CONTENT_ENCODING, TILE_ENCODING).entity(blob.array()).build(); + .header(ACCESS_CONTROL_ALLOW_ORIGIN, "*") + .header(CONTENT_TYPE, TILE_TYPE) + //.header(CONTENT_ENCODING, TILE_ENCODING) + .entity(array).build(); } else { return Response.status(204).build(); } diff --git a/examples/contour/style.json b/examples/contour/style.json index 16047415..bb982ecc 100644 --- a/examples/contour/style.json +++ b/examples/contour/style.json @@ -14,10 +14,10 @@ "background-color" : "rgba(255, 255, 255, 1)" } }, { - "id" : "aster_dem", + "id" : "contours", "type" : "line", "source" : "baremaps", - "source-layer" : "aster_dem", + "source-layer" : "contours", "layout" : { "line-cap" : "round", "line-join" : "round" diff --git a/examples/contour/tileset.json b/examples/contour/tileset.json index 7999eb55..98108edf 100644 --- a/examples/contour/tileset.json +++ b/examples/contour/tileset.json @@ -5,23 +5,16 @@ 47.166, 14.0 ], - "bounds": [ - 9.471078, - 47.04774, - 9.636217, - 47.27128 - ], "tiles": [ "http://localhost:9000/tiles/{z}/{x}/{y}.mvt" ], "vector_layers": [ { - "id": "aster_dem", + "id": "contours", "queries": [ { "minzoom": 0, - "maxzoom": 20, - "sql": "SELECT ogc_fid, jsonb_build_object('elevation', elevation::text), wkb_geometry FROM aster_dem" + "maxzoom": 20 } ] }
