blob: 376d8eb0bd75ef7d5eca3e22b153675387129b30 [file] [log] [blame]
/*
* 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;
}