| /* |
| * 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.opengis.util.GenericName; |
| import org.opengis.metadata.Metadata; |
| import org.apache.sis.coverage.grid.PixelInCell; |
| import org.opengis.referencing.crs.CoordinateReferenceSystem; |
| 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.apache.sis.storage.base.MetadataBuilder; |
| |
| |
| /** |
| * 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.5 |
| * @since 1.2 |
| */ |
| 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 information about this tile matrix. |
| * The metadata should contain at least the following information: |
| * |
| * <ul class="verbose"> |
| * <li>{@code metadata} / |
| * {@link org.apache.sis.metadata.iso.DefaultMetadata#getIdentificationInfo() identificationInfo} / |
| * {@link org.apache.sis.metadata.iso.identification.AbstractIdentification#getCitation() citation} / |
| * {@link org.apache.sis.metadata.iso.citation.DefaultCitation#getTitle() title}:<br> |
| * a human-readable designation for this tile matrix.</li> |
| * <li>{@code metadata} / |
| * {@link org.apache.sis.metadata.iso.DefaultMetadata#getIdentificationInfo() identificationInfo} / |
| * {@link org.apache.sis.metadata.iso.identification.AbstractIdentification#getCitation() citation} / |
| * {@link org.apache.sis.metadata.iso.citation.DefaultCitation#getIdentifier() identifier}:<br> |
| * this {@code TileMatrix} {@linkplain #getIdentifier() identifier}.</li> |
| * <li>{@code metadata} / |
| * {@link org.apache.sis.metadata.iso.DefaultMetadata#getIdentificationInfo() identificationInfo} / |
| * {@link org.apache.sis.metadata.iso.identification.AbstractIdentification#getExtents() extent}:<br> |
| * this {@code TileMatrix} envelope.</li> |
| * <li>{@code metadata} / |
| * {@link org.apache.sis.metadata.iso.DefaultMetadata#getIdentificationInfo() identificationInfo} / |
| * {@link org.apache.sis.metadata.iso.identification.AbstractIdentification#getSpatialResolutions() spatialResolution}:<br> |
| * this {@code TileMatrix} resolution along spatial dimensions.</li> |
| * <li>{@code metadata} / |
| * {@link org.apache.sis.metadata.iso.DefaultMetadata#getIdentificationInfo() identificationInfo} / |
| * {@link org.apache.sis.metadata.iso.identification.AbstractIdentification#getTemporalResolutions() temporalResolution}:<br> |
| * this {@code TileMatrix} resolution along the temporal dimension.</li> |
| * <li>{@code metadata} / |
| * {@link org.apache.sis.metadata.iso.DefaultMetadata#getReferenceSystemInfo() referenceSystemInfo}:<br> |
| * this {@code TileMatrix} coordinate reference system.</li> |
| * <li>{@code metadata} / |
| * {@link org.apache.sis.metadata.iso.DefaultMetadata#getIdentificationInfo() identificationInfo} / |
| * {@link org.apache.sis.metadata.iso.identification.AbstractIdentification#getResourceFormats() resourceFormat}:<br> |
| * a description of the tile format.</li> |
| * </ul> |
| * |
| * <h4>Note for implementers</h4> |
| * The default implementation creates a modifiable {@link org.apache.sis.metadata.iso.DefaultMetadata} instance |
| * with values derived from {@link #getIdentifier()}, {@link #getTilingScheme()} and {@link #getResolution()}. |
| * Subclasses (not users) can cast and complete those metadata. |
| * In particular, implementations are encouraged to add the {@code title} and {@code resourceFormat} information. |
| * |
| * @return information about this tile matrix. |
| * |
| * @since 1.5 |
| */ |
| default Metadata getMetadata() { |
| final var mb = new MetadataBuilder(); |
| mb.addIdentifier(getIdentifier(), MetadataBuilder.Scope.RESOURCE); |
| final GridGeometry gg = getTilingScheme(); |
| if (gg != null) { |
| if (gg.isDefined(GridGeometry.ENVELOPE)) { |
| mb.addExtent(gg.getEnvelope(), null); |
| } |
| if (gg.isDefined(GridGeometry.CRS)) { |
| CoordinateReferenceSystem crs = gg.getCoordinateReferenceSystem(); |
| mb.addReferenceSystem(crs); |
| mb.addSpatioTemporalResolution(getResolution(), crs.getCoordinateSystem()); |
| // Do not add `gg.getResolution()` because this is not the pixel resolution. |
| } |
| } |
| return mb.build(); |
| } |
| |
| /* |
| * There is no `getTileSize()` method because tiles are not necessarily for grid coverages. |
| * Tile size do not apply to vector tiles, quantized mesh or 3D tiles. |
| */ |
| |
| /** |
| * Returns the resolution (in units of CRS axes) at which tiles in this matrix should be used. |
| * If the tiled data is a {@link org.apache.sis.coverage.grid.GridCoverage}, |
| * then the resolution is typically the size of pixels in units of CRS axes. |
| * That resolution may be evaluated at some representative point such as coverage center |
| * if the pixel size is not constant everywhere. |
| * |
| * <p>The array length shall be the number of CRS dimensions, and value at index <var>i</var> |
| * is the resolution along CRS dimension <var>i</var> in units of the CRS axis <var>i</var>.</p> |
| * |
| * @return resolution (in units of CRS axes) at which tiles in this matrix should be used. |
| * |
| * @see GridGeometry#getResolution(boolean) |
| */ |
| double[] getResolution(); |
| |
| /** |
| * 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 <i>tiling scheme</i>, |
| * 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; |
| } |