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 499a2381fbc3ed0599065202dcfe8a79dbc00348 Author: Bertil Chapuis <[email protected]> AuthorDate: Fri Mar 24 16:05:09 2023 +0100 WIP - experiment with gdal --- baremaps-core/pom.xml | 4 + .../apache/baremaps/raster/ContourTileStore.java | 94 ++++++++ .../main/java/org/apache/baremaps/raster/Main.java | 257 +++++++++++++++++++++ examples/contour/dem.xml | 29 +++ pom.xml | 6 + 5 files changed, 390 insertions(+) diff --git a/baremaps-core/pom.xml b/baremaps-core/pom.xml index fe924eec..4b83e635 100644 --- a/baremaps-core/pom.xml +++ b/baremaps-core/pom.xml @@ -118,6 +118,10 @@ limitations under the License. <groupId>org.graalvm.sdk</groupId> <artifactId>graal-sdk</artifactId> </dependency> + <dependency> + <groupId>org.gdal</groupId> + <artifactId>gdal</artifactId> + </dependency> <dependency> <groupId>org.locationtech.jts</groupId> <artifactId>jts-core</artifactId> 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 new file mode 100644 index 00000000..a352fa20 --- /dev/null +++ b/baremaps-core/src/main/java/org/apache/baremaps/raster/ContourTileStore.java @@ -0,0 +1,94 @@ +/* + * 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.raster; + +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.Vector; +import org.apache.baremaps.database.tile.Tile; +import org.apache.baremaps.database.tile.TileStore; +import org.apache.baremaps.database.tile.TileStoreException; +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; + +public class ContourTileStore implements TileStore { + @Override + public ByteBuffer read(Tile tile) throws TileStoreException { + var file = Paths.get(String.format("%s/%s/%s.tif", tile.z(), tile.x(), tile.y())); + var source = String.format("https://s3.amazonaws.com/elevation-tiles-prod/geotiff/%s", file); + + try { + Files.deleteIfExists(file); + Files.createDirectories(file.getParent()); + Files.createFile(file); + try (var stream = new URL(source).openStream()) { + Files.copy(stream, file); + } + } catch (Exception e) { + e.printStackTrace(); + } + + var dataset = gdal.Open(file.toString(), gdalconstConstants.GA_ReadOnly); + + dataset.GetGeoTransform(); + dataset.GetRasterXSize(); + dataset.GetRasterYSize(); + + + var band = dataset.GetRasterBand(1); + + band.ReadRaster_Direct(0, 0, 100, 100); + + var wkt = dataset.GetProjection(); + var srs = new SpatialReference(wkt); + + var driver = ogr.GetDriverByName("Memory"); + var dataSource = driver.CreateDataSource("memory_name"); + + var layer = dataSource.CreateLayer("contour", srs, ogr.wkbLineString); + + var field = new FieldDefn("ID", ogr.OFTInteger); + field.SetWidth(8); + layer.CreateField(field, 0); + field.delete(); + + gdal.ContourGenerateEx(band, layer, new Vector<>(List.of( + "LEVEL_INTERVAL=" + 10))); + + for (int i = 0; i < layer.GetFeatureCount(); i++) { + var feature = layer.GetFeature(i); + var geometry = feature.GetGeometryRef(); + // System.out.println(geometry.ExportToWkt()); + } + + dataSource.delete(); + dataset.delete(); + return null; + } + + @Override + public void write(Tile tile, ByteBuffer blob) throws TileStoreException { + throw new UnsupportedOperationException(); + } + + @Override + public void delete(Tile tile) throws TileStoreException { + throw new UnsupportedOperationException(); + } +} diff --git a/baremaps-core/src/main/java/org/apache/baremaps/raster/Main.java b/baremaps-core/src/main/java/org/apache/baremaps/raster/Main.java new file mode 100644 index 00000000..4e37b4d5 --- /dev/null +++ b/baremaps-core/src/main/java/org/apache/baremaps/raster/Main.java @@ -0,0 +1,257 @@ +/* + * 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.raster; + +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.List; +import java.util.Vector; +import org.gdal.gdal.*; +import org.gdal.gdalconst.gdalconstConstants; +import org.gdal.ogr.*; +import org.gdal.osr.SpatialReference; + +public class Main { + + public static void main(String[] args) { + + // var sourceFilename = Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857.tif") + // .toAbsolutePath().toString(); + // var hillshadeFilename = + // Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857-hillshade.tif").toAbsolutePath() + // .toString(); + // var outputFilename = Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857.shp") + // .toAbsolutePath().toString(); + // var warpFilename = Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857-warp.tif") + // .toAbsolutePath().toString(); + + + var dem = Paths.get("examples/contour/dem.xml") + .toAbsolutePath().toString(); + + gdal.AllRegister(); + ogr.RegisterAll(); + + planetContour("https://s3.amazonaws.com/elevation-tiles-prod/geotiff/%s/%s/%s.tif"); + + // hillshade(sourceFilename, 1, hillshadeFilename, 45d, 315d); + // contourEx(hillshadeFilename, 1, outputFilename, 50, 0); + // warp(sourceFilename, warpFilename); + // shadow(hillshadeFilename, outputFilename); + } + + public static void planetContour(String source) { + var file = Paths.get(String.format("%s/%s/%s.tif", 14, 8514, 5816)); + var url = String.format("https://s3.amazonaws.com/elevation-tiles-prod/geotiff/%s", file); + System.out.println(url); + + try { + Files.deleteIfExists(file); + Files.createDirectories(file.getParent()); + Files.createFile(file); + try (var stream = new URL(url).openStream()) { + Files.copy(stream, file, StandardCopyOption.REPLACE_EXISTING); + } + System.out.println(Files.size(file)); + } catch (Exception e) { + e.printStackTrace(); + } + + + var dataset = gdal.Open(file.toString(), gdalconstConstants.GA_ReadOnly); + + var band = dataset.GetRasterBand(1); + + band.ReadRaster_Direct(0, 0, 100, 100); + + var wkt = dataset.GetProjection(); + var srs = new SpatialReference(wkt); + + var driver = ogr.GetDriverByName("Memory"); + var dataSource = driver.CreateDataSource("memory_name"); + + var layer = dataSource.CreateLayer("contour", srs, ogr.wkbLineString); + + var field = new FieldDefn("ID", ogr.OFTInteger); + field.SetWidth(8); + layer.CreateField(field, 0); + field.delete(); + + gdal.ContourGenerateEx(band, layer, new Vector<>(List.of( + "LEVEL_INTERVAL=" + 10))); + + for (int i = 0; i < layer.GetFeatureCount(); i++) { + var feature = layer.GetFeature(i); + var geometry = feature.GetGeometryRef(); + System.out.println(geometry.ExportToWkt()); + } + + dataSource.delete(); + dataset.delete(); + } + + public static void contour(String source, Integer sourceBand, String target, + Integer contourInterval, + Integer contourBase) { + + var dataset = gdal.Open(source, gdalconstConstants.GA_ReadOnly); + var band = dataset.GetRasterBand(sourceBand); + var wkt = dataset.GetProjection(); + var srs = new SpatialReference(wkt); + + var driver = ogr.GetDriverByName("ESRI Shapefile"); + var dataSource = driver.CreateDataSource(target); + var layer = dataSource.CreateLayer("contour", srs, ogr.wkbLineString); + var field = new FieldDefn("ID", ogr.OFTInteger); + + field.SetWidth(8); + layer.CreateField(field, 0); + field.delete(); + + var feature = layer.GetLayerDefn(); + gdal.ContourGenerate(band, contourInterval, contourBase, null, + 0, 0, layer, feature.GetFieldIndex("ID"), + -1); + + dataSource.delete(); + dataset.delete(); + } + + public static void contourEx(String source, Integer sourceBand, String target, + Integer contourInterval, + Integer contourBase) { + + var dataset = gdal.Open(source, gdalconstConstants.GA_ReadOnly); + var band = dataset.GetRasterBand(sourceBand); + var wkt = dataset.GetProjection(); + var srs = new SpatialReference(wkt); + + var driver = ogr.GetDriverByName("ESRI Shapefile"); + var dataSource = driver.CreateDataSource(target); + var layer = dataSource.CreateLayer("contour", srs, ogr.wkbLineString); + var field = new FieldDefn("ID", ogr.OFTInteger); + + field.SetWidth(8); + layer.CreateField(field, 0); + field.delete(); + + gdal.ContourGenerateEx(band, layer, new Vector<>(List.of( + "LEVEL_BASE=" + contourBase, + "LEVEL_INTERVAL=" + contourInterval, + "POLYGONIZE=YES"))); + + dataSource.delete(); + dataset.delete(); + } + + public static void polygonize(String source, Integer sourceBand, String target) { + var dataset = gdal.Open(source, gdalconstConstants.GA_ReadOnly); + var band = dataset.GetRasterBand(sourceBand); + var wkt = dataset.GetProjection(); + var srs = new SpatialReference(wkt); + + var driver = ogr.GetDriverByName("ESRI Shapefile"); + var dataSource = driver.CreateDataSource(target); + var layer = dataSource.CreateLayer("polygonize", srs, ogr.wkbPolygon); + var field = new FieldDefn("ID", ogr.OFTInteger); + + field.SetWidth(8); + layer.CreateField(field, 0); + field.delete(); + + var feature = layer.GetLayerDefn(); + gdal.Polygonize(band, null, layer, feature.GetFieldIndex("ID"), + null, null); + + dataSource.delete(); + dataset.delete(); + } + + public static void warp(String source, String target) { + var dataset = gdal.Open(source, gdalconstConstants.GA_ReadOnly); + var transform = dataset.GetGeoTransform(); + var xRes = transform[1]; + var yRes = transform[5]; + + var options = new Vector<>(List.of( + "-tr", Double.toString(xRes * 10), Double.toString(yRes * 10))); + + var warp = gdal.Warp(target, new Dataset[] {dataset}, new WarpOptions(options)); + + warp.delete(); + dataset.delete(); + } + + + public record ShadowClass(int a, int b, int c) { + } + + private static final List<ShadowClass> shadowClasses = List.of( + new ShadowClass(1, 250, 255), + new ShadowClass(2, 240, 255), + new ShadowClass(3, 1, 150), + new ShadowClass(4, 1, 100), + new ShadowClass(5, 1, 65), + new ShadowClass(6, 1, 2)); + + private static void shadow(String source, String target) { + var dataset = gdal.Open(source, gdalconstConstants.GA_ReadOnly); + var band = dataset.GetRasterBand(1); + var wkt = dataset.GetProjection(); + var srs = new SpatialReference(wkt); + + var driver = ogr.GetDriverByName("ESRI Shapefile"); + var dataSource = driver.CreateDataSource(target); + + for (var shadowClass : shadowClasses) { + var layer = dataSource.CreateLayer("shadow-" + shadowClass.a(), srs, ogr.wkbPolygon); + var field = new FieldDefn("ID", ogr.OFTInteger); + + field.SetWidth(8); + layer.CreateField(field, 0); + field.delete(); + + gdal.ContourGenerateEx(band, layer, new Vector<>(List.of( + "LEVEL_BASE=" + shadowClass.b(), + "LEVEL_INTERVAL=" + shadowClass.c(), + "POLYGONIZE=YES"))); + } + + dataSource.delete(); + dataset.delete(); + + } + + + public static void hillshade(String source, Integer sourceBand, String target, Double azimuth, + Double altitude) { + var options = new Vector<>(List.of( + "-az", azimuth.toString(), + "-alt", altitude.toString(), + "-z", "1.0", + "-s", "1.0", + "-b", sourceBand.toString(), + "-of", "GTiff", + "-combined")); + + var dataset = gdal.Open(source, gdalconstConstants.GA_ReadOnly); + var hillshadeDataset = + gdal.DEMProcessing(target, dataset, "hillshade", null, new DEMProcessingOptions(options)); + + hillshadeDataset.delete(); + dataset.delete(); + } + +} diff --git a/examples/contour/dem.xml b/examples/contour/dem.xml new file mode 100644 index 00000000..178ca466 --- /dev/null +++ b/examples/contour/dem.xml @@ -0,0 +1,29 @@ +<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>14</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/pom.xml b/pom.xml index 83662488..e0d6812f 100644 --- a/pom.xml +++ b/pom.xml @@ -89,6 +89,7 @@ limitations under the License. <version.lib.commons-compress>1.21</version.lib.commons-compress> <version.lib.fastutil>8.5.9</version.lib.fastutil> <version.lib.flatgeobuf>3.24.0</version.lib.flatgeobuf> + <version.lib.gdal>3.6.3</version.lib.gdal> <version.lib.geopackage>6.5.0</version.lib.geopackage> <version.lib.graalvm>22.2.0</version.lib.graalvm> <version.lib.guava>31.1-jre</version.lib.guava> @@ -393,6 +394,11 @@ limitations under the License. <version>${version.lib.awaitability}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.gdal</groupId> + <artifactId>gdal</artifactId> + <version>${version.lib.gdal}</version> + </dependency> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId>
