This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push: new c82e6ab TileMatrix : add TileMatrixSet API c82e6ab is described below commit c82e6abffa0deb6b4e8dbd6d54b3456073bfb09d Author: jsorel <johann.so...@geomatys.com> AuthorDate: Tue Mar 8 17:33:49 2022 +0100 TileMatrix : add TileMatrixSet API --- .../sis/storage/IncompatibleResourceException.java | 59 +++++++++ .../java/org/apache/sis/storage/tiling/Tile.java | 93 +++++++++++++ .../org/apache/sis/storage/tiling/TileMatrix.java | 145 +++++++++++++++++++++ .../apache/sis/storage/tiling/TileMatrixSet.java | 91 +++++++++++++ .../org/apache/sis/storage/tiling/TileStatus.java | 69 ++++++++++ .../apache/sis/storage/tiling/TiledResource.java | 52 ++++++++ .../sis/storage/tiling/WritableTileMatrix.java | 61 +++++++++ .../sis/storage/tiling/WritableTileMatrixSet.java | 84 ++++++++++++ .../sis/storage/tiling/WritableTiledResource.java | 76 +++++++++++ .../apache/sis/storage/tiling/package-info.java | 75 +++++++++++ 10 files changed, 805 insertions(+) diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/IncompatibleResourceException.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/IncompatibleResourceException.java new file mode 100644 index 0000000..717762e --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/IncompatibleResourceException.java @@ -0,0 +1,59 @@ +/* + * 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.sis.storage; + + +/** + * Thrown when a write operation can not be performed because the resource to write + * is incompatible with the data store. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * @since 1.2 + * @module + */ +public class IncompatibleResourceException extends DataStoreException { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = -1833794980891065300L; + + /** + * Creates an exception with no cause and no details message. + */ + public IncompatibleResourceException() { + } + + /** + * Creates an exception with the specified details message. + * + * @param message the detail message. + */ + public IncompatibleResourceException(String message) { + super(message); + } + + /** + * Creates an exception with the specified details message and cause. + * + * @param message the detail message. + * @param cause the cause for this exception. + */ + public IncompatibleResourceException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/Tile.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/Tile.java new file mode 100644 index 0000000..c131cae --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/Tile.java @@ -0,0 +1,93 @@ +/* + * 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.sis.storage.tiling; + +import org.apache.sis.coverage.grid.GridExtent; +import org.apache.sis.coverage.grid.GridGeometry; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.GridCoverageResource; +import org.apache.sis.storage.Resource; + + +/** + * A small hyper-rectangular representation of data which is part of a tiling scheme. + * A tile is uniquely defined in a tile matrix by an integer index in each dimension. + * Tiles can be a coverage subsets, or a feature based representation (e.g. vector tiles). + * + * <p>All methods in this interface return non-null values.</p> + * + * @author Johann Sorel (Geomatys) + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * + * @see TileMatrix#getTiles(GridExtent, boolean) + * + * @since 1.2 + * @module + */ +public interface Tile { + /** + * Returns the indices of this tile in the {@code TileMatrix}. + * If this tile was obtained by a call to {@link TileMatrix#getTile(long...)}, + * then the returned array contains the indices that were given in that call. + * + * <p>The returned array contains coordinates in the space defined by + * the {@linkplain GridGeometry#getExtent() extent} of + * the {@linkplain TileMatrix#getTilingScheme() tiling scheme}. + * As such, it complies with the following constraints:</p> + * <ul> + * <li>The array length is equal to {@link GridExtent#getDimension()}.</li> + * <li>The axis order — usually (<var>column</var>, <var>row/</var>) — is the + * {@linkplain GridExtent#getAxisType(int) extent axis} order.</li> + * <li>Values are between the {@linkplain GridExtent#getLow(int) extent low} + * and {@linkplain GridExtent#getHigh(int) high} values, inclusive.</li> + * </ul> + * + * @return indices of this tile in the {@link TileMatrix}, + * as coordinates inside the matrix {@link GridExtent}. + * + * @see TileMatrix#getTile(long...) + */ + long[] getIndices(); + + /** + * Returns information about whether the tile failed to load. + * The return value can be {@link TileStatus#EXISTS} or {@link TileStatus#IN_ERROR}; + * other enumeration values should not happen after a user successfully obtained this {@code Tile} instance. + * + * <h4>State transition</h4> + * {@link TileStatus#EXISTS} is not a guarantee that a call to {@link #getResource()} will succeed. + * The error may be detected only during the first attempt to read the resource. + * Consequently this method may initially return {@code EXISTS}, + * then return {@code IN_ERROR} later after the first read attempt. + * + * @return information about the availability of this tile. + * + * @see TileMatrix#getTileStatus(long...) + */ + TileStatus getStatus(); + + /** + * Returns the tile content as a resource. + * The resource type is typically {@link GridCoverageResource}, + * but it may also be other types (e.g. vector tiles). + * + * @return the tile content. + * @throws DataStoreException if an error occurred while reading the content. + */ + Resource getResource() throws DataStoreException; +} diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TileMatrix.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TileMatrix.java new file mode 100644 index 0000000..6598b5f --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TileMatrix.java @@ -0,0 +1,145 @@ +/* + * 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.sis.storage.tiling; + +import java.util.Optional; +import java.util.stream.Stream; +import org.apache.sis.coverage.grid.GridExtent; +import org.apache.sis.coverage.grid.GridGeometry; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.NoSuchDataException; +import org.opengis.referencing.datum.PixelInCell; +import org.opengis.util.GenericName; + + +/** + * A collection of tiles with the same size and properties placed on a regular grid with no overlapping. + * A tile matrix usually has 2 dimensions (width and height), but this API allows any number of dimensions. + * The number of dimensions is given by {@code getTilingScheme().getDimension()}. + * + * <p>Unless otherwise specified in the Javadoc, + * all methods in this interface expect non-null arguments are return non-null values.</p> + * + * @author Johann Sorel (Geomatys) + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * @since 1.2 + * @module + */ +public interface TileMatrix { + /** + * Returns an alphanumeric identifier which is unique in the {@link TileMatrixSet} that contains + * this {@code TileMatrix}. The identifier is often a zoom level (as a number encoded in ASCII), + * but this is not mandatory. + * + * @return a unique (within {@link TileMatrixSet}) identifier. + */ + GenericName getIdentifier(); + + /** + * Returns a description about how space is partitioned into individual tiled units. + * The description contains the extent of valid tile indices, the spatial reference system, + * and the conversion from tile indices to the spatial reference system coordinates. + * The CRS <em>shall</em> be the same as {@link TileMatrixSet#getCoordinateReferenceSystem()}. + * The "grid to CRS" transform <em>should</em> be defined and <em>should</em> be affine. + * The grid geometry <em>shall</em> have a {@link GridExtent} which gives the range of valid indices + * that can be used in calls to {@link #getTile(long...)} and {@link #getTileStatus(long...)} methods. + * + * <p>The "grid to CRS" transform converts tile indices to "real world" coordinates. + * This conversion can follow two conventions:</p> + * + * <ul class="verbose"> + * <li>The {@link PixelInCell#CELL_CORNER} convention maps tile indices to the extreme corner + * (in the direction of smallest indices) of the bounding box of the tile. + * In a two-dimensional space having the usual display axis orientations, + * this is the top-left corner of the top-left pixel.</li> + * <li>The {@link PixelInCell#CELL_CENTER} convention maps tile indices to the median value + * of the tile bounding box in all dimensions.</li> + * </ul> + * + * <h4>Relationship with OGC specification</h4> + * OGC has a more generic definition of <cite>tiling scheme</cite>, + * where the scheme specifies which space a uniquely identified tile occupies. + * Reversely, the tiling scheme makes possible to find which unique identifier + * corresponds to a space satisfying the geometric properties to be a tile. + * In {@code TileMatrix}, the unique identifier of a tile is the sequence of + * tile indices stored in a {@code long[]} array. + * The space occupied by a tile can be computed by the above-cited "grid to CRS" transform. + * Reversely the tile indices for a given space can be computed by the inverse of the "grid to CRS" transform. + * + * @return extent of valid tile indices (mandatory) and their relationship with "real world" coordinates (optional). + * + * @see TileMatrixSet#getCoordinateReferenceSystem() + */ + GridGeometry getTilingScheme(); + + /** + * Fetches information about whether a tile exists, is missing or failed to load. + * The accuracy of a tile status greatly varies with each protocol. + * If the returned value is different than {@link TileStatus#UNKNOWN}, then: + * + * <table class="sis"> + * <caption>Relationship between return value and tile fetching behavior}</caption> + * <tr><th>Return value</th> <th>Consequence</th></tr> + * <tr><td>{@link TileStatus#EXISTS}</td> <td>{@code getTile(indices)} should return a non-empty value.</td></tr> + * <tr><td>{@link TileStatus#MISSING}</td> <td>{@code getTile(indices)} should return an empty value.</td></tr> + * <tr><td>{@link TileStatus#OUTSIDE_EXTENT}</td> <td>{@code getTile(indices)} should throw {@link NoSuchDataException}.</td></tr> + * <tr><td>{@link TileStatus#IN_ERROR}</td> <td>{@code getTile(indices)} should throw {@link DataStoreException} (or a sub-type).</td></tr> + * </table> + * + * @param indices indices of the requested tile (may be outside the tile matrix extent). + * @return information about the availability of the specified tile, + * or {@link TileStatus#OUTSIDE_EXTENT} if the given indices are invalid. + * @throws DataStoreException if fetching the tile status failed. + * + * @see Tile#getStatus() + */ + TileStatus getTileStatus(long... indices) throws DataStoreException; + + /** + * Gets a tile at the given indices. + * + * @param indices indices of the tile to fetch, as coordinates inside the matrix {@link GridExtent}. + * @return the tile if it {@linkplain TileStatus#EXISTS exists}, + * or an empty value if the tile is {@linkplain TileStatus#MISSING missing}. + * @throws NoSuchDataException if the given indices are + * {@linkplain TileStatus#OUTSIDE_EXTENT outside the matrix extent}. + * @throws DataStoreException if fetching the tile failed for another reason. + */ + Optional<Tile> getTile(long... indices) throws DataStoreException; + + /** + * Retrieves a stream of existing tiles in the specified region. The stream contains + * the {@linkplain TileStatus#EXISTS existing} tiles that are inside the given region + * and excludes all {@linkplain TileStatus#MISSING missing} tiles. + * If a tile is {@linkplain TileStatus#IN_ERROR in error}, + * then the stream should nevertheless return a {@link Tile} instance + * but its {@link Tile#getResource()} method should throw the exception. + * + * <p>The {@code parallel} argument specifies whether a parallelized stream is desired. + * If {@code false}, the stream is guaranteed to be sequential. + * If {@code true}, the stream may or may not be parallel; + * implementations are free to ignore this argument if they do not support parallelism.</p> + * + * @param indicesRanges ranges of tile indices in all dimensions, or {@code null} for all tiles. + * @param parallel {@code true} for a parallel stream (if supported), or {@code false} for a sequential stream. + * @return stream of tiles, excluding {@linkplain TileStatus#MISSING missing} tiles. + * Iteration order of the stream may vary from one implementation to another and from one call to another. + * @throws DataStoreException if the stream creation failed. + */ + Stream<Tile> getTiles(GridExtent indicesRanges, boolean parallel) throws DataStoreException; +} diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TileMatrixSet.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TileMatrixSet.java new file mode 100644 index 0000000..277d9ee --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TileMatrixSet.java @@ -0,0 +1,91 @@ +/* + * 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.sis.storage.tiling; + +import java.util.Optional; +import java.util.SortedMap; +import org.opengis.geometry.Envelope; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.util.GenericName; + + +/** + * A collection of {@code TileMatrix} in the same CRS but at different scale levels. + * Each {@code TileMatrix} is optimized for a particular scale and is identified by a tile matrix identifier. + * Tile matrices usually have 2 dimensions (width and height), but this API allows any number of dimensions. + * However the number of dimensions must be the same for all tile matrices. + * + * <p>The {@code TileMatrixSet} concept is derived from OGC standards. The same concept is called + * <cite>image pyramid</cite> or <cite>resolution levels</cite> in some other standards. + * Some standards require that all scales must be related by a power of 2, + * but {@code TileMatrixSet} does not have this restriction.</p> + * + * <h2>Tile matrix identification</h2> + * Each {@link TileMatrix} in a {@code TileMatrixSet} is identified by a {@link GenericName}. + * Identifiers can be any character strings. + * A common practice is to use zoom levels as identifiers, but this is not mandatory. + * However tile matrices must be sorted from coarser resolution (highest scale denominator) + * to most detailed resolution (lowest scale denominator). + * + * <p>All methods in this interface return non-null values.</p> + * + * @author Johann Sorel (Geomatys) + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * @since 1.2 + * @module + */ +public interface TileMatrixSet { + /** + * Returns an alphanumeric identifier which is unique in the {@link TiledResource} that contains + * this {@code TileMatrixSet}. A tiled resource may contains more than one tile matrix set if the + * resource prepared different set of tiles for different CRS. + * + * @return a unique (within {@link TiledResource}) identifier. + */ + GenericName getIdentifier(); + + /** + * Returns the coordinate reference system of all {@code TileMatrix} instances in this set. + * This is the value returned by {@code TileMatrix.getTilingScheme().getCoordinateReferenceSystem()}. + * + * @return the CRS used by all {@code TileMatrix} instances in this set. + * + * @see TileMatrix#getTilingScheme() + */ + CoordinateReferenceSystem getCoordinateReferenceSystem(); + + /** + * Returns an envelope that encompasses all {@code TileMatrix} instances in this set. + * This is the {@linkplain org.apache.sis.geometry.GeneralEnvelope#add(Envelope) union} + * of all values returned by {@code TileMatrix.getTilingScheme().getEnvelope()}. + * May be empty if too costly to compute. + * + * @return the bounding box for all tile matrices in CRS coordinates, if available. + */ + Optional<Envelope> getEnvelope(); + + /** + * Returns all {@link TileMatrix} instances in this set, together with their identifiers. + * For each value in the map, the associated key is {@link TileMatrix#getIdentifier()}. + * Entries are sorted from coarser resolution (highest scale denominator) to most detailed + * resolution (lowest scale denominator). + * + * @return unmodifiable collection of all {@code TileMatrix} instances with their identifiers. + */ + SortedMap<GenericName, ? extends TileMatrix> getTileMatrices(); +} diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TileStatus.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TileStatus.java new file mode 100644 index 0000000..d23f14f --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TileStatus.java @@ -0,0 +1,69 @@ +/* + * 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.sis.storage.tiling; + +import java.io.IOException; + + +/** + * Information about the availability of a tile. Some {@link TileMatrix} implementations + * may not know whether a tile exists or not before the first attempt to read that tile. + * Consequently a tile status may be initially {@link #UNKNOWN} and transitions + * at a later time to a state such as {@link #EXISTS}, {@link #MISSING} or {@link #IN_ERROR}. + * + * @author Alexis Manin (Geomatys) + * @author Johann Sorel (Geomatys) + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * + * @see Tile#getStatus() + * @see TileMatrix#getTileStatus(long...) + * + * @since 1.2 + * @module + */ +public enum TileStatus { + /** + * The tile status can not be known unless the tile is read. This value is returned + * by some {@link TileMatrix} implementations when determining the availability of + * a tile would require relatively costly I/O operations. + */ + UNKNOWN, + + /** + * The tile exists. However this is not a guarantee that no I/O error will happen when reading the tile, + * neither that the tile will be non-empty. If an I/O error happens at tile reading time, + * then the tile status should transition from {@code EXISTS} to {@link #IN_ERROR}. + */ + EXISTS, + + /** + * The tile is flagged as missing. It may happen in regions where no data is available. + */ + MISSING, + + /** + * The tile for which a status has been requested is outside the {@link TileMatrix} extent. + */ + OUTSIDE_EXTENT, + + /** + * The tile exists but attempt to read it failed. + * It may be because an {@link IOException} occurred while reading the tile. + */ + IN_ERROR +} diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TiledResource.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TiledResource.java new file mode 100644 index 0000000..fef9de3 --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/TiledResource.java @@ -0,0 +1,52 @@ +/* + * 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.sis.storage.tiling; + +import java.util.Collection; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.Resource; + + +/** + * A resource which content can be accessed by smaller chunks called tiles. + * The use of {@code TiledResource} is not strictly necessary for efficient data loading because + * {@code Resource} implementations should automatically take advantage of tiling when answering requests. + * However clients may use this information for optimizing their loading strategy. + * + * <p>A {@code TiledResource} may contain multiple {@link TileMatrixSet} instances, + * each one for a different {@link org.opengis.referencing.crs.CoordinateReferenceSystem}. + * Most format specifications only support a single {@link TileMatrixSet}, + * but a few ones like WMTS may have several.</p> + * + * <p>All methods in this interface return non-null values.</p> + * + * @author Johann Sorel (Geomatys) + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * @since 1.2 + * @module + */ +public interface TiledResource extends Resource { + /** + * Returns the collection of all available tile matrix sets in this resource. + * The returned collection typically contains exactly one instance. + * + * @return all available {@link TileMatrixSet} instances, or an empty collection if none. + * @throws DataStoreException if an error occurred while fetching the tile matrix sets. + */ + Collection<? extends TileMatrixSet> getTileMatrixSets() throws DataStoreException; +} diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/WritableTileMatrix.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/WritableTileMatrix.java new file mode 100644 index 0000000..24d2f65 --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/WritableTileMatrix.java @@ -0,0 +1,61 @@ +/* + * 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.sis.storage.tiling; + +import java.util.stream.Stream; +import org.apache.sis.coverage.grid.GridExtent; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.IncompatibleResourceException; +import org.apache.sis.storage.ReadOnlyStorageException; + + +/** + * A {@code TileMatrix} that can write and delete tiles. + * + * <p>All methods in this interface expect non-null arguments.</p> + * + * @author Johann Sorel (Geomatys) + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * @since 1.2 + * @module + */ +public interface WritableTileMatrix extends TileMatrix { + /** + * Writes a stream of tiles. The caller must ensure that all tiles are compatible + * with the {@linkplain #getTilingScheme() tiling scheme} of this tile matrix set. + * If a tile already exists, it will be overwritten. + * + * @param tiles the tiles to write. + * @throws ReadOnlyStorageException if this tile matrix is not writable. It may be caused by insufficient credentials. + * @throws IncompatibleResourceException if a tile is not compatible with the tiling scheme of this tile matrix. + * @throws DataStoreException if writing the tiles failed for another reason. + */ + void writeTiles(Stream<Tile> tiles) throws DataStoreException; + + /** + * Deletes all existing tiles in the given region. + * After this method call, the status of all tiles in the given region become {@link TileStatus#MISSING}. + * Tiles that were already missing are silently ignored. + * + * @param indicesRanges ranges of tile indices in all dimensions, or {@code null} for all tiles. + * @return number of tiles deleted (i.e. not counting the tiles that were already missing). + * @throws ReadOnlyStorageException if this tile matrix is not writable. It may be caused by insufficient credentials. + * @throws DataStoreException if deleting the tile failed for another reason. + */ + long deleteTiles(GridExtent indicesRanges) throws DataStoreException; +} diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/WritableTileMatrixSet.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/WritableTileMatrixSet.java new file mode 100644 index 0000000..961b9f2 --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/WritableTileMatrixSet.java @@ -0,0 +1,84 @@ +/* + * 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.sis.storage.tiling; + +import java.util.SortedMap; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.IncompatibleResourceException; +import org.apache.sis.storage.NoSuchDataException; +import org.apache.sis.storage.ReadOnlyStorageException; +import org.opengis.util.GenericName; + + +/** + * A {@code TileMatrixSet} that can write and delete tile matrices. + * + * <p>All methods in this interface expect non-null arguments are return non-null values.</p> + * + * @author Johann Sorel (Geomatys) + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * @since 1.2 + * @module + */ +public interface WritableTileMatrixSet extends TileMatrixSet { + /** + * Returns all {@link WritableTileMatrix} instances in this set, together with their identifiers. + * For each value in the map, the associated key is {@link WritableTileMatrix#getIdentifier()}. + * Entries are sorted from coarser resolution (highest scale denominator) + * to most detailed resolution (lowest scale denominator). + * + * <p>The returned view is unmodifiable but live: creations or removals of tile matrices + * in this set will be reflected on the returned map.</p> + * + * @return an unmodifiable view of all {@code WritableTileMatrix} instances with their identifiers. + */ + @Override + SortedMap<GenericName, ? extends WritableTileMatrix> getTileMatrices(); + + /** + * Adds the given tile matrix to this set and returns a writable instance for later completion. + * Typically the given {@link TileMatrix} instance contains no tile and is used only as a template. + * If the {@code TileMatrix} is not empty, then the tiles that it contains are written immediately. + * + * <p>The {@linkplain TileMatrix#getTilingScheme() tiling scheme} of the given tile matrix must + * be compatible with this set. In particular, it must use the same CRS than the value returned + * by {@link #getCoordinateReferenceSystem()}. If not, an {@link IncompatibleResourceException} + * is thrown.</p> + * + * <p>This method returns a writable tile matrix with the same tiles than the given {@code TileMatrix}. + * However the identifier of the returned tile matrix may be different.</p> + * + * @param tiles the (potentially empty) tile matrix to create. + * @return a writable tile matrix to use for adding more tiles. + * @throws ReadOnlyStorageException if this tile matrix set is not writable. It may be caused by insufficient credentials. + * @throws IncompatibleResourceException if the tiling scheme of the given tile matrix is not compatible with this set. + * @throws DataStoreException if creating the tile matrix failed for another reason. + */ + WritableTileMatrix createTileMatrix(TileMatrix tiles) throws DataStoreException; + + /** + * Deletes a {@code TileMatrix} identified by the given name. The given identifier shall be the + * <code>{@linkplain TileMatrix#getIdentifier()}.toString()</code> value of the tile matrix to delete. + * + * @param identifier identifier of the {@link TileMatrix} to delete. + * @throws NoSuchDataException if there is no tile matrix associated to the given identifier in this set. + * @throws ReadOnlyStorageException if this tile matrix set is not writable. It may be caused by insufficient credentials. + * @throws DataStoreException if deleting the tile matrix failed for another reason. + */ + void deleteTileMatrix(String identifier) throws DataStoreException; +} diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/WritableTiledResource.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/WritableTiledResource.java new file mode 100644 index 0000000..b4d95ab --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/WritableTiledResource.java @@ -0,0 +1,76 @@ +/* + * 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.sis.storage.tiling; + +import java.util.Collection; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.IncompatibleResourceException; +import org.apache.sis.storage.NoSuchDataException; +import org.apache.sis.storage.ReadOnlyStorageException; + + +/** + * A {@code TiledResource} that can write and delete tile matrix sets. + * + * <p>All methods in this interface expect non-null arguments are return non-null values.</p> + * + * @author Johann Sorel (Geomatys) + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * @since 1.2 + * @module + */ +public interface WritableTiledResource extends TiledResource { + /** + * Returns the collection of all available tile matrix sets in this resource. + * The returned collection is unmodifiable but live: additions or removals of + * tile matrix sets in this resource are reflected in the returned collection. + * + * @return an unmodifiable view of all {@link TileMatrixSet} instances in this resource. + * @throws DataStoreException if an error occurred while fetching the tile matrix sets. + */ + @Override + Collection<? extends WritableTileMatrixSet> getTileMatrixSets() throws DataStoreException; + + /** + * Adds the given tile matrix set to this resource and returns a writable instance for later completion. + * Typically the given {@link TileMatrixSet} instance contains no tile and is used only as a template. + * If the {@code TileMatrixSet} is not empty, then the tiles that it contains are written immediately. + * + * <p>This method returns a writable tile matrix set with the same tiles than the given {@code TileMatrixSet}. + * The identifier and the envelope of the returned set may be different, but the CRS and tiling scheme shall + * be equivalent with a tolerance for rounding errors.</p> + * + * @param tiles the (potentially empty) tile matrix set to create. + * @return a writable tile matrix set to use for adding more tiles. + * @throws ReadOnlyStorageException if this resource is not writable. It may be caused by insufficient credentials. + * @throws IncompatibleResourceException if the given tile matrix set is incompatible with this resource. + * @throws DataStoreException if creating the tile matrix set failed for another reason. + */ + WritableTileMatrixSet createTileMatrixSet(TileMatrixSet tiles) throws DataStoreException; + + /** + * Deletes a {@code TileMatrixSet} identified by the given name. The given identifier shall be the + * <code>{@linkplain TileMatrixSet#getIdentifier()}.toString()</code> value of the set to delete. + * + * @param identifier identifier of the {@link TileMatrixSet} to delete. + * @throws NoSuchDataException if there is no tile matrix set associated to the given identifier in this resource. + * @throws ReadOnlyStorageException if this resource is not writable. It may be caused by insufficient credentials. + * @throws DataStoreException if deleting the tile matrix set failed for another reason. + */ + void removeTileMatrixSet(String identifier) throws DataStoreException; +} diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/package-info.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/package-info.java new file mode 100644 index 0000000..7e1fe91 --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/tiling/package-info.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + + +/** + * Base types for retrieving and saving tiles in resources. + * A {@link TiledResource} if a resource capable to describe its tiling schemes as {@link TileMatrixSet} instances. + * A {@link TileMatrixSet} is a collection of {@link TileMatrix} instances in the same CRS but at different scale levels. + * A {@link TileMatrix} is a collection of {@link Tile} instances with the same size and properties placed on a regular grid with no overlapping. + * The "tile" word is used because of its wide usage with two-dimensional data, but actually this package has no restriction + * on the number of dimensions and can work with multi-dimensional "tiles" as well. + * + * <h2>References</h2> + * <ul> + * <li><a href="https://www.ogc.org/standards/tms">OGC Two Dimensional Tile Matrix Set</a> — the core standard used in this package.</li> + * <li><a href="https://www.ogc.org/standards/wmts">OGC Web Map Tile Service (WMTS)</a> — a common use of above standard.</li> + * <li><a href="https://docs.opengeospatial.org/is/17-066r1/17-066r1.html">OGC Geopackage: Extension for Tiled Gridded Coverage Data</a> — another common use.</li> + * <li><a href="https://docs.ogc.org/per/18-074.html">OGC Geopackage: Extension for vector tiles</a> — experimental work for tiled geometries.</li> + * </ul> + * + * The concepts developed in above references are also used, often with different names, by other projects such as + * <a href="https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification">OSGeo Tile Map Service Specification</a>, + * <a href="https://github.com/CesiumGS/quantized-mesh">Cesium QuantizedMesh</a>, + * <a href="https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">Open Street Map: Slippy Map</a>, + * <a href="https://developers.google.com/maps/documentation/javascript/coordinates">Google Map</a> and + * <a href="https://docs.mapbox.com/mapbox-tiling-service/guides/">MapBox Tiling service</a>. + * + * + * <h2>Relationship with OGC specifications</h2> + * The {@code TileMatrix} and {@code TileMatrixSet} class names are reused as defined by OGC. + * The "2D" suffix in class names is omitted because this package is fully multi-dimensional. + * The concept of "tiling scheme" is encapsulated in a {@link org.apache.sis.coverage.grid.GridGeometry}. + * + * <h3>Departures with OGC specifications</h3> + * The OGC {@code TileMatrixLimits} class is replaced by {@link org.apache.sis.coverage.grid.GridExtent}. + * The OGC restriction against negative numbers is removed (Apache SIS accepts negative tile indices). + * The <var>tile span</var> and <var>tile matrix min/max</var> coefficients are replaced by a more generic + * "grid to CRS" {@link org.opengis.referencing.operation.MathTransform}, usually affine but not necessarily. + * Users may need to enforce above OGC restrictions themselves if compatibility with OGC specification is desired). + * + * + * <h2>Relationship with Java2D rendered image</h2> + * OGC tiles can be mapped to {@linkplain java.awt.image.RenderedImage#getTile(int, int) Java2D tiles} + * with the following restrictions: + * + * <ul> + * <li>Java2D tile indices and pixel indices are 32 bits integer instead of 64 bits. + * See {@linkplain org.apache.sis.coverage.grid.GridCoverage#render grid coverage render} + * (in particular the relative pixel coordinates) for the workaround applied in Apache SIS.</li> + * <li>Java2D does not support coalescence coefficient (used in OGC tiles for compensating distortions near poles). + * Tiles in Java2D are expanded as needed as if the {@code TileMatrix} had no coalescence.</li> + * </ul> + * + * @author Johann Sorel (Geomatys) + * @author Alexis Manin (Geomatys) + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * @since 1.2 + * @module + */ +package org.apache.sis.storage.tiling;