From bc9890b0d321b8bc99adb84898e6db048d04bad0 Mon Sep 17 00:00:00 2001 From: Antoine Drabble Date: Wed, 4 Jan 2023 16:59:00 +0100 Subject: [PATCH 1/7] Make a first experiment with 3d tiles --- .run/tdtiles-create.run.xml | 11 + .run/tdtiles-serve.run.xml | 11 + .../org/apache/baremaps/cli/Baremaps.java | 3 +- .../apache/baremaps/cli/tdtiles/Serve.java | 71 ++++ .../apache/baremaps/cli/tdtiles/TdTiles.java | 28 ++ baremaps-core/pom.xml | 4 + .../apache/baremaps/tdtiles/GltfBuilder.java | 325 ++++++++++++++++++ .../apache/baremaps/tdtiles/TdTilesStore.java | 81 +++++ .../baremaps/tdtiles/building/Building.java | 7 + .../tdtiles/subtree/Availability.java | 4 + .../baremaps/tdtiles/subtree/Subtree.java | 7 + .../baremaps/server/TdTilesResources.java | 104 ++++++ .../src/main/resources/tdtiles/favicon.ico | Bin 0 -> 15086 bytes .../src/main/resources/tdtiles/index.html | 43 +++ .../src/main/resources/tdtiles/tileset.json | 24 ++ examples/tdtiles/README.md | 5 + examples/tdtiles/indexes.sql | 5 + examples/tdtiles/workflow.json | 42 +++ pom.xml | 5 + 19 files changed, 779 insertions(+), 1 deletion(-) create mode 100644 .run/tdtiles-create.run.xml create mode 100644 .run/tdtiles-serve.run.xml create mode 100644 baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java create mode 100644 baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/TdTiles.java create mode 100644 baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java create mode 100644 baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java create mode 100644 baremaps-core/src/main/java/org/apache/baremaps/tdtiles/building/Building.java create mode 100644 baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java create mode 100644 baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java create mode 100644 baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java create mode 100644 baremaps-server/src/main/resources/tdtiles/favicon.ico create mode 100644 baremaps-server/src/main/resources/tdtiles/index.html create mode 100644 baremaps-server/src/main/resources/tdtiles/tileset.json create mode 100644 examples/tdtiles/README.md create mode 100644 examples/tdtiles/indexes.sql create mode 100644 examples/tdtiles/workflow.json diff --git a/.run/tdtiles-create.run.xml b/.run/tdtiles-create.run.xml new file mode 100644 index 000000000..e795524c2 --- /dev/null +++ b/.run/tdtiles-create.run.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/.run/tdtiles-serve.run.xml b/.run/tdtiles-serve.run.xml new file mode 100644 index 000000000..67337bd73 --- /dev/null +++ b/.run/tdtiles-serve.run.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/Baremaps.java b/baremaps-cli/src/main/java/org/apache/baremaps/cli/Baremaps.java index e931ff656..0422684c4 100644 --- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/Baremaps.java +++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/Baremaps.java @@ -28,6 +28,7 @@ import org.apache.baremaps.cli.geocoder.Geocoder; import org.apache.baremaps.cli.iploc.IpLoc; import org.apache.baremaps.cli.map.Map; +import org.apache.baremaps.cli.tdtiles.TdTiles; import org.apache.baremaps.cli.workflow.Workflow; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.config.Configurator; @@ -38,7 +39,7 @@ @Command(name = "baremaps", description = "A toolkit for producing vector tiles.", versionProvider = VersionProvider.class, subcommands = {Workflow.class, Database.class, - Map.class, Geocoder.class, IpLoc.class}, + Map.class, TdTiles.class, Geocoder.class, IpLoc.class}, sortOptions = false) public class Baremaps implements Callable { diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java new file mode 100644 index 000000000..3ba449135 --- /dev/null +++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java @@ -0,0 +1,71 @@ +/* + * 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.tdtiles; + +import io.servicetalk.http.netty.HttpServers; +import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder; +import java.util.concurrent.Callable; +import org.apache.baremaps.cli.Options; +import org.apache.baremaps.database.PostgresUtils; +import org.apache.baremaps.server.CorsFilter; +import org.apache.baremaps.server.TdTilesResources; +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 javax.sql.DataSource; + +@Command(name = "serve", description = "Start a 3d tile server.") +public class Serve implements Callable { + + private static final Logger logger = LoggerFactory.getLogger(Serve.class); + + @Mixin + private Options options; + + @Option(names = {"--database"}, paramLabel = "DATABASE", + description = "The JDBC url of Postgres.", required = true) + private String database; + + @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 datasource = PostgresUtils.dataSource(database); + + // Configure the application + var application = + new ResourceConfig().register(CorsFilter.class).register(TdTilesResources.class).register(new AbstractBinder() { + @Override + protected void configure() { + bind(datasource).to(DataSource.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/tdtiles/TdTiles.java b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/TdTiles.java new file mode 100644 index 000000000..5ffcf186a --- /dev/null +++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/TdTiles.java @@ -0,0 +1,28 @@ +/* + * 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.tdtiles; + + + +import picocli.CommandLine; +import picocli.CommandLine.Command; + +@Command(name = "tdtiles", description = "3d Tiles commands.", subcommands = {Serve.class}, + sortOptions = false) +public class TdTiles implements Runnable { + + @Override + public void run() { + CommandLine.usage(this, System.out); + } +} diff --git a/baremaps-core/pom.xml b/baremaps-core/pom.xml index 2b40f1306..727539219 100644 --- a/baremaps-core/pom.xml +++ b/baremaps-core/pom.xml @@ -66,6 +66,10 @@ limitations under the License. de.bytefish pgbulkinsert + + de.javagl + jgltf-model-builder + it.unimi.dsi fastutil diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java new file mode 100644 index 000000000..b32bd6cf4 --- /dev/null +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java @@ -0,0 +1,325 @@ +/* + * 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.tdtiles; + +import de.javagl.jgltf.model.NodeModel; +import de.javagl.jgltf.model.creation.GltfModelBuilder; +import de.javagl.jgltf.model.creation.MaterialBuilder; +import de.javagl.jgltf.model.creation.MeshPrimitiveBuilder; +import de.javagl.jgltf.model.impl.*; +import de.javagl.jgltf.model.io.v2.GltfAssetV2; +import de.javagl.jgltf.model.io.v2.GltfAssetWriterV2; +import de.javagl.jgltf.model.io.v2.GltfAssetsV2; +import de.javagl.jgltf.model.v2.MaterialModelV2; +import org.apache.baremaps.tdtiles.building.Building; +import org.apache.commons.lang3.ArrayUtils; +import org.locationtech.jts.geom.*; +import org.locationtech.jts.geomgraph.Edge; +import org.locationtech.jts.math.Vector3D; +import org.locationtech.jts.triangulate.DelaunayTriangulationBuilder; + +import java.io.*; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.*; + +public class GltfBuilder { + + /** + * Create a node from a building. + * + * @param building + * @return + */ + public static NodeModel createNode(Building building, float tolerance) { + DelaunayTriangulationBuilder delaunayTriangulationBuilder = new DelaunayTriangulationBuilder(); + delaunayTriangulationBuilder.setSites(building.geometry()); + delaunayTriangulationBuilder.setTolerance(tolerance); + + float[] translation = cartesian3Degrees((float) building.geometry().getCoordinates()[0].y, (float) building.geometry().getCoordinates()[0].x, 0); + + Geometry triangulation = delaunayTriangulationBuilder.getTriangles(new GeometryFactory()); // initial triangulation + if(triangulation.getNumGeometries() == 0){ + return new DefaultNodeModel(); + } + + List vertices = new ArrayList<>(); + List indices = new ArrayList<>(); + List normals = new ArrayList<>(); + + createRoof(building, translation, triangulation, vertices, indices); + HashSet edges = getExteriorEdges(triangulation); + createWalls(building, translation, vertices, indices, edges); + createNormals(vertices, normals); + + MeshPrimitiveBuilder meshPrimitiveBuilder = + MeshPrimitiveBuilder.create(); + meshPrimitiveBuilder.setIntIndicesAsShort(IntBuffer.wrap(ArrayUtils.toPrimitive(indices.toArray(new Integer[0]), 0))); + meshPrimitiveBuilder.addPositions3D(FloatBuffer.wrap(ArrayUtils.toPrimitive(vertices.toArray(new Float[0]), 0.0F))); + meshPrimitiveBuilder.addNormals3D(FloatBuffer.wrap(ArrayUtils.toPrimitive(normals.toArray(new Float[0]), 0.0F))); + + DefaultMeshPrimitiveModel meshPrimitiveModel = + meshPrimitiveBuilder.build(); + + // Create a material, and assign it to the mesh primitive + MaterialBuilder materialBuilder = MaterialBuilder.create(); + materialBuilder.setBaseColorFactor(1f, 1f, 1f, 1.0f); + materialBuilder.setDoubleSided(false); + MaterialModelV2 materialModel = materialBuilder.build(); + materialModel.setMetallicFactor(0.0f); + materialModel.setOcclusionStrength(0.0f); + materialModel.setRoughnessFactor(1.0f); + meshPrimitiveModel.setMaterialModel(materialModel); + + // Create a mesh with the mesh primitive + DefaultMeshModel meshModel = new DefaultMeshModel(); + meshModel.addMeshPrimitiveModel(meshPrimitiveModel); + + // Create a node with the mesh + DefaultNodeModel nodeModel = new DefaultNodeModel(); + nodeModel.addMeshModel(meshModel); + //nodeModel.setScale(new float[]{5f,5f,5f}); + nodeModel.setTranslation(translation); + return nodeModel; + } + + /** + * Compute the normal for each vertex in the vertices array. + * Vertices are grouped by 3, so we can compute the normal for each triangle. + * The normal is the normalized cross product of the two vectors of the triangle. + * + * @param vertices + * @param normals + */ + private static void createNormals(List vertices, List normals) { + for (int i = 0; i < vertices.size(); i += 9) { + float[] v1 = new float[]{vertices.get(i), vertices.get(i + 1), vertices.get(i + 2)}; + float[] v2 = new float[]{vertices.get(i + 3), vertices.get(i + 4), vertices.get(i + 5)}; + float[] v3 = new float[]{vertices.get(i + 6), vertices.get(i + 7), vertices.get(i + 8)}; + float[] u = new float[]{v2[0] - v1[0], v2[1] - v1[1], v2[2] - v1[2]}; + float[] v = new float[]{v3[0] - v1[0], v3[1] - v1[1], v3[2] - v1[2]}; + float[] normal = new float[]{u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]}; + float length = (float) Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]); + normal[0] /= length; + normal[1] /= length; + normal[2] /= length; + normals.add(normal[0]); + normals.add(normal[1]); + normals.add(normal[2]); + normals.add(normal[0]); + normals.add(normal[1]); + normals.add(normal[2]); + normals.add(normal[0]); + normals.add(normal[1]); + normals.add(normal[2]); + } + } + + /** + * Iterate over the edges and extrude them to create the walls based on the build height. + * + * @param building + * @param translation + * @param vertices + * @param indices + * @param edges the exterior edges + */ + private static void createWalls(Building building, float[] translation, List vertices, List indices, HashSet edges) { + for (Edge edge : edges) { + Coordinate[] v = edge.getCoordinates(); + + float[] pos0 = cartesian3Degrees((float)v[0].getY(), (float)v[0].getX(), 0); + pos0[0] -= translation[0]; + pos0[1] -= translation[1]; + pos0[2] -= translation[2]; + float[] pos1 = cartesian3Degrees((float)v[1].getY(), (float)v[1].getX(), 0); + pos1[0] -= translation[0]; + pos1[1] -= translation[1]; + pos1[2] -= translation[2]; + float[] pos2 = cartesian3Degrees((float)v[0].getY(), (float)v[0].getX(), building.height()); + pos2[0] -= translation[0]; + pos2[1] -= translation[1]; + pos2[2] -= translation[2]; + float[] pos3 = cartesian3Degrees((float)v[1].getY(), (float)v[1].getX(), building.height()); + pos3[0] -= translation[0]; + pos3[1] -= translation[1]; + pos3[2] -= translation[2]; + + indices.add(vertices.size()/3); + vertices.add(pos0[0]); + vertices.add(pos0[1]); + vertices.add(pos0[2]); + indices.add(vertices.size()/3); + vertices.add(pos1[0]); + vertices.add(pos1[1]); + vertices.add(pos1[2]); + indices.add(vertices.size()/3); + vertices.add(pos2[0]); + vertices.add(pos2[1]); + vertices.add(pos2[2]); + + indices.add(vertices.size()/3); + vertices.add(pos2[0]); + vertices.add(pos2[1]); + vertices.add(pos2[2]); + indices.add(vertices.size()/3); + vertices.add(pos1[0]); + vertices.add(pos1[1]); + vertices.add(pos1[2]); + indices.add(vertices.size()/3); + vertices.add(pos3[0]); + vertices.add(pos3[1]); + vertices.add(pos3[2]); + } + } + + /** + * Get a list of exterior edges from the building geometry. The exterior edges are the ones that are not shared by two + * triangles. + * @param triangulation + * @return + */ + private static HashSet getExteriorEdges(Geometry triangulation) { + HashSet edges = new HashSet<>(triangulation.getNumGeometries() * 3, 1.0f); + for (int i = 0; i < triangulation.getNumGeometries(); i++) { + Geometry triangle = triangulation.getGeometryN(i); + Coordinate corner1 = triangle.getCoordinates()[0]; + Coordinate corner2 = triangle.getCoordinates()[1]; + Coordinate corner3 = triangle.getCoordinates()[2]; + Edge edge1 = new Edge(new Coordinate[]{corner1, corner2}); + if(edges.contains(edge1)){ + edges.remove(edge1); + } else { + edges.add(edge1); + } + Edge edge2 = new Edge(new Coordinate[]{corner2, corner3}); + if(edges.contains(edge2)){ + edges.remove(edge2); + } else { + edges.add(edge2); + } + Edge edge3 = new Edge(new Coordinate[]{corner3, corner1}); + if(edges.contains(edge3)){ + edges.remove(edge3); + } else { + edges.add(edge3); + } + } + return edges; + } + + /** + * Create the roof geometry. This is simply the triangulation of the building geometry at the building height. + * + * @param building + * @param translation + * @param triangulation + * @param vertices + * @param indices + */ + private static void createRoof(Building building, float[] translation, Geometry triangulation, List vertices, List indices) { + for (int i = 0; i < triangulation.getNumGeometries(); i++) { + Geometry triangle = triangulation.getGeometryN(i); + Coordinate corner1 = triangle.getCoordinates()[0]; + Coordinate corner2 = triangle.getCoordinates()[1]; + Coordinate corner3 = triangle.getCoordinates()[2]; + + float[] pos0 = cartesian3Degrees((float) corner1.y, (float) corner1.x, building.height()); + pos0[0] -= translation[0]; + pos0[1] -= translation[1]; + pos0[2] -= translation[2]; + float[] pos1 = cartesian3Degrees((float) corner2.y, (float) corner2.x, building.height()); + pos1[0] -= translation[0]; + pos1[1] -= translation[1]; + pos1[2] -= translation[2]; + float[] pos2 = cartesian3Degrees((float) corner3.y, (float) corner3.x, building.height()); + pos2[0] -= translation[0]; + pos2[1] -= translation[1]; + pos2[2] -= translation[2]; + + indices.add(vertices.size() / 3); + vertices.add(pos0[0]); + vertices.add(pos0[1]); + vertices.add(pos0[2]); + indices.add(vertices.size() / 3); + vertices.add(pos1[0]); + vertices.add(pos1[1]); + vertices.add(pos1[2]); + indices.add(vertices.size() / 3); + vertices.add(pos2[0]); + vertices.add(pos2[1]); + vertices.add(pos2[2]); + } + } + + /** + * Create a GLB from a list of nodes. + * + * @param nodes + * @return + * @throws Exception + */ + public static byte[] createGltf(List nodes) throws Exception { + DefaultSceneModel sceneModel = new DefaultSceneModel(); + + for (NodeModel node : nodes) { + sceneModel.addNode(node); + } + + GltfModelBuilder gltfModelBuilder = GltfModelBuilder.create(); + gltfModelBuilder.addSceneModel(sceneModel); + DefaultGltfModel gltfModel = gltfModelBuilder.build(); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + GltfAssetV2 asset = GltfAssetsV2.createEmbedded(gltfModel); + + GltfAssetWriterV2 gltfAssetWriter = new GltfAssetWriterV2(); + gltfAssetWriter.writeBinary(asset, outputStream); + + return outputStream.toByteArray(); + } + + /** + * Returns a Cartesian3 position from longitude and latitude values given in radians. + * Port of CesiumGS + * + * @param latitude in radians + * @param longitude in radians + * @param height in meters above the ellipsoid. + * @return The position + */ + public static float[] cartesian3FromRadians(float latitude, float longitude, float height) { + Vector3D wgs84RadiiSquared = new Vector3D(6378137.0f * 6378137.0f, 6378137.0f * 6378137.0f, 6356752.3142451793f * 6356752.3142451793f); + double cosLatitude = Math.cos(latitude); + Vector3D scratchN = new Vector3D(cosLatitude * Math.cos(longitude), cosLatitude * Math.sin(longitude), Math.sin(latitude)).normalize(); + Vector3D scratchK = new Vector3D(wgs84RadiiSquared.getX() * scratchN.getX(), wgs84RadiiSquared.getY() * scratchN.getY(), wgs84RadiiSquared.getZ() * scratchN.getZ()); + double gamma = Math.sqrt(scratchN.dot(scratchK)); + scratchK = scratchK.divide(gamma); + scratchN = new Vector3D(scratchN.getX() * height, scratchN.getY() * height, scratchN.getZ() * height); + Vector3D result = scratchK.add(scratchN); + return new float[]{(float) result.getX(), (float) result.getZ(), -(float) result.getY()}; + } + + /** + * Returns a Cartesian3 position from longitude and latitude values given in degrees. + * Port of CesiumGS + * + * @param latitude in degrees + * @param longitude in degrees + * @param height in meters above the ellipsoid. + * @return The position + */ + public static float[] cartesian3Degrees(float latitude, float longitude, float height) { + return cartesian3FromRadians(latitude * (float) Math.PI / 180, longitude * (float) Math.PI / 180, height); + } +} diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java new file mode 100644 index 000000000..044206a14 --- /dev/null +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java @@ -0,0 +1,81 @@ +/* + * 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.tdtiles; + + +import org.apache.baremaps.database.tile.*; +import org.apache.baremaps.openstreetmap.utils.GeometryUtils; +import org.apache.baremaps.tdtiles.building.Building; +import org.locationtech.jts.geom.Geometry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.*; + +/** + * A read-only {@code TileStore} implementation that uses the PostgreSQL to generate 3d tiles. + */ +public class TdTilesStore { + + private static final Logger logger = LoggerFactory.getLogger(TdTilesStore.class); + private static final String QUERY = + "select st_asbinary(geom), tags -> 'buildings:height', tags -> 'height', tags -> 'buildings:levels' from osm_ways where tags ? 'building' and st_intersects( st_force3d(geom,0), st_makeenvelope(%1$s, %2$s, %3$s, %4$s, 4326)) LIMIT %5$s"; + + + private final DataSource datasource; + + public TdTilesStore(DataSource datasource) { + this.datasource = datasource; + } + + public List read(float xmin, float xmax, float ymin, float ymax, int limit) throws TileStoreException { + try (Connection connection = datasource.getConnection(); + Statement statement = connection.createStatement()) { + + String sql = String.format(QUERY, ymin * 180 / (float)Math.PI, xmin * 180 / (float)Math.PI, ymax * 180 / (float)Math.PI, xmax * 180 / (float)Math.PI, limit); + logger.debug("Executing query: {}", sql); + + List buildings = new ArrayList<>(); + + try (ResultSet resultSet = statement.executeQuery(sql)) { + while (resultSet.next()) { + byte[] bytes = resultSet.getBytes(1); + Geometry geometry = GeometryUtils.deserialize(bytes); + + String buildingHeight = resultSet.getString(2); + String height = resultSet.getString(3); + String buildingLevels = resultSet.getString(4); + float finalHeight = 10; + if(buildingHeight != null) { + finalHeight = Float.parseFloat(buildingHeight.replaceAll("[^0-9]", "")); + } else if(height != null) { + finalHeight = Float.parseFloat(height.replaceAll("[^0-9]", "")); + } else if(buildingLevels != null) { + finalHeight = Float.parseFloat(buildingLevels.replaceAll("[^0-9]", "")) * 3; + } + + buildings.add(new Building(geometry, finalHeight)); + } + } + return buildings; + } catch (SQLException e) { + throw new TileStoreException(e); + } + } + +} diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/building/Building.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/building/Building.java new file mode 100644 index 000000000..3eafff701 --- /dev/null +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/building/Building.java @@ -0,0 +1,7 @@ +package org.apache.baremaps.tdtiles.building; + +import org.locationtech.jts.geom.Geometry; + +public record Building(Geometry geometry, float height) { + +} diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java new file mode 100644 index 000000000..a6ef848d9 --- /dev/null +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java @@ -0,0 +1,4 @@ +package org.apache.baremaps.tdtiles.subtree; + +public record Availability(boolean constant) { +} \ No newline at end of file diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java new file mode 100644 index 000000000..ff48f0c06 --- /dev/null +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java @@ -0,0 +1,7 @@ +package org.apache.baremaps.tdtiles.subtree; + +public record Subtree(Availability tileAvailability, + Availability contentAvailability, + Availability childSubtreeAvailability) { + +} \ No newline at end of file diff --git a/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java new file mode 100644 index 000000000..7b0e61a47 --- /dev/null +++ b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java @@ -0,0 +1,104 @@ +/* + * 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.server; + +import static com.google.common.net.HttpHeaders.*; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.sql.DataSource; +import javax.ws.rs.GET; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import de.javagl.jgltf.model.NodeModel; +import org.apache.baremaps.tdtiles.TdTilesStore; +import org.apache.baremaps.tdtiles.building.Building; +import org.apache.baremaps.tdtiles.GltfBuilder; +import org.apache.baremaps.tdtiles.subtree.Availability; +import org.apache.baremaps.tdtiles.subtree.Subtree; + +@Singleton +@javax.ws.rs.Path("/") +public class TdTilesResources { + private final TdTilesStore tdTilesStore; + + @Inject + public TdTilesResources(DataSource dataSource) { + this.tdTilesStore = new TdTilesStore(dataSource); + } + + @GET + @javax.ws.rs.Path("/subtrees/{level}.{x}.{y}.json") + public Response getSubtree(@PathParam("level") int level, @PathParam("x") int x, + @PathParam("y") int y) { + if (level == 18) { + return Response.ok().entity(new Subtree(new Availability(false),new Availability(true),new Availability(false))).header(CONTENT_TYPE, "application/json").build(); + } + return Response.ok().entity(new Subtree(new Availability(true),new Availability(true),new Availability(true))).header(CONTENT_TYPE, "application/json").build(); + } + + @GET + @javax.ws.rs.Path("/content/content_{level}__{x}_{y}.glb") + public Response getContent(@PathParam("level") int level, @PathParam("x") int x, + @PathParam("y") int y) throws Exception { + float[] coords = xyzToLatLonRadians(x, y, level); + int limit = level > 17 ? 1000 : 80; + List buildings = tdTilesStore.read(coords[0],coords[1],coords[2],coords[3], limit); + List nodes = new ArrayList<>(); + for (Building building : buildings) { + float tolerance = level > 17 ? 0.00001f : level >= 16 ? 0.0001f : 0.0003f; + nodes.add(GltfBuilder.createNode(building, tolerance)); + } + return Response.ok().entity( + GltfBuilder.createGltf(nodes) + ).build(); + } + + public static float[] xyzToLatLonRadians(int x, int y, int z) { + float[] answer = new float[4]; + int subdivision = 1 << z; + float yWidth = (float)Math.PI / subdivision; + float xWidth = 2 * (float)Math.PI / subdivision; + answer[0] = - (float)Math.PI / 2 + y * yWidth; // Lon + answer[1] = answer[0] + yWidth; // Lon max + answer[2] = - (float)Math.PI + xWidth * x; // Lat + answer[3] = answer[2] + xWidth; // Lat max + // Clamp to -PI/2 to PI/2 + answer[0] = Math.max(- (float)Math.PI / 2, Math.min((float)Math.PI / 2, answer[0])); + answer[1] = Math.max(- (float)Math.PI / 2, Math.min((float)Math.PI / 2, answer[1])); + // Clamp to -PI to PI + answer[2] = Math.max(- (float)Math.PI, Math.min((float)Math.PI, answer[2])); + answer[3] = Math.max(- (float)Math.PI, Math.min((float)Math.PI, answer[3])); + return answer; + } + + @GET + @javax.ws.rs.Path("/{path:.*}") + public Response get(@PathParam("path") String path) { + if (path.equals("") || path.endsWith("/")) { + path += "index.html"; + } + path = String.format("tdtiles/%s", path); + try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path)) { + var bytes = inputStream.readAllBytes(); + return Response.ok().entity(bytes).build(); + } catch (IOException e) { + return Response.status(404).build(); + } + } +} diff --git a/baremaps-server/src/main/resources/tdtiles/favicon.ico b/baremaps-server/src/main/resources/tdtiles/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7162b07e37bb49d44454fb9d82aaa73053343034 GIT binary patch literal 15086 zcmeI2ZHQGx7=X{Jc}vo@3@R(#?1K_YF{vy?!H|OJM@b_6CHwtGDO5yR)5+=ic4BZdq_%c$_)s%*Q+L zymw~aS)-^b8W@cqACcBXZ(bHf*G5rPQ`7Z4Jc@SnZaAsm=M9RYdJ0@Y8LCA0fbWZP zX=jrCn^_>UKxTo=0+|I;EHI6C55PFcL4OLnQ*;U31&d%VOn@_>Kct#QnxFvR!#i*{ zjDi8s7qQ+*xD(bu3v_^e9ETraJw4neYgpMQe)U=FDB0{9dTLR$GFy#Ea1^Q$c$fem1LY4yVV zzrc6>xSS;QSEnhk6m~$G4`?fOOS9weyx$H>U^)x~+X{L*{?lLxOoT^48{{FBiKj2~ zzMM}b^}nC;ivBzjX2BbSRZ9#}s}n*QONsXllE)Ik$yn=poL;4x;n2Ri^(2}8r7cvc|77;>Tt7=&H1q#*w#ob_^PjkXWb04d z8tM6L|4O%uZ!`ZXZJY2V^Pgae6Vrdge>`J{^QvcW&*0_cWX{jV4ri8Wytn(Wv5YZ| zv5hfK(BIg{7|2-2n8@~$Qi=Y?X4@dNe}ud-Tpdh;W0+5z3bQj-hFI^@Xhu=19c1U;;DBl8$q2W z!yGVvD|L5rh;QEEgf@DkKgEl8MHi9IhPAL4(ro2ejzMTYE!D@Hp&qoSF?n3P1Dgo7 z@Hxcq1Cs6aR)3o57Jcdx@VEC4w1Rpk+m1i$13O_Ec!xLwf&6aSP$O4hOsz5EwBdegbQE*^hK;U3hoAN_C08yCa8w~5a)dY%!5U67dTJO zSAR;5#>Rnn`qLnj%mSGOG7DrD$Se>Qio)i0l4-tBXqn0mnIBzJ;`kpI10uC!a`S!@17vN9>REx z&98(9;RCR*P{-7`CA4GS7-JpGh0DSEX=4AzItQQ;et^*K&*bf^7T$tZux-B^S8joq z!Mg;X7s3)SE(`Yr+GRhy0BI|c{aeQPa5RjE$6z!30zns3zH;zfAp^(B_->>^!#h9%>J4GWxv0k*B{qN*UIF*V0`_HuRpHA zuEnm&uFbB|uGOyD@qMPJ-=F1w1J}o0umW6@t*0dWch7O}c@cJkds2Lla?ff4_b~Ue zQDC`J>#w@HpY87|V_Uz2d+4*U0Nh*i;9l#V>$BzDi(A3H**)65+C4ky<6hnf2SEFz z?LWLOo(;6^Tv!L59l}2EnIhyvyPiGl%d^OpFc=iiD%XK$mu6^(P{(#k_0Okn$&u3! zJVSj1_NDEd<4vGlJ?EVP}w|62+n<_;+b{~*!QqXD`(|1 z3;Yun=)5mD@!x%gPYW%z(bSgVgK}+A+f!|u+bWQKZF{NIQgeE)BdX06o+xZSv4_q# zS1>3Sz8dJhrx?V;e^V|*t#cu{H>s_^?~CDT7z%0fJTJGyGcW}#=iW67+_S!gR&cFe z1QWn@FvzQ9{JZ38_yRUUGq@Mj!@KY{+}D-=n$-0(NCTP2yB;njeIH(fv%B6sO}e}* z?<}ZiL)Wv3`B2|y%UUN$yuR-&+hC?k8c6@|^|gs}t;EN#4Yj2<)wW7<{LY1Q;ygJ= z&XsxR&N*~0om1!5Id-m{^C0?yKA~?kLM!MquY*3MFAaq$pq~2L^N=Q%(^vJ`FrIk1 nDjxK8eg2e7fzv}^DZ6hSyZVPK;g!F$lIJaGo + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/baremaps-server/src/main/resources/tdtiles/tileset.json b/baremaps-server/src/main/resources/tdtiles/tileset.json new file mode 100644 index 000000000..84850eb87 --- /dev/null +++ b/baremaps-server/src/main/resources/tdtiles/tileset.json @@ -0,0 +1,24 @@ +{ + "asset" : { + "version" : "1.1" + }, + "geometricError" : 5000.0, + "root" : { + "boundingVolume" : { + "region" : [ -3.141592653589793238, -1.57079632679, 3.141592653589793238, 1.57079632679, 0, 1000] + }, + "geometricError" : 100000.0, + "refine" : "REPLACE", + "content" : { + "uri" : "/content/content_{level}__{x}_{y}.glb" + }, + "implicitTiling" : { + "subdivisionScheme" : "QUADTREE", + "subtreeLevels" : 3, + "availableLevels" : 5, + "subtrees" : { + "uri" : "/subtrees/{level}.{x}.{y}.json" + } + } + } +} \ No newline at end of file diff --git a/examples/tdtiles/README.md b/examples/tdtiles/README.md new file mode 100644 index 000000000..1d541c6f8 --- /dev/null +++ b/examples/tdtiles/README.md @@ -0,0 +1,5 @@ +# OpenStreetMap example + +This folder contains the required files to create and serve 3d tiles from OpenStreetMap data. + +Refer to the [official documentation](https://baremaps.apache.org/examples/serve-3d-tiles/) for more information. \ No newline at end of file diff --git a/examples/tdtiles/indexes.sql b/examples/tdtiles/indexes.sql new file mode 100644 index 000000000..6990e7b6f --- /dev/null +++ b/examples/tdtiles/indexes.sql @@ -0,0 +1,5 @@ +CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_ways_gin ON osm_ways USING gin (nodes); +CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_relations_gin ON osm_relations USING gin (member_refs); +CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_nodes_gix ON osm_nodes USING GIST (geom); +CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_ways_gix ON osm_ways USING GIST (geom); +CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_relations_gix ON osm_relations USING GIST (geom); \ No newline at end of file diff --git a/examples/tdtiles/workflow.json b/examples/tdtiles/workflow.json new file mode 100644 index 000000000..fa7388e9f --- /dev/null +++ b/examples/tdtiles/workflow.json @@ -0,0 +1,42 @@ +{ + "steps": [ + { + "id": "download", + "needs": [], + "tasks": [ + { + "type": "DownloadUrl", + "url": "https://download.geofabrik.de/europe/liechtenstein-latest.osm.pbf", + "path": "liechtenstein-latest.osm.pbf" + } + ] + }, + { + "id": "import", + "needs": [ + "download" + ], + "tasks": [ + { + "type": "ImportOpenStreetMap", + "file": "liechtenstein-latest.osm.pbf", + "database": "jdbc:postgresql://localhost:5432/baremaps?&user=baremaps&password=baremaps", + "databaseSrid": 4326 + } + ] + }, + { + "id": "index", + "needs": [ + "import" + ], + "tasks": [ + { + "type": "ExecuteSql", + "file": "indexes.sql", + "database": "jdbc:postgresql://localhost:5432/baremaps?&user=baremaps&password=baremaps" + } + ] + } + ] +} diff --git a/pom.xml b/pom.xml index bd1744c98..54ebed350 100644 --- a/pom.xml +++ b/pom.xml @@ -196,6 +196,11 @@ limitations under the License. pgbulkinsert ${version.lib.pgbulkinsert}
+ + de.javagl + jgltf-model-builder + ${version.lib.jgltf} + info.picocli picocli From fb28387e9fe1cb85078c9bb0ba265b48a0989b5b Mon Sep 17 00:00:00 2001 From: Antoine Drabble Date: Wed, 4 Jan 2023 17:03:42 +0100 Subject: [PATCH 2/7] Apply spotless --- .../apache/baremaps/cli/tdtiles/Serve.java | 8 +- .../apache/baremaps/tdtiles/GltfBuilder.java | 569 +++++++++--------- .../apache/baremaps/tdtiles/TdTilesStore.java | 26 +- .../tdtiles/subtree/Availability.java | 12 + .../baremaps/tdtiles/subtree/Subtree.java | 12 + .../baremaps/server/TdTilesResources.java | 37 +- examples/openstreetmap/indexes.sql | 425 ++++++++++++- 7 files changed, 781 insertions(+), 308 deletions(-) diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java index 3ba449135..00fa95fee 100644 --- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java +++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java @@ -12,9 +12,12 @@ package org.apache.baremaps.cli.tdtiles; + + import io.servicetalk.http.netty.HttpServers; import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder; import java.util.concurrent.Callable; +import javax.sql.DataSource; import org.apache.baremaps.cli.Options; import org.apache.baremaps.database.PostgresUtils; import org.apache.baremaps.server.CorsFilter; @@ -27,8 +30,6 @@ import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; -import javax.sql.DataSource; - @Command(name = "serve", description = "Start a 3d tile server.") public class Serve implements Callable { @@ -53,7 +54,8 @@ public Integer call() throws Exception { // Configure the application var application = - new ResourceConfig().register(CorsFilter.class).register(TdTilesResources.class).register(new AbstractBinder() { + new ResourceConfig().register(CorsFilter.class).register(TdTilesResources.class) + .register(new AbstractBinder() { @Override protected void configure() { bind(datasource).to(DataSource.class); diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java index b32bd6cf4..b7498d074 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java @@ -12,6 +12,8 @@ package org.apache.baremaps.tdtiles; + + import de.javagl.jgltf.model.NodeModel; import de.javagl.jgltf.model.creation.GltfModelBuilder; import de.javagl.jgltf.model.creation.MaterialBuilder; @@ -21,6 +23,10 @@ import de.javagl.jgltf.model.io.v2.GltfAssetWriterV2; import de.javagl.jgltf.model.io.v2.GltfAssetsV2; import de.javagl.jgltf.model.v2.MaterialModelV2; +import java.io.*; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.*; import org.apache.baremaps.tdtiles.building.Building; import org.apache.commons.lang3.ArrayUtils; import org.locationtech.jts.geom.*; @@ -28,298 +34,311 @@ import org.locationtech.jts.math.Vector3D; import org.locationtech.jts.triangulate.DelaunayTriangulationBuilder; -import java.io.*; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.util.*; - public class GltfBuilder { - /** - * Create a node from a building. - * - * @param building - * @return - */ - public static NodeModel createNode(Building building, float tolerance) { - DelaunayTriangulationBuilder delaunayTriangulationBuilder = new DelaunayTriangulationBuilder(); - delaunayTriangulationBuilder.setSites(building.geometry()); - delaunayTriangulationBuilder.setTolerance(tolerance); - - float[] translation = cartesian3Degrees((float) building.geometry().getCoordinates()[0].y, (float) building.geometry().getCoordinates()[0].x, 0); - - Geometry triangulation = delaunayTriangulationBuilder.getTriangles(new GeometryFactory()); // initial triangulation - if(triangulation.getNumGeometries() == 0){ - return new DefaultNodeModel(); - } - - List vertices = new ArrayList<>(); - List indices = new ArrayList<>(); - List normals = new ArrayList<>(); - - createRoof(building, translation, triangulation, vertices, indices); - HashSet edges = getExteriorEdges(triangulation); - createWalls(building, translation, vertices, indices, edges); - createNormals(vertices, normals); - - MeshPrimitiveBuilder meshPrimitiveBuilder = - MeshPrimitiveBuilder.create(); - meshPrimitiveBuilder.setIntIndicesAsShort(IntBuffer.wrap(ArrayUtils.toPrimitive(indices.toArray(new Integer[0]), 0))); - meshPrimitiveBuilder.addPositions3D(FloatBuffer.wrap(ArrayUtils.toPrimitive(vertices.toArray(new Float[0]), 0.0F))); - meshPrimitiveBuilder.addNormals3D(FloatBuffer.wrap(ArrayUtils.toPrimitive(normals.toArray(new Float[0]), 0.0F))); - - DefaultMeshPrimitiveModel meshPrimitiveModel = - meshPrimitiveBuilder.build(); - - // Create a material, and assign it to the mesh primitive - MaterialBuilder materialBuilder = MaterialBuilder.create(); - materialBuilder.setBaseColorFactor(1f, 1f, 1f, 1.0f); - materialBuilder.setDoubleSided(false); - MaterialModelV2 materialModel = materialBuilder.build(); - materialModel.setMetallicFactor(0.0f); - materialModel.setOcclusionStrength(0.0f); - materialModel.setRoughnessFactor(1.0f); - meshPrimitiveModel.setMaterialModel(materialModel); - - // Create a mesh with the mesh primitive - DefaultMeshModel meshModel = new DefaultMeshModel(); - meshModel.addMeshPrimitiveModel(meshPrimitiveModel); - - // Create a node with the mesh - DefaultNodeModel nodeModel = new DefaultNodeModel(); - nodeModel.addMeshModel(meshModel); - //nodeModel.setScale(new float[]{5f,5f,5f}); - nodeModel.setTranslation(translation); - return nodeModel; + /** + * Create a node from a building. + * + * @param building + * @return + */ + public static NodeModel createNode(Building building, float tolerance) { + DelaunayTriangulationBuilder delaunayTriangulationBuilder = new DelaunayTriangulationBuilder(); + delaunayTriangulationBuilder.setSites(building.geometry()); + delaunayTriangulationBuilder.setTolerance(tolerance); + + float[] translation = cartesian3Degrees((float) building.geometry().getCoordinates()[0].y, + (float) building.geometry().getCoordinates()[0].x, 0); + + Geometry triangulation = delaunayTriangulationBuilder.getTriangles(new GeometryFactory()); // initial + // triangulation + if (triangulation.getNumGeometries() == 0) { + return new DefaultNodeModel(); } - /** - * Compute the normal for each vertex in the vertices array. - * Vertices are grouped by 3, so we can compute the normal for each triangle. - * The normal is the normalized cross product of the two vectors of the triangle. - * - * @param vertices - * @param normals - */ - private static void createNormals(List vertices, List normals) { - for (int i = 0; i < vertices.size(); i += 9) { - float[] v1 = new float[]{vertices.get(i), vertices.get(i + 1), vertices.get(i + 2)}; - float[] v2 = new float[]{vertices.get(i + 3), vertices.get(i + 4), vertices.get(i + 5)}; - float[] v3 = new float[]{vertices.get(i + 6), vertices.get(i + 7), vertices.get(i + 8)}; - float[] u = new float[]{v2[0] - v1[0], v2[1] - v1[1], v2[2] - v1[2]}; - float[] v = new float[]{v3[0] - v1[0], v3[1] - v1[1], v3[2] - v1[2]}; - float[] normal = new float[]{u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]}; - float length = (float) Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]); - normal[0] /= length; - normal[1] /= length; - normal[2] /= length; - normals.add(normal[0]); - normals.add(normal[1]); - normals.add(normal[2]); - normals.add(normal[0]); - normals.add(normal[1]); - normals.add(normal[2]); - normals.add(normal[0]); - normals.add(normal[1]); - normals.add(normal[2]); - } + List vertices = new ArrayList<>(); + List indices = new ArrayList<>(); + List normals = new ArrayList<>(); + + createRoof(building, translation, triangulation, vertices, indices); + HashSet edges = getExteriorEdges(triangulation); + createWalls(building, translation, vertices, indices, edges); + createNormals(vertices, normals); + + MeshPrimitiveBuilder meshPrimitiveBuilder = + MeshPrimitiveBuilder.create(); + meshPrimitiveBuilder.setIntIndicesAsShort( + IntBuffer.wrap(ArrayUtils.toPrimitive(indices.toArray(new Integer[0]), 0))); + meshPrimitiveBuilder.addPositions3D( + FloatBuffer.wrap(ArrayUtils.toPrimitive(vertices.toArray(new Float[0]), 0.0F))); + meshPrimitiveBuilder.addNormals3D( + FloatBuffer.wrap(ArrayUtils.toPrimitive(normals.toArray(new Float[0]), 0.0F))); + + DefaultMeshPrimitiveModel meshPrimitiveModel = + meshPrimitiveBuilder.build(); + + // Create a material, and assign it to the mesh primitive + MaterialBuilder materialBuilder = MaterialBuilder.create(); + materialBuilder.setBaseColorFactor(1f, 1f, 1f, 1.0f); + materialBuilder.setDoubleSided(false); + MaterialModelV2 materialModel = materialBuilder.build(); + materialModel.setMetallicFactor(0.0f); + materialModel.setOcclusionStrength(0.0f); + materialModel.setRoughnessFactor(1.0f); + meshPrimitiveModel.setMaterialModel(materialModel); + + // Create a mesh with the mesh primitive + DefaultMeshModel meshModel = new DefaultMeshModel(); + meshModel.addMeshPrimitiveModel(meshPrimitiveModel); + + // Create a node with the mesh + DefaultNodeModel nodeModel = new DefaultNodeModel(); + nodeModel.addMeshModel(meshModel); + // nodeModel.setScale(new float[]{5f,5f,5f}); + nodeModel.setTranslation(translation); + return nodeModel; + } + + /** + * Compute the normal for each vertex in the vertices array. Vertices are grouped by 3, so we can + * compute the normal for each triangle. The normal is the normalized cross product of the two + * vectors of the triangle. + * + * @param vertices + * @param normals + */ + private static void createNormals(List vertices, List normals) { + for (int i = 0; i < vertices.size(); i += 9) { + float[] v1 = new float[] {vertices.get(i), vertices.get(i + 1), vertices.get(i + 2)}; + float[] v2 = new float[] {vertices.get(i + 3), vertices.get(i + 4), vertices.get(i + 5)}; + float[] v3 = new float[] {vertices.get(i + 6), vertices.get(i + 7), vertices.get(i + 8)}; + float[] u = new float[] {v2[0] - v1[0], v2[1] - v1[1], v2[2] - v1[2]}; + float[] v = new float[] {v3[0] - v1[0], v3[1] - v1[1], v3[2] - v1[2]}; + float[] normal = new float[] {u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], + u[0] * v[1] - u[1] * v[0]}; + float length = + (float) Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]); + normal[0] /= length; + normal[1] /= length; + normal[2] /= length; + normals.add(normal[0]); + normals.add(normal[1]); + normals.add(normal[2]); + normals.add(normal[0]); + normals.add(normal[1]); + normals.add(normal[2]); + normals.add(normal[0]); + normals.add(normal[1]); + normals.add(normal[2]); } + } + + /** + * Iterate over the edges and extrude them to create the walls based on the build height. + * + * @param building + * @param translation + * @param vertices + * @param indices + * @param edges the exterior edges + */ + private static void createWalls(Building building, float[] translation, List vertices, + List indices, HashSet edges) { + for (Edge edge : edges) { + Coordinate[] v = edge.getCoordinates(); + + float[] pos0 = cartesian3Degrees((float) v[0].getY(), (float) v[0].getX(), 0); + pos0[0] -= translation[0]; + pos0[1] -= translation[1]; + pos0[2] -= translation[2]; + float[] pos1 = cartesian3Degrees((float) v[1].getY(), (float) v[1].getX(), 0); + pos1[0] -= translation[0]; + pos1[1] -= translation[1]; + pos1[2] -= translation[2]; + float[] pos2 = cartesian3Degrees((float) v[0].getY(), (float) v[0].getX(), building.height()); + pos2[0] -= translation[0]; + pos2[1] -= translation[1]; + pos2[2] -= translation[2]; + float[] pos3 = cartesian3Degrees((float) v[1].getY(), (float) v[1].getX(), building.height()); + pos3[0] -= translation[0]; + pos3[1] -= translation[1]; + pos3[2] -= translation[2]; - /** - * Iterate over the edges and extrude them to create the walls based on the build height. - * - * @param building - * @param translation - * @param vertices - * @param indices - * @param edges the exterior edges - */ - private static void createWalls(Building building, float[] translation, List vertices, List indices, HashSet edges) { - for (Edge edge : edges) { - Coordinate[] v = edge.getCoordinates(); - - float[] pos0 = cartesian3Degrees((float)v[0].getY(), (float)v[0].getX(), 0); - pos0[0] -= translation[0]; - pos0[1] -= translation[1]; - pos0[2] -= translation[2]; - float[] pos1 = cartesian3Degrees((float)v[1].getY(), (float)v[1].getX(), 0); - pos1[0] -= translation[0]; - pos1[1] -= translation[1]; - pos1[2] -= translation[2]; - float[] pos2 = cartesian3Degrees((float)v[0].getY(), (float)v[0].getX(), building.height()); - pos2[0] -= translation[0]; - pos2[1] -= translation[1]; - pos2[2] -= translation[2]; - float[] pos3 = cartesian3Degrees((float)v[1].getY(), (float)v[1].getX(), building.height()); - pos3[0] -= translation[0]; - pos3[1] -= translation[1]; - pos3[2] -= translation[2]; - - indices.add(vertices.size()/3); - vertices.add(pos0[0]); - vertices.add(pos0[1]); - vertices.add(pos0[2]); - indices.add(vertices.size()/3); - vertices.add(pos1[0]); - vertices.add(pos1[1]); - vertices.add(pos1[2]); - indices.add(vertices.size()/3); - vertices.add(pos2[0]); - vertices.add(pos2[1]); - vertices.add(pos2[2]); - - indices.add(vertices.size()/3); - vertices.add(pos2[0]); - vertices.add(pos2[1]); - vertices.add(pos2[2]); - indices.add(vertices.size()/3); - vertices.add(pos1[0]); - vertices.add(pos1[1]); - vertices.add(pos1[2]); - indices.add(vertices.size()/3); - vertices.add(pos3[0]); - vertices.add(pos3[1]); - vertices.add(pos3[2]); - } + indices.add(vertices.size() / 3); + vertices.add(pos0[0]); + vertices.add(pos0[1]); + vertices.add(pos0[2]); + indices.add(vertices.size() / 3); + vertices.add(pos1[0]); + vertices.add(pos1[1]); + vertices.add(pos1[2]); + indices.add(vertices.size() / 3); + vertices.add(pos2[0]); + vertices.add(pos2[1]); + vertices.add(pos2[2]); + + indices.add(vertices.size() / 3); + vertices.add(pos2[0]); + vertices.add(pos2[1]); + vertices.add(pos2[2]); + indices.add(vertices.size() / 3); + vertices.add(pos1[0]); + vertices.add(pos1[1]); + vertices.add(pos1[2]); + indices.add(vertices.size() / 3); + vertices.add(pos3[0]); + vertices.add(pos3[1]); + vertices.add(pos3[2]); } + } - /** - * Get a list of exterior edges from the building geometry. The exterior edges are the ones that are not shared by two - * triangles. - * @param triangulation - * @return - */ - private static HashSet getExteriorEdges(Geometry triangulation) { - HashSet edges = new HashSet<>(triangulation.getNumGeometries() * 3, 1.0f); - for (int i = 0; i < triangulation.getNumGeometries(); i++) { - Geometry triangle = triangulation.getGeometryN(i); - Coordinate corner1 = triangle.getCoordinates()[0]; - Coordinate corner2 = triangle.getCoordinates()[1]; - Coordinate corner3 = triangle.getCoordinates()[2]; - Edge edge1 = new Edge(new Coordinate[]{corner1, corner2}); - if(edges.contains(edge1)){ - edges.remove(edge1); - } else { - edges.add(edge1); - } - Edge edge2 = new Edge(new Coordinate[]{corner2, corner3}); - if(edges.contains(edge2)){ - edges.remove(edge2); - } else { - edges.add(edge2); - } - Edge edge3 = new Edge(new Coordinate[]{corner3, corner1}); - if(edges.contains(edge3)){ - edges.remove(edge3); - } else { - edges.add(edge3); - } - } - return edges; + /** + * Get a list of exterior edges from the building geometry. The exterior edges are the ones that + * are not shared by two triangles. + * + * @param triangulation + * @return + */ + private static HashSet getExteriorEdges(Geometry triangulation) { + HashSet edges = new HashSet<>(triangulation.getNumGeometries() * 3, 1.0f); + for (int i = 0; i < triangulation.getNumGeometries(); i++) { + Geometry triangle = triangulation.getGeometryN(i); + Coordinate corner1 = triangle.getCoordinates()[0]; + Coordinate corner2 = triangle.getCoordinates()[1]; + Coordinate corner3 = triangle.getCoordinates()[2]; + Edge edge1 = new Edge(new Coordinate[] {corner1, corner2}); + if (edges.contains(edge1)) { + edges.remove(edge1); + } else { + edges.add(edge1); + } + Edge edge2 = new Edge(new Coordinate[] {corner2, corner3}); + if (edges.contains(edge2)) { + edges.remove(edge2); + } else { + edges.add(edge2); + } + Edge edge3 = new Edge(new Coordinate[] {corner3, corner1}); + if (edges.contains(edge3)) { + edges.remove(edge3); + } else { + edges.add(edge3); + } } + return edges; + } + + /** + * Create the roof geometry. This is simply the triangulation of the building geometry at the + * building height. + * + * @param building + * @param translation + * @param triangulation + * @param vertices + * @param indices + */ + private static void createRoof(Building building, float[] translation, Geometry triangulation, + List vertices, List indices) { + for (int i = 0; i < triangulation.getNumGeometries(); i++) { + Geometry triangle = triangulation.getGeometryN(i); + Coordinate corner1 = triangle.getCoordinates()[0]; + Coordinate corner2 = triangle.getCoordinates()[1]; + Coordinate corner3 = triangle.getCoordinates()[2]; - /** - * Create the roof geometry. This is simply the triangulation of the building geometry at the building height. - * - * @param building - * @param translation - * @param triangulation - * @param vertices - * @param indices - */ - private static void createRoof(Building building, float[] translation, Geometry triangulation, List vertices, List indices) { - for (int i = 0; i < triangulation.getNumGeometries(); i++) { - Geometry triangle = triangulation.getGeometryN(i); - Coordinate corner1 = triangle.getCoordinates()[0]; - Coordinate corner2 = triangle.getCoordinates()[1]; - Coordinate corner3 = triangle.getCoordinates()[2]; - - float[] pos0 = cartesian3Degrees((float) corner1.y, (float) corner1.x, building.height()); - pos0[0] -= translation[0]; - pos0[1] -= translation[1]; - pos0[2] -= translation[2]; - float[] pos1 = cartesian3Degrees((float) corner2.y, (float) corner2.x, building.height()); - pos1[0] -= translation[0]; - pos1[1] -= translation[1]; - pos1[2] -= translation[2]; - float[] pos2 = cartesian3Degrees((float) corner3.y, (float) corner3.x, building.height()); - pos2[0] -= translation[0]; - pos2[1] -= translation[1]; - pos2[2] -= translation[2]; - - indices.add(vertices.size() / 3); - vertices.add(pos0[0]); - vertices.add(pos0[1]); - vertices.add(pos0[2]); - indices.add(vertices.size() / 3); - vertices.add(pos1[0]); - vertices.add(pos1[1]); - vertices.add(pos1[2]); - indices.add(vertices.size() / 3); - vertices.add(pos2[0]); - vertices.add(pos2[1]); - vertices.add(pos2[2]); - } + float[] pos0 = cartesian3Degrees((float) corner1.y, (float) corner1.x, building.height()); + pos0[0] -= translation[0]; + pos0[1] -= translation[1]; + pos0[2] -= translation[2]; + float[] pos1 = cartesian3Degrees((float) corner2.y, (float) corner2.x, building.height()); + pos1[0] -= translation[0]; + pos1[1] -= translation[1]; + pos1[2] -= translation[2]; + float[] pos2 = cartesian3Degrees((float) corner3.y, (float) corner3.x, building.height()); + pos2[0] -= translation[0]; + pos2[1] -= translation[1]; + pos2[2] -= translation[2]; + + indices.add(vertices.size() / 3); + vertices.add(pos0[0]); + vertices.add(pos0[1]); + vertices.add(pos0[2]); + indices.add(vertices.size() / 3); + vertices.add(pos1[0]); + vertices.add(pos1[1]); + vertices.add(pos1[2]); + indices.add(vertices.size() / 3); + vertices.add(pos2[0]); + vertices.add(pos2[1]); + vertices.add(pos2[2]); } + } - /** - * Create a GLB from a list of nodes. - * - * @param nodes - * @return - * @throws Exception - */ - public static byte[] createGltf(List nodes) throws Exception { - DefaultSceneModel sceneModel = new DefaultSceneModel(); + /** + * Create a GLB from a list of nodes. + * + * @param nodes + * @return + * @throws Exception + */ + public static byte[] createGltf(List nodes) throws Exception { + DefaultSceneModel sceneModel = new DefaultSceneModel(); - for (NodeModel node : nodes) { - sceneModel.addNode(node); - } + for (NodeModel node : nodes) { + sceneModel.addNode(node); + } - GltfModelBuilder gltfModelBuilder = GltfModelBuilder.create(); - gltfModelBuilder.addSceneModel(sceneModel); - DefaultGltfModel gltfModel = gltfModelBuilder.build(); + GltfModelBuilder gltfModelBuilder = GltfModelBuilder.create(); + gltfModelBuilder.addSceneModel(sceneModel); + DefaultGltfModel gltfModel = gltfModelBuilder.build(); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - GltfAssetV2 asset = GltfAssetsV2.createEmbedded(gltfModel); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + GltfAssetV2 asset = GltfAssetsV2.createEmbedded(gltfModel); - GltfAssetWriterV2 gltfAssetWriter = new GltfAssetWriterV2(); - gltfAssetWriter.writeBinary(asset, outputStream); + GltfAssetWriterV2 gltfAssetWriter = new GltfAssetWriterV2(); + gltfAssetWriter.writeBinary(asset, outputStream); - return outputStream.toByteArray(); - } + return outputStream.toByteArray(); + } - /** - * Returns a Cartesian3 position from longitude and latitude values given in radians. - * Port of CesiumGS - * - * @param latitude in radians - * @param longitude in radians - * @param height in meters above the ellipsoid. - * @return The position - */ - public static float[] cartesian3FromRadians(float latitude, float longitude, float height) { - Vector3D wgs84RadiiSquared = new Vector3D(6378137.0f * 6378137.0f, 6378137.0f * 6378137.0f, 6356752.3142451793f * 6356752.3142451793f); - double cosLatitude = Math.cos(latitude); - Vector3D scratchN = new Vector3D(cosLatitude * Math.cos(longitude), cosLatitude * Math.sin(longitude), Math.sin(latitude)).normalize(); - Vector3D scratchK = new Vector3D(wgs84RadiiSquared.getX() * scratchN.getX(), wgs84RadiiSquared.getY() * scratchN.getY(), wgs84RadiiSquared.getZ() * scratchN.getZ()); - double gamma = Math.sqrt(scratchN.dot(scratchK)); - scratchK = scratchK.divide(gamma); - scratchN = new Vector3D(scratchN.getX() * height, scratchN.getY() * height, scratchN.getZ() * height); - Vector3D result = scratchK.add(scratchN); - return new float[]{(float) result.getX(), (float) result.getZ(), -(float) result.getY()}; - } + /** + * Returns a Cartesian3 position from longitude and latitude values given in radians. Port of + * CesiumGS + * + * @param latitude in radians + * @param longitude in radians + * @param height in meters above the ellipsoid. + * @return The position + */ + public static float[] cartesian3FromRadians(float latitude, float longitude, float height) { + Vector3D wgs84RadiiSquared = new Vector3D(6378137.0f * 6378137.0f, 6378137.0f * 6378137.0f, + 6356752.3142451793f * 6356752.3142451793f); + double cosLatitude = Math.cos(latitude); + Vector3D scratchN = new Vector3D(cosLatitude * Math.cos(longitude), + cosLatitude * Math.sin(longitude), Math.sin(latitude)).normalize(); + Vector3D scratchK = new Vector3D(wgs84RadiiSquared.getX() * scratchN.getX(), + wgs84RadiiSquared.getY() * scratchN.getY(), wgs84RadiiSquared.getZ() * scratchN.getZ()); + double gamma = Math.sqrt(scratchN.dot(scratchK)); + scratchK = scratchK.divide(gamma); + scratchN = + new Vector3D(scratchN.getX() * height, scratchN.getY() * height, scratchN.getZ() * height); + Vector3D result = scratchK.add(scratchN); + return new float[] {(float) result.getX(), (float) result.getZ(), -(float) result.getY()}; + } - /** - * Returns a Cartesian3 position from longitude and latitude values given in degrees. - * Port of CesiumGS - * - * @param latitude in degrees - * @param longitude in degrees - * @param height in meters above the ellipsoid. - * @return The position - */ - public static float[] cartesian3Degrees(float latitude, float longitude, float height) { - return cartesian3FromRadians(latitude * (float) Math.PI / 180, longitude * (float) Math.PI / 180, height); - } + /** + * Returns a Cartesian3 position from longitude and latitude values given in degrees. Port of + * CesiumGS + * + * @param latitude in degrees + * @param longitude in degrees + * @param height in meters above the ellipsoid. + * @return The position + */ + public static float[] cartesian3Degrees(float latitude, float longitude, float height) { + return cartesian3FromRadians(latitude * (float) Math.PI / 180, + longitude * (float) Math.PI / 180, height); + } } diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java index 044206a14..aec6482da 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java @@ -13,19 +13,19 @@ package org.apache.baremaps.tdtiles; -import org.apache.baremaps.database.tile.*; -import org.apache.baremaps.openstreetmap.utils.GeometryUtils; -import org.apache.baremaps.tdtiles.building.Building; -import org.locationtech.jts.geom.Geometry; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import javax.sql.DataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.*; +import javax.sql.DataSource; +import org.apache.baremaps.database.tile.*; +import org.apache.baremaps.openstreetmap.utils.GeometryUtils; +import org.apache.baremaps.tdtiles.building.Building; +import org.locationtech.jts.geom.Geometry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A read-only {@code TileStore} implementation that uses the PostgreSQL to generate 3d tiles. @@ -43,11 +43,13 @@ public TdTilesStore(DataSource datasource) { this.datasource = datasource; } - public List read(float xmin, float xmax, float ymin, float ymax, int limit) throws TileStoreException { + public List read(float xmin, float xmax, float ymin, float ymax, int limit) + throws TileStoreException { try (Connection connection = datasource.getConnection(); Statement statement = connection.createStatement()) { - String sql = String.format(QUERY, ymin * 180 / (float)Math.PI, xmin * 180 / (float)Math.PI, ymax * 180 / (float)Math.PI, xmax * 180 / (float)Math.PI, limit); + String sql = String.format(QUERY, ymin * 180 / (float) Math.PI, xmin * 180 / (float) Math.PI, + ymax * 180 / (float) Math.PI, xmax * 180 / (float) Math.PI, limit); logger.debug("Executing query: {}", sql); List buildings = new ArrayList<>(); @@ -61,11 +63,11 @@ public List read(float xmin, float xmax, float ymin, float ymax, int l String height = resultSet.getString(3); String buildingLevels = resultSet.getString(4); float finalHeight = 10; - if(buildingHeight != null) { + if (buildingHeight != null) { finalHeight = Float.parseFloat(buildingHeight.replaceAll("[^0-9]", "")); - } else if(height != null) { + } else if (height != null) { finalHeight = Float.parseFloat(height.replaceAll("[^0-9]", "")); - } else if(buildingLevels != null) { + } else if (buildingLevels != null) { finalHeight = Float.parseFloat(buildingLevels.replaceAll("[^0-9]", "")) * 3; } diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java index a6ef848d9..b3426773c 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java @@ -1,3 +1,15 @@ +/* + * 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.tdtiles.subtree; public record Availability(boolean constant) { diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java index ff48f0c06..168113cdf 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java @@ -1,3 +1,15 @@ +/* + * 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.tdtiles.subtree; public record Subtree(Availability tileAvailability, diff --git a/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java index 7b0e61a47..e36cac32f 100644 --- a/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java +++ b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java @@ -14,6 +14,7 @@ import static com.google.common.net.HttpHeaders.*; +import de.javagl.jgltf.model.NodeModel; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -24,11 +25,9 @@ import javax.ws.rs.GET; import javax.ws.rs.PathParam; import javax.ws.rs.core.Response; - -import de.javagl.jgltf.model.NodeModel; +import org.apache.baremaps.tdtiles.GltfBuilder; import org.apache.baremaps.tdtiles.TdTilesStore; import org.apache.baremaps.tdtiles.building.Building; -import org.apache.baremaps.tdtiles.GltfBuilder; import org.apache.baremaps.tdtiles.subtree.Availability; import org.apache.baremaps.tdtiles.subtree.Subtree; @@ -47,9 +46,14 @@ public TdTilesResources(DataSource dataSource) { public Response getSubtree(@PathParam("level") int level, @PathParam("x") int x, @PathParam("y") int y) { if (level == 18) { - return Response.ok().entity(new Subtree(new Availability(false),new Availability(true),new Availability(false))).header(CONTENT_TYPE, "application/json").build(); + return Response.ok() + .entity( + new Subtree(new Availability(false), new Availability(true), new Availability(false))) + .header(CONTENT_TYPE, "application/json").build(); } - return Response.ok().entity(new Subtree(new Availability(true),new Availability(true),new Availability(true))).header(CONTENT_TYPE, "application/json").build(); + return Response.ok() + .entity(new Subtree(new Availability(true), new Availability(true), new Availability(true))) + .header(CONTENT_TYPE, "application/json").build(); } @GET @@ -58,32 +62,31 @@ public Response getContent(@PathParam("level") int level, @PathParam("x") int x, @PathParam("y") int y) throws Exception { float[] coords = xyzToLatLonRadians(x, y, level); int limit = level > 17 ? 1000 : 80; - List buildings = tdTilesStore.read(coords[0],coords[1],coords[2],coords[3], limit); + List buildings = tdTilesStore.read(coords[0], coords[1], coords[2], coords[3], limit); List nodes = new ArrayList<>(); for (Building building : buildings) { float tolerance = level > 17 ? 0.00001f : level >= 16 ? 0.0001f : 0.0003f; nodes.add(GltfBuilder.createNode(building, tolerance)); } return Response.ok().entity( - GltfBuilder.createGltf(nodes) - ).build(); + GltfBuilder.createGltf(nodes)).build(); } public static float[] xyzToLatLonRadians(int x, int y, int z) { float[] answer = new float[4]; - int subdivision = 1 << z; - float yWidth = (float)Math.PI / subdivision; - float xWidth = 2 * (float)Math.PI / subdivision; - answer[0] = - (float)Math.PI / 2 + y * yWidth; // Lon + int subdivision = 1 << z; + float yWidth = (float) Math.PI / subdivision; + float xWidth = 2 * (float) Math.PI / subdivision; + answer[0] = -(float) Math.PI / 2 + y * yWidth; // Lon answer[1] = answer[0] + yWidth; // Lon max - answer[2] = - (float)Math.PI + xWidth * x; // Lat + answer[2] = -(float) Math.PI + xWidth * x; // Lat answer[3] = answer[2] + xWidth; // Lat max // Clamp to -PI/2 to PI/2 - answer[0] = Math.max(- (float)Math.PI / 2, Math.min((float)Math.PI / 2, answer[0])); - answer[1] = Math.max(- (float)Math.PI / 2, Math.min((float)Math.PI / 2, answer[1])); + answer[0] = Math.max(-(float) Math.PI / 2, Math.min((float) Math.PI / 2, answer[0])); + answer[1] = Math.max(-(float) Math.PI / 2, Math.min((float) Math.PI / 2, answer[1])); // Clamp to -PI to PI - answer[2] = Math.max(- (float)Math.PI, Math.min((float)Math.PI, answer[2])); - answer[3] = Math.max(- (float)Math.PI, Math.min((float)Math.PI, answer[3])); + answer[2] = Math.max(-(float) Math.PI, Math.min((float) Math.PI, answer[2])); + answer[3] = Math.max(-(float) Math.PI, Math.min((float) Math.PI, answer[3])); return answer; } diff --git a/examples/openstreetmap/indexes.sql b/examples/openstreetmap/indexes.sql index b46089ddc..cc9d0c927 100644 --- a/examples/openstreetmap/indexes.sql +++ b/examples/openstreetmap/indexes.sql @@ -16,4 +16,427 @@ CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_ways_gin ON osm_ways USING gin (node CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_relations_gin ON osm_relations USING gin (member_refs); CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_nodes_gix ON osm_nodes USING GIST (geom); CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_ways_gix ON osm_ways USING GIST (geom); -CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_relations_gix ON osm_relations USING GIST (geom); \ No newline at end of file +CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_relations_gix ON osm_relations USING GIST (geom); + +with hfabbbbce as (select * + from osm_nodes + where ((tags ? 'aeroway') OR (tags ? 'waterway') OR (tags ? 'landuse') OR (tags ? 'railway') OR + (tags ? 'highway') OR (tags ? 'public_transport') OR (tags ? 'aerialway') OR + (tags ? 'geological') OR (tags ? 'building') OR (tags ? 'amenity') OR (tags ? 'craft') OR + (tags ? 'emergency') OR (tags ? 'historic') OR (tags ? 'leisure') OR (tags ? 'man_made') OR + (tags ? 'military') OR (tags ? 'natural') OR (tags ? 'office') OR (tags ? 'place') OR + (tags ? 'power') OR (tags ? 'route') OR (tags ? 'shop') OR (tags ? 'sport') OR + (tags ? 'telecom') OR (tags ? 'tourism')) + and st_intersects(geom, st_tileenvelope(14, 8625, 5750))), + hf88736cf as (select * + from osm_ways + where ((tags ? 'aeroway') OR (tags ? 'waterway') OR (tags ? 'landuse') OR (tags ? 'railway') OR + (tags ? 'highway') OR (tags ? 'public_transport') OR (tags ? 'aerialway') OR + (tags ? 'geological') OR (tags ? 'building') OR (tags ? 'amenity') OR (tags ? 'craft') OR + (tags ? 'emergency') OR (tags ? 'historic') OR (tags ? 'leisure') OR (tags ? 'man_made') OR + (tags ? 'military') OR (tags ? 'natural') OR (tags ? 'office') OR (tags ? 'place') OR + (tags ? 'power') OR (tags ? 'route') OR (tags ? 'shop') OR (tags ? 'sport') OR + (tags ? 'telecom') OR (tags ? 'tourism')) + and st_intersects(geom, st_tileenvelope(14, 8625, 5750))), + h633b0648 as (select * + from osm_relations + where ((tags ? 'aeroway' AND tags->>'type' = 'multipolygon') OR + (tags ? 'waterway' AND tags->>'type' = 'multipolygon') OR + (tags ? 'landuse' AND tags->>'type' = 'multipolygon') OR + (tags ? 'railway' AND tags->>'type' = 'multipolygon') OR + (tags ? 'highway' AND tags->>'type' = 'multipolygon') OR + (tags ? 'public_transport' AND tags->>'type' = 'multipolygon') OR + (tags ? 'aerialway' AND tags->>'type' = 'multipolygon') OR + (tags ? 'geological' AND tags->>'type' = 'multipolygon') OR + (tags ? 'building' AND tags->>'type' = 'multipolygon') OR + (tags ? 'amenity' AND tags->>'type' = 'multipolygon') OR + (tags ? 'craft' AND tags->>'type' = 'multipolygon') OR + (tags ? 'emergency' AND tags->>'type' = 'multipolygon') OR + (tags ? 'historic' AND tags->>'type' = 'multipolygon') OR + (tags ? 'leisure' AND tags->>'type' = 'multipolygon') OR + (tags ? 'man_made' AND tags->>'type' = 'multipolygon') OR + (tags ? 'military' AND tags->>'type' = 'multipolygon') OR + (tags ? 'natural' AND tags->>'type' = 'multipolygon') OR + (tags ? 'office' AND tags->>'type' = 'multipolygon') OR + (tags ? 'place' AND tags->>'type' = 'multipolygon') OR + (tags ? 'power' AND tags->>'type' = 'multipolygon') OR + (tags ? 'route' AND tags->>'type' = 'multipolygon') OR + (tags ? 'shop' AND tags->>'type' = 'multipolygon') OR + (tags ? 'sport' AND tags->>'type' = 'multipolygon') OR + (tags ? 'telecom' AND tags->>'type' = 'multipolygon') OR + (tags ? 'tourism' AND tags->>'type' = 'multipolygon')) + and st_intersects(geom, st_tileenvelope(14, 8625, 5750))) +select st_asmvt(target, 'aeroway', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'aeroway' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'aeroway' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'aeroway' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'waterway', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'waterway' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'waterway' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'waterway' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'landuse', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'landuse' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'landuse' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'landuse' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'railway', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'railway' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'railway' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'railway' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'highway', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'highway' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'highway' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'highway' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'public_transport', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'public_transport' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'public_transport' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'public_transport' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'aerialway', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'aerialway' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'aerialway' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'aerialway' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'geological', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'geological' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'geological' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'geological' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'building', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'building' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'building' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'building' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'amenity', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'amenity' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'amenity' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'amenity' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'craft', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'craft' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'craft' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'craft' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'emergency', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'emergency' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'emergency' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'emergency' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'historic', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'historic' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'historic' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'historic' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'leisure', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'leisure' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'leisure' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'leisure' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'man_made', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'man_made' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'man_made' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'man_made' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'military', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'military' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'military' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'military' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'natural', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'natural' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'natural' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'natural' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'office', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'office' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'office' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'office' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'place', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'place' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'place' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'place' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'power', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'power' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'power' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'power' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'route', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'route' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'route' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'route' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'shop', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'shop' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'shop' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'shop' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'sport', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'sport' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'sport' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'sport' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'telecom', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'telecom' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'telecom' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'telecom' AND tags->>'type' = 'multipolygon') as target +union all +select st_asmvt(target, 'tourism', 4096, 'geom', 'id') +from (select id as id, + (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, + st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hfabbbbce + where tags ? 'tourism' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from hf88736cf + where tags ? 'tourism' + union all + select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom + from h633b0648 + where tags ? 'tourism' AND tags->>'type' = 'multipolygon') as target \ No newline at end of file From 286060ec891f4106844290e896f297aa46e9f7eb Mon Sep 17 00:00:00 2001 From: Antoine Drabble Date: Thu, 5 Jan 2023 14:18:38 +0100 Subject: [PATCH 3/7] Clean up the code --- .run/tdtiles-dev.run.xml | 11 + .../apache/baremaps/tdtiles/GltfBuilder.java | 41 +- .../baremaps/server/TdTilesResources.java | 48 +- .../src/main/resources/tdtiles/index.html | 6 +- examples/openstreetmap/indexes.sql | 425 +----------------- examples/tdtiles/indexes.sql | 11 +- 6 files changed, 72 insertions(+), 470 deletions(-) create mode 100644 .run/tdtiles-dev.run.xml diff --git a/.run/tdtiles-dev.run.xml b/.run/tdtiles-dev.run.xml new file mode 100644 index 000000000..e5bc2600c --- /dev/null +++ b/.run/tdtiles-dev.run.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java index b7498d074..6aa90956c 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java @@ -43,28 +43,32 @@ public class GltfBuilder { * @return */ public static NodeModel createNode(Building building, float tolerance) { + + // Tessellate the vector data DelaunayTriangulationBuilder delaunayTriangulationBuilder = new DelaunayTriangulationBuilder(); delaunayTriangulationBuilder.setSites(building.geometry()); delaunayTriangulationBuilder.setTolerance(tolerance); - - float[] translation = cartesian3Degrees((float) building.geometry().getCoordinates()[0].y, - (float) building.geometry().getCoordinates()[0].x, 0); - - Geometry triangulation = delaunayTriangulationBuilder.getTriangles(new GeometryFactory()); // initial - // triangulation + Geometry triangulation = delaunayTriangulationBuilder.getTriangles(new GeometryFactory()); if (triangulation.getNumGeometries() == 0) { return new DefaultNodeModel(); } + // Compute a translation for the origin of the building. If the building is too far from the + // origin, it will + // suffer from jittering. https://help.agi.com/AGIComponents/html/BlogPrecisionsPrecisions.htm + float[] translation = cartesian3FromDegrees((float) building.geometry().getCoordinates()[0].y, + (float) building.geometry().getCoordinates()[0].x, 0); + + // Generate the 3d vertices, indices and normals List vertices = new ArrayList<>(); List indices = new ArrayList<>(); List normals = new ArrayList<>(); - createRoof(building, translation, triangulation, vertices, indices); HashSet edges = getExteriorEdges(triangulation); createWalls(building, translation, vertices, indices, edges); createNormals(vertices, normals); + // Create a mesh from the vertices, indices and normals MeshPrimitiveBuilder meshPrimitiveBuilder = MeshPrimitiveBuilder.create(); meshPrimitiveBuilder.setIntIndicesAsShort( @@ -73,7 +77,6 @@ public static NodeModel createNode(Building building, float tolerance) { FloatBuffer.wrap(ArrayUtils.toPrimitive(vertices.toArray(new Float[0]), 0.0F))); meshPrimitiveBuilder.addNormals3D( FloatBuffer.wrap(ArrayUtils.toPrimitive(normals.toArray(new Float[0]), 0.0F))); - DefaultMeshPrimitiveModel meshPrimitiveModel = meshPrimitiveBuilder.build(); @@ -94,8 +97,8 @@ public static NodeModel createNode(Building building, float tolerance) { // Create a node with the mesh DefaultNodeModel nodeModel = new DefaultNodeModel(); nodeModel.addMeshModel(meshModel); - // nodeModel.setScale(new float[]{5f,5f,5f}); nodeModel.setTranslation(translation); + return nodeModel; } @@ -147,19 +150,21 @@ private static void createWalls(Building building, float[] translation, List())).build(); + } float[] coords = xyzToLatLonRadians(x, y, level); - int limit = level > 17 ? 1000 : 80; - List buildings = tdTilesStore.read(coords[0], coords[1], coords[2], coords[3], limit); List nodes = new ArrayList<>(); + int limit = level > 17 ? 1000 : level > 16 ? 200 : level > 15 ? 30 : 10; + List buildings = tdTilesStore.read(coords[0], coords[1], coords[2], coords[3], limit); for (Building building : buildings) { - float tolerance = level > 17 ? 0.00001f : level >= 16 ? 0.0001f : 0.0003f; + float tolerance = level > 17 ? 0.00001f : level > 15 ? 0.00002f : 0.00004f; nodes.add(GltfBuilder.createNode(building, tolerance)); } return Response.ok().entity( GltfBuilder.createGltf(nodes)).build(); } + @GET + @javax.ws.rs.Path("/{path:.*}") + public Response get(@PathParam("path") String path) { + if (path.equals("") || path.endsWith("/")) { + path += "index.html"; + } + path = String.format("tdtiles/%s", path); + try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path)) { + var bytes = inputStream.readAllBytes(); + return Response.ok().entity(bytes).build(); + } catch (IOException e) { + return Response.status(404).build(); + } + } + + /** + * Convert XYZ tile coordinates to lat/lon in radians. + * + * @param x + * @param y + * @param z + * @return + */ public static float[] xyzToLatLonRadians(int x, int y, int z) { float[] answer = new float[4]; int subdivision = 1 << z; @@ -89,19 +116,4 @@ public static float[] xyzToLatLonRadians(int x, int y, int z) { answer[3] = Math.max(-(float) Math.PI, Math.min((float) Math.PI, answer[3])); return answer; } - - @GET - @javax.ws.rs.Path("/{path:.*}") - public Response get(@PathParam("path") String path) { - if (path.equals("") || path.endsWith("/")) { - path += "index.html"; - } - path = String.format("tdtiles/%s", path); - try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path)) { - var bytes = inputStream.readAllBytes(); - return Response.ok().entity(bytes).build(); - } catch (IOException e) { - return Response.status(404).build(); - } - } } diff --git a/baremaps-server/src/main/resources/tdtiles/index.html b/baremaps-server/src/main/resources/tdtiles/index.html index 0bc4b8891..9b0825c29 100644 --- a/baremaps-server/src/main/resources/tdtiles/index.html +++ b/baremaps-server/src/main/resources/tdtiles/index.html @@ -29,13 +29,9 @@ viewer.scene.primitives.add(tileset); - const pos = Cesium.Cartesian3.fromDegrees( - 9.5209, 47.1410, 0); - console.log(pos); - // Set initial position viewer.camera.setView({ - destination : Cesium.Cartesian3.fromDegrees(6.6323, 46.5197, 300) + destination : Cesium.Cartesian3.fromDegrees(9.5209, 47.1410, 300) }); diff --git a/examples/openstreetmap/indexes.sql b/examples/openstreetmap/indexes.sql index cc9d0c927..b46089ddc 100644 --- a/examples/openstreetmap/indexes.sql +++ b/examples/openstreetmap/indexes.sql @@ -16,427 +16,4 @@ CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_ways_gin ON osm_ways USING gin (node CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_relations_gin ON osm_relations USING gin (member_refs); CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_nodes_gix ON osm_nodes USING GIST (geom); CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_ways_gix ON osm_ways USING GIST (geom); -CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_relations_gix ON osm_relations USING GIST (geom); - -with hfabbbbce as (select * - from osm_nodes - where ((tags ? 'aeroway') OR (tags ? 'waterway') OR (tags ? 'landuse') OR (tags ? 'railway') OR - (tags ? 'highway') OR (tags ? 'public_transport') OR (tags ? 'aerialway') OR - (tags ? 'geological') OR (tags ? 'building') OR (tags ? 'amenity') OR (tags ? 'craft') OR - (tags ? 'emergency') OR (tags ? 'historic') OR (tags ? 'leisure') OR (tags ? 'man_made') OR - (tags ? 'military') OR (tags ? 'natural') OR (tags ? 'office') OR (tags ? 'place') OR - (tags ? 'power') OR (tags ? 'route') OR (tags ? 'shop') OR (tags ? 'sport') OR - (tags ? 'telecom') OR (tags ? 'tourism')) - and st_intersects(geom, st_tileenvelope(14, 8625, 5750))), - hf88736cf as (select * - from osm_ways - where ((tags ? 'aeroway') OR (tags ? 'waterway') OR (tags ? 'landuse') OR (tags ? 'railway') OR - (tags ? 'highway') OR (tags ? 'public_transport') OR (tags ? 'aerialway') OR - (tags ? 'geological') OR (tags ? 'building') OR (tags ? 'amenity') OR (tags ? 'craft') OR - (tags ? 'emergency') OR (tags ? 'historic') OR (tags ? 'leisure') OR (tags ? 'man_made') OR - (tags ? 'military') OR (tags ? 'natural') OR (tags ? 'office') OR (tags ? 'place') OR - (tags ? 'power') OR (tags ? 'route') OR (tags ? 'shop') OR (tags ? 'sport') OR - (tags ? 'telecom') OR (tags ? 'tourism')) - and st_intersects(geom, st_tileenvelope(14, 8625, 5750))), - h633b0648 as (select * - from osm_relations - where ((tags ? 'aeroway' AND tags->>'type' = 'multipolygon') OR - (tags ? 'waterway' AND tags->>'type' = 'multipolygon') OR - (tags ? 'landuse' AND tags->>'type' = 'multipolygon') OR - (tags ? 'railway' AND tags->>'type' = 'multipolygon') OR - (tags ? 'highway' AND tags->>'type' = 'multipolygon') OR - (tags ? 'public_transport' AND tags->>'type' = 'multipolygon') OR - (tags ? 'aerialway' AND tags->>'type' = 'multipolygon') OR - (tags ? 'geological' AND tags->>'type' = 'multipolygon') OR - (tags ? 'building' AND tags->>'type' = 'multipolygon') OR - (tags ? 'amenity' AND tags->>'type' = 'multipolygon') OR - (tags ? 'craft' AND tags->>'type' = 'multipolygon') OR - (tags ? 'emergency' AND tags->>'type' = 'multipolygon') OR - (tags ? 'historic' AND tags->>'type' = 'multipolygon') OR - (tags ? 'leisure' AND tags->>'type' = 'multipolygon') OR - (tags ? 'man_made' AND tags->>'type' = 'multipolygon') OR - (tags ? 'military' AND tags->>'type' = 'multipolygon') OR - (tags ? 'natural' AND tags->>'type' = 'multipolygon') OR - (tags ? 'office' AND tags->>'type' = 'multipolygon') OR - (tags ? 'place' AND tags->>'type' = 'multipolygon') OR - (tags ? 'power' AND tags->>'type' = 'multipolygon') OR - (tags ? 'route' AND tags->>'type' = 'multipolygon') OR - (tags ? 'shop' AND tags->>'type' = 'multipolygon') OR - (tags ? 'sport' AND tags->>'type' = 'multipolygon') OR - (tags ? 'telecom' AND tags->>'type' = 'multipolygon') OR - (tags ? 'tourism' AND tags->>'type' = 'multipolygon')) - and st_intersects(geom, st_tileenvelope(14, 8625, 5750))) -select st_asmvt(target, 'aeroway', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'aeroway' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'aeroway' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'aeroway' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'waterway', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'waterway' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'waterway' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'waterway' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'landuse', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'landuse' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'landuse' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'landuse' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'railway', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'railway' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'railway' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'railway' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'highway', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'highway' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'highway' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'highway' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'public_transport', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'public_transport' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'public_transport' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'public_transport' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'aerialway', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'aerialway' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'aerialway' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'aerialway' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'geological', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'geological' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'geological' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'geological' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'building', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'building' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'building' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'building' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'amenity', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'amenity' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'amenity' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'amenity' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'craft', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'craft' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'craft' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'craft' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'emergency', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'emergency' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'emergency' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'emergency' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'historic', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'historic' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'historic' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'historic' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'leisure', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'leisure' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'leisure' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'leisure' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'man_made', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'man_made' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'man_made' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'man_made' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'military', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'military' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'military' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'military' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'natural', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'natural' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'natural' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'natural' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'office', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'office' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'office' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'office' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'place', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'place' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'place' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'place' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'power', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'power' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'power' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'power' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'route', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'route' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'route' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'route' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'shop', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'shop' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'shop' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'shop' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'sport', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'sport' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'sport' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'sport' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'telecom', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'telecom' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'telecom' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'telecom' AND tags->>'type' = 'multipolygon') as target -union all -select st_asmvt(target, 'tourism', 4096, 'geom', 'id') -from (select id as id, - (tags || jsonb_build_object('geometry', lower(replace(st_geometrytype(geom), 'ST_', '')))) as tags, - st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hfabbbbce - where tags ? 'tourism' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from hf88736cf - where tags ? 'tourism' - union all - select id as id, (tags || jsonb_build_object('geometry', lower (replace(st_geometrytype(geom), 'ST_', '')))) as tags, st_asmvtgeom(geom, st_tileenvelope(14, 8625, 5750), 4096, 256, true) as geom - from h633b0648 - where tags ? 'tourism' AND tags->>'type' = 'multipolygon') as target \ No newline at end of file +CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_relations_gix ON osm_relations USING GIST (geom); \ No newline at end of file diff --git a/examples/tdtiles/indexes.sql b/examples/tdtiles/indexes.sql index 6990e7b6f..9cad3fc46 100644 --- a/examples/tdtiles/indexes.sql +++ b/examples/tdtiles/indexes.sql @@ -1,5 +1,6 @@ -CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_ways_gin ON osm_ways USING gin (nodes); -CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_relations_gin ON osm_relations USING gin (member_refs); -CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_nodes_gix ON osm_nodes USING GIST (geom); -CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_ways_gix ON osm_ways USING GIST (geom); -CREATE INDEX CONCURRENTLY IF NOT EXISTS osm_relations_gix ON osm_relations USING GIST (geom); \ No newline at end of file +CREATE INDEX IF NOT EXISTS osm_ways_gin ON osm_ways USING gin (nodes); +CREATE INDEX IF NOT EXISTS osm_ways_tags_gin ON osm_ways USING gin (tags); +CREATE INDEX IF NOT EXISTS osm_relations_gin ON osm_relations USING gin (member_refs); +CREATE INDEX IF NOT EXISTS osm_nodes_gix ON osm_nodes USING GIST (geom); +CREATE INDEX IF NOT EXISTS osm_ways_gix ON osm_ways USING GIST (geom); +CREATE INDEX IF NOT EXISTS osm_relations_gix ON osm_relations USING GIST (geom); \ No newline at end of file From 16a7cf2342979a977da17414601c8e1840fcdb52 Mon Sep 17 00:00:00 2001 From: Antoine Drabble Date: Thu, 5 Jan 2023 14:30:14 +0100 Subject: [PATCH 4/7] Remove default maximum screen space error config in Cesium --- baremaps-server/src/main/resources/tdtiles/index.html | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/baremaps-server/src/main/resources/tdtiles/index.html b/baremaps-server/src/main/resources/tdtiles/index.html index 9b0825c29..45290391d 100644 --- a/baremaps-server/src/main/resources/tdtiles/index.html +++ b/baremaps-server/src/main/resources/tdtiles/index.html @@ -20,11 +20,10 @@ const tileset = new Cesium.Cesium3DTileset({ url: "http://localhost:9000/tileset.json", - maximumScreenSpaceError: 10, - //debugShowBoundingVolume: true, - //debugShowGeometricError: true, - //debugShowUrl: true, - //debugWireframe: true + debugShowBoundingVolume: false, + debugShowGeometricError: false, + debugShowUrl: false, + debugWireframe: false }); viewer.scene.primitives.add(tileset); From 3203edbe9589e1993fd9878f173e6d7b14198989 Mon Sep 17 00:00:00 2001 From: Bertil Chapuis Date: Mon, 27 Nov 2023 10:31:42 +0100 Subject: [PATCH 5/7] Fix minor issues related to the rebase --- .../apache/baremaps/cli/tdtiles/Serve.java | 21 +++++++++------ .../apache/baremaps/cli/tdtiles/TdTiles.java | 17 +++++++----- baremaps-core/pom.xml | 5 ++++ .../apache/baremaps/tdtiles/GltfBuilder.java | 17 +++++++----- .../apache/baremaps/tdtiles/TdTilesStore.java | 26 ++++++++++++------- .../baremaps/tdtiles/building/Building.java | 17 ++++++++++++ .../tdtiles/subtree/Availability.java | 19 +++++++++----- .../baremaps/tdtiles/subtree/Subtree.java | 23 +++++++++------- .../baremaps/server/TdTilesResources.java | 17 +++++++----- .../src/main/resources/tdtiles/index.html | 2 +- basemap/import.js | 2 +- pom.xml | 5 ++++ 12 files changed, 118 insertions(+), 53 deletions(-) diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java index 00fa95fee..d1b4e78ef 100644 --- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java +++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java @@ -1,13 +1,18 @@ /* - * 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 + * 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. + * 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.tdtiles; @@ -19,9 +24,9 @@ import java.util.concurrent.Callable; import javax.sql.DataSource; import org.apache.baremaps.cli.Options; -import org.apache.baremaps.database.PostgresUtils; import org.apache.baremaps.server.CorsFilter; import org.apache.baremaps.server.TdTilesResources; +import org.apache.baremaps.utils.PostgresUtils; import org.glassfish.hk2.utilities.binding.AbstractBinder; import org.glassfish.jersey.server.ResourceConfig; import org.slf4j.Logger; @@ -50,7 +55,7 @@ public class Serve implements Callable { @Override public Integer call() throws Exception { - var datasource = PostgresUtils.dataSource(database); + var datasource = PostgresUtils.createDataSource(database); // Configure the application var application = diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/TdTiles.java b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/TdTiles.java index 5ffcf186a..f378cc108 100644 --- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/TdTiles.java +++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/TdTiles.java @@ -1,13 +1,18 @@ /* - * 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 + * 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. + * 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.tdtiles; diff --git a/baremaps-core/pom.xml b/baremaps-core/pom.xml index 727539219..679ccb5b8 100644 --- a/baremaps-core/pom.xml +++ b/baremaps-core/pom.xml @@ -66,9 +66,14 @@ limitations under the License. de.bytefish pgbulkinsert + + de.javagl + jgltf-model + de.javagl jgltf-model-builder + ${version.lib.jgltf} it.unimi.dsi diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java index 6aa90956c..336a072cc 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/GltfBuilder.java @@ -1,13 +1,18 @@ /* - * 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 + * 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. + * 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.tdtiles; diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java index aec6482da..7c83a8258 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/TdTilesStore.java @@ -1,13 +1,18 @@ /* - * 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 + * 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. + * 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.tdtiles; @@ -20,9 +25,9 @@ import java.sql.Statement; import java.util.*; import javax.sql.DataSource; -import org.apache.baremaps.database.tile.*; -import org.apache.baremaps.openstreetmap.utils.GeometryUtils; import org.apache.baremaps.tdtiles.building.Building; +import org.apache.baremaps.tilestore.TileStoreException; +import org.apache.baremaps.utils.GeometryUtils; import org.locationtech.jts.geom.Geometry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,7 +39,7 @@ public class TdTilesStore { private static final Logger logger = LoggerFactory.getLogger(TdTilesStore.class); private static final String QUERY = - "select st_asbinary(geom), tags -> 'buildings:height', tags -> 'height', tags -> 'buildings:levels' from osm_ways where tags ? 'building' and st_intersects( st_force3d(geom,0), st_makeenvelope(%1$s, %2$s, %3$s, %4$s, 4326)) LIMIT %5$s"; + "select st_asbinary(geom), tags -> 'buildings:height', tags -> 'height', tags -> 'buildings:levels' from osm_ways where tags ? 'building' and st_intersects(geom, st_makeenvelope(%1$s, %2$s, %3$s, %4$s, 4326)) LIMIT %5$s"; private final DataSource datasource; @@ -50,10 +55,13 @@ public List read(float xmin, float xmax, float ymin, float ymax, int l String sql = String.format(QUERY, ymin * 180 / (float) Math.PI, xmin * 180 / (float) Math.PI, ymax * 180 / (float) Math.PI, xmax * 180 / (float) Math.PI, limit); + logger.debug("Executing query: {}", sql); + System.out.println(sql); List buildings = new ArrayList<>(); + try (ResultSet resultSet = statement.executeQuery(sql)) { while (resultSet.next()) { byte[] bytes = resultSet.getBytes(1); diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/building/Building.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/building/Building.java index 3eafff701..abe69ca9d 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/building/Building.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/building/Building.java @@ -1,3 +1,20 @@ +/* + * 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. + */ + package org.apache.baremaps.tdtiles.building; import org.locationtech.jts.geom.Geometry; diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java index b3426773c..4e5f4b4c8 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Availability.java @@ -1,16 +1,21 @@ /* - * 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 + * 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. + * 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.tdtiles.subtree; public record Availability(boolean constant) { -} \ No newline at end of file +} diff --git a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java index 168113cdf..18ae9d873 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/tdtiles/subtree/Subtree.java @@ -1,19 +1,24 @@ /* - * 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 + * 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. + * 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.tdtiles.subtree; public record Subtree(Availability tileAvailability, - Availability contentAvailability, - Availability childSubtreeAvailability) { + Availability contentAvailability, + Availability childSubtreeAvailability) { -} \ No newline at end of file +} diff --git a/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java index 5c5061545..8a60b8057 100644 --- a/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java +++ b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java @@ -1,13 +1,18 @@ /* - * 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 + * 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. + * 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.server; diff --git a/baremaps-server/src/main/resources/tdtiles/index.html b/baremaps-server/src/main/resources/tdtiles/index.html index 45290391d..66449d058 100644 --- a/baremaps-server/src/main/resources/tdtiles/index.html +++ b/baremaps-server/src/main/resources/tdtiles/index.html @@ -30,7 +30,7 @@ // Set initial position viewer.camera.setView({ - destination : Cesium.Cartesian3.fromDegrees(9.5209, 47.1410, 300) + destination : Cesium.Cartesian3.fromDegrees(6.6323, 46.5197, 300) }); diff --git a/basemap/import.js b/basemap/import.js index f5490ae73..8d546251b 100644 --- a/basemap/import.js +++ b/basemap/import.js @@ -119,7 +119,7 @@ export default { "type": "ImportOsmPbf", "file": "data/data.osm.pbf", "database": config.database, - "databaseSrid": 3857, + "databaseSrid": 4326, "replaceExisting": true, }, { diff --git a/pom.xml b/pom.xml index 54ebed350..49ff9e30a 100644 --- a/pom.xml +++ b/pom.xml @@ -196,6 +196,11 @@ limitations under the License. pgbulkinsert ${version.lib.pgbulkinsert} + + de.javagl + jgltf-model + ${version.lib.jgltf} + de.javagl jgltf-model-builder From a3b57290404c62c33c24859365c7e57bbcab5c97 Mon Sep 17 00:00:00 2001 From: Bertil Chapuis Date: Tue, 27 Feb 2024 08:02:31 +0100 Subject: [PATCH 6/7] Use armeria server --- .../apache/baremaps/cli/tdtiles/Serve.java | 56 +++++++++----- .../baremaps/server/TdTilesResources.java | 74 ++++++++----------- pom.xml | 1 + 3 files changed, 68 insertions(+), 63 deletions(-) diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java index d1b4e78ef..522f2678e 100644 --- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java +++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java @@ -19,16 +19,19 @@ -import io.servicetalk.http.netty.HttpServers; -import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder; +import static org.apache.baremaps.utils.ObjectMapperUtils.objectMapper; + +import com.linecorp.armeria.common.HttpHeaderNames; +import com.linecorp.armeria.common.HttpMethod; +import com.linecorp.armeria.server.Server; +import com.linecorp.armeria.server.annotation.JacksonResponseConverterFunction; +import com.linecorp.armeria.server.cors.CorsService; +import com.linecorp.armeria.server.file.FileService; +import com.linecorp.armeria.server.file.HttpFile; import java.util.concurrent.Callable; -import javax.sql.DataSource; import org.apache.baremaps.cli.Options; -import org.apache.baremaps.server.CorsFilter; import org.apache.baremaps.server.TdTilesResources; import org.apache.baremaps.utils.PostgresUtils; -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; @@ -55,24 +58,39 @@ public class Serve implements Callable { @Override public Integer call() throws Exception { + var objectMapper = objectMapper(); var datasource = PostgresUtils.createDataSource(database); - // Configure the application - var application = - new ResourceConfig().register(CorsFilter.class).register(TdTilesResources.class) - .register(new AbstractBinder() { - @Override - protected void configure() { - bind(datasource).to(DataSource.class); - } - }); + var serverBuilder = Server.builder(); + serverBuilder.http(port); + + var jsonResponseConverter = new JacksonResponseConverterFunction(objectMapper); + serverBuilder.annotatedService(new TdTilesResources(datasource), jsonResponseConverter); + + var index = HttpFile.of(ClassLoader.getSystemClassLoader(), "/tdtiles/index.html"); + serverBuilder.service("/", index.asService()); + serverBuilder.serviceUnder("/", FileService.of(ClassLoader.getSystemClassLoader(), "/tdtiles")); + + serverBuilder.decorator(CorsService.builderForAnyOrigin() + .allowRequestMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE, + HttpMethod.OPTIONS, HttpMethod.HEAD) + .allowRequestHeaders(HttpHeaderNames.ORIGIN, HttpHeaderNames.CONTENT_TYPE, + HttpHeaderNames.ACCEPT, HttpHeaderNames.AUTHORIZATION) + .allowCredentials() + .exposeHeaders(HttpHeaderNames.LOCATION) + .newDecorator()); + + serverBuilder.disableServerHeader(); + serverBuilder.disableDateHeader(); + + var server = serverBuilder.build(); - var httpService = new HttpJerseyRouterBuilder().buildBlockingStreaming(application); - var serverContext = HttpServers.forPort(port).listenBlockingStreamingAndAwait(httpService); + var startFuture = server.start(); + startFuture.join(); - logger.info("Listening on {}", serverContext.listenAddress()); + var shutdownFuture = server.closeOnJvmShutdown(); + shutdownFuture.join(); - serverContext.awaitShutdown(); return 0; } } diff --git a/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java index 8a60b8057..c67403d11 100644 --- a/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java +++ b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java @@ -18,56 +18,58 @@ package org.apache.baremaps.server; import static com.google.common.net.HttpHeaders.*; +import static io.netty.handler.codec.http.HttpHeaders.Values.APPLICATION_JSON; +import static io.netty.handler.codec.http.HttpHeaders.Values.BINARY; +import com.linecorp.armeria.common.HttpData; +import com.linecorp.armeria.common.HttpResponse; +import com.linecorp.armeria.common.ResponseHeaders; +import com.linecorp.armeria.server.annotation.Get; +import com.linecorp.armeria.server.annotation.Param; import de.javagl.jgltf.model.NodeModel; -import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; -import javax.inject.Singleton; import javax.sql.DataSource; -import javax.ws.rs.GET; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; + import org.apache.baremaps.tdtiles.GltfBuilder; import org.apache.baremaps.tdtiles.TdTilesStore; import org.apache.baremaps.tdtiles.building.Building; import org.apache.baremaps.tdtiles.subtree.Availability; import org.apache.baremaps.tdtiles.subtree.Subtree; -@Singleton -@javax.ws.rs.Path("/") public class TdTilesResources { + + private static final ResponseHeaders GLB_HEADERS = ResponseHeaders.builder(200) + .add(CONTENT_TYPE, BINARY) + .add(ACCESS_CONTROL_ALLOW_ORIGIN, "*") + .build(); + + private static final ResponseHeaders JSON_HEADERS = ResponseHeaders.builder(200) + .add(CONTENT_TYPE, APPLICATION_JSON) + .add(ACCESS_CONTROL_ALLOW_ORIGIN, "*") + .build(); + private final TdTilesStore tdTilesStore; - @Inject public TdTilesResources(DataSource dataSource) { this.tdTilesStore = new TdTilesStore(dataSource); } - @GET - @javax.ws.rs.Path("/subtrees/{level}.{x}.{y}.json") - public Response getSubtree(@PathParam("level") int level, @PathParam("x") int x, - @PathParam("y") int y) { + @Get("regex:^/subtrees/(?[0-9]+).(?[0-9]+).(?[0-9]+).json") + public HttpResponse getSubtree(@Param("level") int level, @Param("x") int x, @Param("y") int y) { if (level == 18) { - return Response.ok() - .entity( - new Subtree(new Availability(false), new Availability(true), new Availability(false))) - .header(CONTENT_TYPE, "application/json").build(); + return HttpResponse.ofJson(JSON_HEADERS, + new Subtree(new Availability(false), new Availability(true), new Availability(false))); } - return Response.ok() - .entity(new Subtree(new Availability(true), new Availability(true), new Availability(true))) - .header(CONTENT_TYPE, "application/json").build(); + return HttpResponse.ofJson(JSON_HEADERS, + new Subtree(new Availability(true), new Availability(true), new Availability(true))); } - @GET - @javax.ws.rs.Path("/content/content_{level}__{x}_{y}.glb") - public Response getContent(@PathParam("level") int level, @PathParam("x") int x, - @PathParam("y") int y) throws Exception { + @Get("regex:^/content/content_(?[0-9]+)__(?[0-9]+)_(?[0-9]+).glb") + public HttpResponse getContent(@Param("level") int level, @Param("x") int x, @Param("y") int y) + throws Exception { if (level < 14) { - return Response.ok().entity( - GltfBuilder.createGltf(new ArrayList<>())).build(); + return HttpResponse.of(GLB_HEADERS, HttpData.wrap(GltfBuilder.createGltf(new ArrayList<>()))); } float[] coords = xyzToLatLonRadians(x, y, level); List nodes = new ArrayList<>(); @@ -77,23 +79,7 @@ public Response getContent(@PathParam("level") int level, @PathParam("x") int x, float tolerance = level > 17 ? 0.00001f : level > 15 ? 0.00002f : 0.00004f; nodes.add(GltfBuilder.createNode(building, tolerance)); } - return Response.ok().entity( - GltfBuilder.createGltf(nodes)).build(); - } - - @GET - @javax.ws.rs.Path("/{path:.*}") - public Response get(@PathParam("path") String path) { - if (path.equals("") || path.endsWith("/")) { - path += "index.html"; - } - path = String.format("tdtiles/%s", path); - try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path)) { - var bytes = inputStream.readAllBytes(); - return Response.ok().entity(bytes).build(); - } catch (IOException e) { - return Response.status(404).build(); - } + return HttpResponse.of(GLB_HEADERS, HttpData.wrap(GltfBuilder.createGltf(nodes))); } /** diff --git a/pom.xml b/pom.xml index 49ff9e30a..5c528afb0 100644 --- a/pom.xml +++ b/pom.xml @@ -93,6 +93,7 @@ limitations under the License. 5.0.1 1.52 2.16.1 + 2.0.3 1.35 1.19.0 5.10.0 From afbdf05b2601ff034dc6218adad0201c8fc262c4 Mon Sep 17 00:00:00 2001 From: Bertil Chapuis Date: Mon, 25 Mar 2024 16:01:02 +0100 Subject: [PATCH 7/7] Format code --- .../main/java/org/apache/baremaps/server/TdTilesResources.java | 1 - 1 file changed, 1 deletion(-) diff --git a/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java index c67403d11..b328f5c66 100644 --- a/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java +++ b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java @@ -30,7 +30,6 @@ import java.util.ArrayList; import java.util.List; import javax.sql.DataSource; - import org.apache.baremaps.tdtiles.GltfBuilder; import org.apache.baremaps.tdtiles.TdTilesStore; import org.apache.baremaps.tdtiles.building.Building;