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 f5fa44f5bb66aa4c18611eb7b141367a67e82320 Author: Bertil Chapuis <[email protected]> AuthorDate: Mon Sep 25 17:22:32 2023 +0200 Fix envelope and levels --- .../apache/baremaps/raster/ContourTileStore.java | 231 +++++++++++++-------- .../org/apache/baremaps/tilestore/TileCoord.java | 4 +- .../baremaps/database/calcite/CalciteTest.java | 1 - .../apache/baremaps/server/TilesetResource.java | 5 +- examples/contour/dem.xml | 2 +- 5 files changed, 149 insertions(+), 94 deletions(-) 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 5eeb5855..2aead3c5 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 @@ -12,12 +12,6 @@ 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.LongStream; import org.apache.baremaps.tilestore.TileCoord; import org.apache.baremaps.tilestore.TileStore; import org.apache.baremaps.tilestore.TileStoreException; @@ -32,91 +26,152 @@ import org.gdal.gdal.gdal; import org.gdal.gdalconst.gdalconstConstants; import org.gdal.ogr.ogr; import org.gdal.osr.SpatialReference; -import org.locationtech.jts.geom.Envelope; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; 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.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.LongStream; + public class ContourTileStore implements TileStore, AutoCloseable { - static { - gdal.AllRegister(); - ogr.RegisterAll(); - } - - private final Dataset sourceDataset; - - public ContourTileStore() { - var dem = Paths.get("dem.xml").toAbsolutePath().toString(); - sourceDataset = gdal.Open(dem, gdalconstConstants.GA_ReadOnly); - } - - @Override - public ByteBuffer read(TileCoord tile) throws TileStoreException { - 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", - "-te", Double.toString(envelope.getMinX()), Double.toString(envelope.getMinY()), - Double.toString(envelope.getMaxX()), Double.toString(envelope.getMaxY()), - "-te_srs", "EPSG:4326"))); - var rasterDataset = gdal.Warp("", new Dataset[] {sourceDataset}, rasterOptions); - var rasterBand = rasterDataset.GetRasterBand(1); - - // 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); - gdal.ContourGenerateEx(rasterBand, vectorLayer, new Vector<>(List.of("LEVEL_INTERVAL=" + 50))); - - // return the contours - var features = LongStream.range(0, vectorLayer.GetFeatureCount()) - .mapToObj(vectorLayer::GetFeature) - .map(feature -> feature.GetGeometryRef()) - .map(geometry -> GeometryUtils.deserialize(geometry.ExportToWkb())) - .map(geometry -> VectorTileFunctions.asVectorTileGeom(geometry, targetEnvelope, 4096, 0, - true)) - .map(geometry -> new Feature(null, Map.of(), geometry)) - .toList(); - - var vectorTile = VectorTileFunctions - .asVectorTile(new VectorTile(List.of(new Layer("contours", 4096, features)))); - - rasterBand.delete(); - rasterDataset.delete(); - sourceBand.delete(); - - return vectorTile; - } - - @Override - public void write(TileCoord tile, ByteBuffer blob) throws TileStoreException { - throw new UnsupportedOperationException(); - } - - @Override - public void delete(TileCoord tile) throws TileStoreException { - throw new UnsupportedOperationException(); - } - - @Override - public void close() throws Exception { - sourceDataset.delete(); - } - - public static void main(String[] args) throws Exception { - var store = new ContourTileStore(); - store.read(new TileCoord(8492, 5792, 14).parent()); - } + static { + gdal.AllRegister(); + ogr.RegisterAll(); + } + + private final Map<Integer, Dataset> datasets = new HashMap<>(); + + public ContourTileStore() { + } + + public Dataset initDataset(Integer zoom) { + try { + var dem = Files.readString(Paths.get("dem.xml")); + dem = dem.replace("<TileLevel>0</TileLevel>", "<TileLevel>" + zoom + "</TileLevel>"); + return gdal.Open(dem, gdalconstConstants.GA_ReadOnly); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + @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 + 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 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 bufferedEnvelope = targetEnvelope.buffer(buffer); + + // Warp the raster to the requested extent + var rasterOptions = 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); + + // 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); + + + String levels = IntStream.range(1, 1000) + .mapToObj(i -> i * 10) + .filter(l -> { + if (tile.z() <= 9) { + return l % 1000 == 0; + } else if (tile.z() <= 10) { + return l % 800 == 0; + } else if (tile.z() <= 11) { + return l % 400 == 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 l % 10 == 0; + } + }) + .map(Object::toString) + .collect(Collectors.joining(",")); + + gdal.ContourGenerateEx(rasterBand, vectorLayer, new Vector<>(List.of("FIXED_LEVELS=" + levels))); + + // return the contours + var geometries = LongStream.range(0, vectorLayer.GetFeatureCount()) + .mapToObj(vectorLayer::GetFeature) + .map(feature -> feature.GetGeometryRef()) + .map(geometry -> GeometryUtils.deserialize(geometry.ExportToWkb())) + .map(targetEnvelope::intersection) + .toList(); + + var features = geometries.stream() + .map(geometry -> VectorTileFunctions.asVectorTileGeom(geometry, targetEnvelope.getEnvelopeInternal(), 4096, 0, + true)) + .filter(geometry -> geometry.getCoordinates().length >= 2) + .map(geometry -> new Feature(null, Map.of(), geometry)) + .toList(); + + var vectorTile = VectorTileFunctions + .asVectorTile(new VectorTile(List.of(new Layer("contours", 4096, features)))); + + rasterBand.delete(); + rasterDataset.delete(); + sourceBand.delete(); + + return vectorTile; + } + + @Override + public void write(TileCoord tile, ByteBuffer blob) throws TileStoreException { + throw new UnsupportedOperationException(); + } + + @Override + public void delete(TileCoord tile) throws TileStoreException { + throw new UnsupportedOperationException(); + } + + @Override + public void close() throws Exception { + datasets.values().forEach(Dataset::delete); + } + + public static void main(String[] args) throws Exception { + var store = new ContourTileStore(); + store.read(new TileCoord(8492, 5792, 14).parent()); + } } diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tilestore/TileCoord.java b/baremaps-core/src/main/java/org/apache/baremaps/tilestore/TileCoord.java index 1953e634..c08505e7 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/tilestore/TileCoord.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/tilestore/TileCoord.java @@ -203,8 +203,8 @@ public final class TileCoord implements Comparable<TileCoord> { return new Envelope(x1, x2, y1, y2); } - public static double tile2lon(int x, int z) { - return x / Math.pow(2.0, z) * 360.0 - 180; + public static double tile2lon(double x, double z) { + return x / Math.pow(2.0, z) * 360.0 - 180.0; } public static double tile2lat(int y, int z) { diff --git a/baremaps-core/src/test/java/org/apache/baremaps/database/calcite/CalciteTest.java b/baremaps-core/src/test/java/org/apache/baremaps/database/calcite/CalciteTest.java index ed22aee5..ea32f16b 100644 --- a/baremaps-core/src/test/java/org/apache/baremaps/database/calcite/CalciteTest.java +++ b/baremaps-core/src/test/java/org/apache/baremaps/database/calcite/CalciteTest.java @@ -44,7 +44,6 @@ import org.locationtech.jts.geom.*; public class CalciteTest { - @Test public void test() throws SQLException { GeometryFactory geometryFactory = new GeometryFactory(); diff --git a/baremaps-server/src/main/java/org/apache/baremaps/server/TilesetResource.java b/baremaps-server/src/main/java/org/apache/baremaps/server/TilesetResource.java index d2434b84..2ebcb816 100644 --- a/baremaps-server/src/main/java/org/apache/baremaps/server/TilesetResource.java +++ b/baremaps-server/src/main/java/org/apache/baremaps/server/TilesetResource.java @@ -17,13 +17,14 @@ package org.apache.baremaps.server; -import java.util.function.Supplier; +import org.apache.baremaps.vectortile.tileset.Tileset; + import javax.inject.Inject; import javax.inject.Singleton; import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; -import org.apache.baremaps.vectortile.tileset.Tileset; +import java.util.function.Supplier; /** * A resource that provides access to the tileset file. Only suitable for development purposes, as diff --git a/examples/contour/dem.xml b/examples/contour/dem.xml index 178ca466..ac8b8e1d 100644 --- a/examples/contour/dem.xml +++ b/examples/contour/dem.xml @@ -11,7 +11,7 @@ <UpperLeftY>20037508.34</UpperLeftY> <LowerRightX>20037508.34</LowerRightX> <LowerRightY>-20037508.34</LowerRightY> - <TileLevel>14</TileLevel> + <TileLevel>0</TileLevel> <TileCountX>1</TileCountX> <TileCountY>1</TileCountY> <YOrigin>top</YOrigin>
