diff --git a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/FeatureEncoderMVT.java b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/FeatureEncoderMVT.java index 7b0518a5b..85fd9dd30 100644 --- a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/FeatureEncoderMVT.java +++ b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/FeatureEncoderMVT.java @@ -60,13 +60,12 @@ public FeatureEncoderMVT(TileGenerationContext encodingContext) { super(encodingContext); this.parameters = encodingContext.getParameters(); this.tile = encodingContext.getCoordinates(); - this.tileEncoder = new VectorTileEncoder(tile.getTileMatrixSet().getTileExtent()); + final int tileExtent = parameters.getTileExtentOrDefault(tile.getTileMatrixSet()); + this.tileEncoder = new VectorTileEncoder(tileExtent); this.affineTransformation = createTransformNativeToTile(); this.tileset = encodingContext.getTileset(); this.tilePrecisionModel = - new PrecisionModel( - (double) tile.getTileMatrixSet().getTileExtent() - / (double) tile.getTileMatrixSet().getTileSize()); + new PrecisionModel((double) tileExtent / (double) tile.getTileMatrixSet().getTileSize()); this.geometryFactoryTile = new GeometryFactory(tilePrecisionModel); this.geometryFactoryWorld = new GeometryFactory(); diff --git a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileBuilderDefault.java b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileBuilderDefault.java index 0d66683e9..32d08a746 100644 --- a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileBuilderDefault.java +++ b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileBuilderDefault.java @@ -258,7 +258,9 @@ private FeatureQuery getFeatureQuery( .limit(tileset.getFeatureLimit()) .offset(0) .crs(tile.getTileMatrixSet().getCrs()) - .maxAllowableOffset(getMaxAllowableOffset(tile, nativeCrs)); + .maxAllowableOffset( + getMaxAllowableOffset( + tile, nativeCrs, tileset.getTileExtentOrDefault(tile.getTileMatrixSet()))); if (tileset.getFilters().containsKey(tile.getTileMatrixSet().getId())) { tileset.getFilters().get(tile.getTileMatrixSet().getId()).stream() @@ -310,10 +312,10 @@ private FeatureQuery getFeatureQuery( return queryBuilder.build(); } - public double getMaxAllowableOffset(TileCoordinates tile, EpsgCrs nativeCrs) { + public double getMaxAllowableOffset(TileCoordinates tile, EpsgCrs nativeCrs, int tileExtent) { double maxAllowableOffsetTileMatrixSet = tile.getTileMatrixSet() - .getMaxAllowableOffset(tile.getLevel(), tile.getRow(), tile.getCol()); + .getMaxAllowableOffset(tile.getLevel(), tile.getRow(), tile.getCol(), tileExtent); Unit tmsCrsUnit = crsInfo.getUnit(tile.getTileMatrixSet().getCrs()); Unit nativeCrsUnit = crsInfo.getUnit(nativeCrs); if (tmsCrsUnit.equals(nativeCrsUnit)) { diff --git a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileBuilderPgisAsMvt.java b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileBuilderPgisAsMvt.java index db697f68e..ea34293fc 100644 --- a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileBuilderPgisAsMvt.java +++ b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileBuilderPgisAsMvt.java @@ -290,19 +290,16 @@ private String queryToSql( .map(FeatureSchema::getName); String filter = filtersToSql(providerId, tileset, schema, tms.getId(), level); - int buffer = (tms.getTileExtent() / tms.getTileSize()) * TileBuilder.BUFFER_SIZE_FORMAL; + int tileExtent = tileset.getTileExtentOrDefault(tms); + // the buffer is in the units of the internal coordinate system, so it has to be derived from + // the tile extent to stay proportional to the tile + int buffer = (tileExtent / tms.getTileSize()) * TileBuilder.BUFFER_SIZE_FORMAL; String bounds = "bounds AS (SELECT %1$s AS geom, %2$s::box2d AS b2d)"; String mvtgeom = String.format( "mvtgeom AS (SELECT ST_AsMVTGeom(ST_Transform(A.%1$s, %%3$s), bounds.b2d, %6$d, %7$d) AS geom, %2$s FROM %3$s A, bounds WHERE (%5$s AND ST_Intersects(A.%1$s, ST_Transform(bounds.geom, %4$s))))", - geomColumn, - attrColumns, - table, - nativeCrs.getCode(), - filter, - tms.getTileExtent(), - buffer); + geomColumn, attrColumns, table, nativeCrs.getCode(), filter, tileExtent, buffer); String template = String.format( @@ -310,7 +307,7 @@ private String queryToSql( bounds, mvtgeom, schema.getName(), - tms.getTileExtent(), + tileExtent, idProperty.map(id -> ", '" + id + "'").orElse("")); queryTemplates.put(key, template); diff --git a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileEncoderMvt.java b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileEncoderMvt.java index 3949a0891..83ecbfe1e 100644 --- a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileEncoderMvt.java +++ b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/app/TileEncoderMvt.java @@ -43,10 +43,14 @@ public byte[] empty(TileMatrixSetBase tms) { public byte[] combine( TileQuery tile, TileProviderFeaturesData data, ChainedTileProvider tileProvider) throws IOException { - TilesetFeatures combinedTileset = data.getTilesets().get(tile.getTileset()); + TilesetFeatures combinedTileset = + data.getTilesets().get(tile.getTileset()).mergeDefaults(data.getTilesetDefaults()); List tilesets = getLayerTilesets(data, combinedTileset, tile.getGenerationParametersTransient()); - VectorTileEncoder encoder = new VectorTileEncoder(tile.getTileMatrixSet().getTileExtent()); + // the layers of the source tilesets are decoded to a normalized coordinate space, so a source + // tileset with a different tile extent is rescaled to the tile extent of the combined tileset + VectorTileEncoder encoder = + new VectorTileEncoder(combinedTileset.getTileExtentOrDefault(tile.getTileMatrixSet())); VectorTileDecoder decoder = new VectorTileDecoder(); for (String tileset : tilesets) { diff --git a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileGenerationOptions.java b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileGenerationOptions.java index f302b2176..4e8d817d8 100644 --- a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileGenerationOptions.java +++ b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileGenerationOptions.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Objects; import javax.annotation.Nullable; public interface TileGenerationOptions { @@ -97,4 +98,30 @@ public interface TileGenerationOptions { * @since v4.3 */ List getProfiles(); + + /** + * @langEn The width and height of a tile in the internal coordinate system that is used for the + * coordinates in a vector tile. A higher value increases the geometric precision of the tiles + * and reduces the simplification of the geometries, but it also increases the size of the + * tiles. The value should be a power of 2. Renderers typically restrict the internal + * precision, MapLibre for example normalizes all coordinates to a value of `8192`, so higher + * values have no effect in such clients. Changing the value invalidates the content of + * existing tile caches, the tiles have to be seeded again. + * @langDe Die Breite und Höhe einer Kachel in dem internen Koordinatensystem, das für die + * Koordinaten in einer Vector Tile verwendet wird. Ein höherer Wert erhöht die geometrische + * Genauigkeit der Kacheln und reduziert die Vereinfachung der Geometrien, erhöht aber auch + * die Größe der Kacheln. Der Wert sollte eine Zweierpotenz sein. Renderer beschränken die + * interne Genauigkeit üblicherweise, MapLibre normalisiert zum Beispiel alle Koordinaten auf + * einen Wert von `8192`, höhere Werte haben in solchen Clients daher keinen Effekt. Eine + * Änderung des Werts invalidiert den Inhalt bestehender Tile-Caches, die Kacheln müssen + * erneut geseedet werden. + * @default 4096 + * @since v4.9 + */ + @Nullable + Integer getTileExtent(); + + default int getTileExtentOrDefault(TileMatrixSetBase tileMatrixSet) { + return Objects.isNull(getTileExtent()) ? tileMatrixSet.getTileExtent() : getTileExtent(); + } } diff --git a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileMatrixSet.java b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileMatrixSet.java index e385a6fd4..94a57f548 100644 --- a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileMatrixSet.java +++ b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileMatrixSet.java @@ -151,8 +151,24 @@ default int getRows(int level) { * scheme */ default double getMaxAllowableOffset(int level, int row, int col) { + return getMaxAllowableOffset(level, row, col, getTileExtent()); + } + + /** + * determine the Douglas-Peucker distance parameter for a tile that uses a tile extent that + * differs from the tile extent of the tiling scheme + * + * @param level the zoom level + * @param row the row + * @param col the column + * @param tileExtent the width/height of the tile in its internal coordinate system + * @return the distance in the units of measure of the coordinate references system of the tiling + * scheme + */ + @Override + default double getMaxAllowableOffset(int level, int row, int col, int tileExtent) { BoundingBox bbox = getBoundingBox(); - return (bbox.getXmax() - bbox.getXmin()) / getCols(level) / getTileExtent(); + return (bbox.getXmax() - bbox.getXmin()) / getCols(level) / tileExtent; } /** diff --git a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileMatrixSetBase.java b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileMatrixSetBase.java index 01d0f239a..3c3aea39a 100644 --- a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileMatrixSetBase.java +++ b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TileMatrixSetBase.java @@ -31,5 +31,7 @@ public interface TileMatrixSetBase { double getMaxAllowableOffset(int level, int row, int col); + double getMaxAllowableOffset(int level, int row, int col, int tileExtent); + int getTmsRow(int level, int row); } diff --git a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TilesetFeatures.java b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TilesetFeatures.java index 7fd25ebf6..3865902d5 100644 --- a/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TilesetFeatures.java +++ b/xtraplatform-tiles/src/main/java/de/ii/xtraplatform/tiles/domain/TilesetFeatures.java @@ -69,6 +69,11 @@ public interface TilesetFeatures @Override Boolean getSparse(); + @DocIgnore + @Nullable + @Override + Integer getTileExtent(); + @DocIgnore @Override Map> getTransformations(); @@ -157,6 +162,9 @@ default TilesetFeatures mergeDefaults(TilesetFeaturesDefaults defaults) { if (Objects.isNull(this.getSparse()) && Objects.nonNull(defaults.getSparse())) { withDefaults.sparse(defaults.getSparse()); } + if (Objects.isNull(this.getTileExtent()) && Objects.nonNull(defaults.getTileExtent())) { + withDefaults.tileExtent(defaults.getTileExtent()); + } return withDefaults.build(); }