This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-3.1
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 76ac26bca233fd47b797ce44f4418b35c62bc849
Merge: 8c45b25f06 3a021d2345
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Tue Mar 31 16:08:05 2026 +0200

    Merge branch 'geoapi-4.0' into geoapi-3.1.
    Contains (non-exhaustive list):
    
    - Implementation of `TileMatrixSet` by the GeoTIFF reader.
    - Redesign of the controls over coverage rendering in JavaFX.
    - Work in the geometry package (incubator).
    - Bug fixes.

 .../sis/coverage/grid/ClippedGridCoverage.java     |   3 +-
 .../org/apache/sis/coverage/grid/GridCoverage.java |  12 +-
 .../apache/sis/coverage/grid/GridCoverage2D.java   |   3 +-
 .../sis/coverage/grid/GridCoverageBuilder.java     |  53 +-
 .../apache/sis/coverage/grid/GridDerivation.java   |   2 +-
 .../org/apache/sis/coverage/grid/GridExtent.java   |  61 +-
 .../org/apache/sis/coverage/grid/GridGeometry.java |  24 +-
 .../main/org/apache/sis/feature/FeatureFormat.java |   8 +-
 .../feature/internal/shared/MovingFeatures.java    |  28 +-
 .../org/apache/sis/filter/ComparisonFilter.java    | 141 ++++-
 .../main/org/apache/sis/filter/LogicalFilter.java  |  15 +-
 .../main/org/apache/sis/filter/Optimization.java   |   2 +-
 .../sis/filter/base/BinaryFunctionWidening.java    |   3 +-
 .../apache/sis/filter/math/FilteringFunction.java  |  62 ++
 .../main/org/apache/sis/filter/math/Predicate.java |  28 +-
 .../main/org/apache/sis/image/BandedIterator.java  |  23 +
 .../main/org/apache/sis/image/ComputedImage.java   |  20 +-
 .../main/org/apache/sis/image/ComputedTiles.java   |  26 +-
 .../main/org/apache/sis/image/ImageProcessor.java  |   4 +-
 .../main/org/apache/sis/image/PlanarImage.java     |   2 +-
 .../apache/sis/image/WritablePixelIterator.java    |  50 +-
 .../sis/image/internal/shared/ReshapedImage.java   | 128 ++++-
 .../main/org/apache/sis/image/package-info.java    |   2 +-
 .../sis/coverage/grid/ClippedGridCoverageTest.java |   1 +
 .../apache/sis/coverage/grid/GridExtentTest.java   |  10 +-
 .../apache/sis/filter/ComparisonFilterTest.java    |  98 ++--
 .../apache/sis/filter/DynamicOptimizationTest.java |  19 +
 .../image/internal/shared/ReshapedImageTest.java   |  15 +-
 .../iso/extent/NotSpatioTemporalException.java     |   4 +-
 .../metadata/sql/internal/shared/ScriptRunner.java |   2 +-
 .../org.apache.sis.portrayal/main/module-info.java |   2 +-
 .../coverage/MultiResolutionCoverageLoader.java    |  46 +-
 .../org/apache/sis/map/coverage/RenderingData.java |  53 +-
 .../org/apache/sis/map/internal/Resources.java     | 102 ++++
 .../apache/sis/map/internal/Resources.properties   |  23 +
 .../org/apache/sis/map/internal/Resources_en.java  |  14 +-
 .../org/apache/sis/map/internal/Resources_fr.java  |  14 +-
 .../sis/map/internal/Resources_fr.properties       |  28 +
 .../org/apache/sis/map/internal}/package-info.java |  11 +-
 .../main/org/apache/sis/portrayal/Observable.java  |   2 -
 .../org/apache/sis/portrayal/PlanarCanvas.java     |   7 +-
 .../MultiResolutionCoverageLoaderTest.java         |  18 +-
 .../main/org/apache/sis/geometry/Shapes2D.java     |   2 +-
 .../main/org/apache/sis/referencing/CommonCRS.java |   8 +-
 .../referencing/internal/shared/WKTUtilities.java  |   4 +-
 .../operation/CoordinateOperationContext.java      |  31 +-
 .../operation/CoordinateOperationFinder.java       |  30 +-
 .../operation/CoordinateOperationRegistry.java     |  63 +-
 .../DefaultCoordinateOperationFactory.java         |  58 +-
 .../referencing/operation/SubOperationInfo.java    |   8 +-
 .../sis/referencing/operation/matrix/Matrices.java |   4 +-
 .../sis/referencing/operation/package-info.java    |   2 +-
 .../operation/transform/PassThroughTransform.java  |   2 +-
 .../main/module-info.java                          |   2 +-
 .../sis/storage/geotiff/CompressedSubset.java      |  18 +-
 .../org/apache/sis/storage/geotiff/DataCube.java   |  65 +--
 .../org/apache/sis/storage/geotiff/DataSubset.java |  36 +-
 .../apache/sis/storage/geotiff/GeoTiffStore.java   |   2 +-
 .../sis/storage/geotiff/ImageFileDirectory.java    | 218 +++++--
 .../sis/storage/geotiff/MultiResolutionImage.java  | 286 ---------
 .../org/apache/sis/storage/geotiff/Reader.java     |  22 +-
 .../apache/sis/storage/geotiff/package-info.java   |   2 +-
 .../sis/storage/geotiff/GeoTiffStoreTest.java      |  56 +-
 .../org/apache/sis/storage/geotiff/ReaderTest.java | 124 ++++
 .../org/apache/sis/storage/geotiff/WriterTest.java |   5 +-
 .../org/apache/sis/storage/geotiff/untiled.tiff    | Bin 0 -> 2284 bytes
 .../apache/sis/storage/netcdf/base/FeatureSet.java |  62 +-
 .../sis/storage/netcdf/base/RasterResource.java    |   2 +
 .../org/apache/sis/io/stream/ChannelDataInput.java |   2 +-
 .../sis/storage/AbstractGridCoverageResource.java  |  82 ++-
 .../org/apache/sis/storage/CoverageSubset.java     |  11 +-
 .../main/org/apache/sis/storage/DataStore.java     |  18 +-
 .../apache/sis/storage/GridCoverageResource.java   |  41 +-
 .../main/org/apache/sis/storage/Resource.java      |   4 +-
 .../org/apache/sis/storage/StorageConnector.java   |  25 +-
 .../sis/storage/UnsupportedQueryException.java     |   1 +
 .../aggregate/BandAggregateGridResource.java       |   4 +-
 .../aggregate/ConcatenatedGridResource.java        |  12 +-
 .../apache/sis/storage/aggregate/GridSlice.java    |  12 +-
 .../sis/storage/aggregate/GridSliceLocator.java    |   5 +-
 .../sis/storage/base/GridResourceWrapper.java      |   6 +-
 .../main/org/apache/sis/storage/csv/Store.java     |  13 +-
 .../org/apache/sis/storage/event/StoreEvent.java   |   2 +-
 .../apache/sis/storage/event/StoreListeners.java   |  14 +-
 .../org/apache/sis/storage/event/package-info.java |   4 +-
 .../apache/sis/storage/image/SingleImageStore.java |   6 +-
 .../storage/image/WritableSingleImageStore.java    |   4 +-
 .../org/apache/sis/storage/internal/Resources.java |   5 +
 .../sis/storage/internal/Resources.properties      |   1 +
 .../sis/storage/internal/Resources_fr.properties   |   1 +
 .../apache/sis/storage/tiling/ImagePyramid.java    | 472 +++++++++++++++
 .../apache/sis/storage/tiling/ImageTileMatrix.java | 532 +++++++++++++++++
 .../apache/sis/storage/tiling/IterationDomain.java | 221 +++++++
 .../main/org/apache/sis/storage/tiling/Tile.java   |   4 +-
 .../org/apache/sis/storage/tiling/TileMatrix.java  |  11 +-
 .../apache/sis/storage/tiling/TileMatrixSet.java   |  12 +-
 .../sis/storage/tiling/TileMatrixSetFormat.java    | 524 +++++++++++++++++
 .../apache/sis/storage/tiling/TileReadEvent.java   | 234 ++++++++
 .../org/apache/sis/storage/tiling/TileStatus.java  |   2 +-
 .../{base => tiling}/TiledDeferredImage.java       |  21 +-
 .../{base => tiling}/TiledGridCoverage.java        | 500 ++++++++++------
 .../TiledGridCoverageResource.java}                | 599 +++++++++++++++++--
 .../apache/sis/storage/tiling/TiledResource.java   |   4 +-
 .../apache/sis/storage/tiling/package-info.java    |  10 +-
 .../org/apache/sis/storage/CoverageQueryTest.java  |   8 +-
 .../storage/MemoryGridCoverageResourceTest.java    |   6 +-
 .../sis/storage/test/CoverageReadConsistency.java  |   2 +-
 .../main/org/apache/sis/io/TableAppender.java      |  16 +-
 .../main/org/apache/sis/io/TabularFormat.java      |   4 +-
 .../main/org/apache/sis/io/package-info.java       |   2 +-
 .../main/org/apache/sis/math/DecimalFunctions.java |  29 +-
 .../main/org/apache/sis/math/NumberType.java       |   2 +-
 .../main/org/apache/sis/math/Vector.java           |   2 +-
 .../main/org/apache/sis/util/ArgumentChecks.java   |  26 +-
 .../main/org/apache/sis/util/collection/Cache.java |   4 +-
 .../org/apache/sis/util/collection/Containers.java |  30 +-
 .../apache/sis/util/collection/DerivedList.java    |  31 +-
 .../sis/util/collection/WeakValueHashMap.java      |   6 +-
 .../sis/util/collection/WritableDerivedList.java   | 143 +++++
 .../sis/util/internal/shared/AbstractMap.java      |   2 +-
 .../apache/sis/util/internal/shared/Numerics.java  | 118 +++-
 .../org/apache/sis/util/resources/Vocabulary.java  |  20 +
 .../sis/util/resources/Vocabulary.properties       |   4 +
 .../sis/util/resources/Vocabulary_fr.properties    |   4 +
 .../org/apache/sis/math/DecimalFunctionsTest.java  |  32 +-
 .../{DerivedSetTest.java => DerivedListTest.java}  |  66 +--
 .../apache/sis/util/collection/DerivedMapTest.java |   1 +
 .../apache/sis/util/collection/DerivedSetTest.java |   1 +
 .../BilinearGrid.java                              |   3 +-
 .../{parametriccurvesurfaces => }/Cone.java        |   4 +-
 .../{parametriccurvesurfaces => }/Cylinder.java    |   4 +-
 .../main/org/apache/sis/geometries/Geometries.java |  24 +-
 .../ParametricCurveSurface.java                    |   2 +-
 .../apache/sis/geometries/{rhumb => }/Rhumb.java   |   2 +-
 .../main/org/apache/sis/geometries/Sphere.java     |  66 ++-
 .../apache/sis/geometries/math/AbstractAffine.java | 163 ++++++
 .../apache/sis/geometries/math/AbstractArray.java  |  21 +-
 .../apache/sis/geometries/math/AbstractCursor.java |   2 +-
 .../apache/sis/geometries/math/AbstractMatrix.java | 636 +++++++++++++++++++++
 .../sis/geometries/math/AbstractSimilarity.java    | 329 +++++++++++
 .../apache/sis/geometries/math/AbstractTuple.java  |   4 +-
 .../org/apache/sis/geometries/math/Affine.java     | 122 ++++
 .../org/apache/sis/geometries/math/Affine1D.java   | 161 ++++++
 .../org/apache/sis/geometries/math/Affine2D.java   | 226 ++++++++
 .../org/apache/sis/geometries/math/Affine3D.java   | 365 ++++++++++++
 .../org/apache/sis/geometries/math/Affine4D.java   | 482 ++++++++++++++++
 .../org/apache/sis/geometries/math/AffineND.java   |  99 ++++
 .../org/apache/sis/geometries/math/Affines.java}   |  22 +-
 .../main/org/apache/sis/geometries/math/Array.java |  30 +-
 .../sis/geometries/math/ArrayConcatenated.java     |  11 +-
 .../apache/sis/geometries/math/ArrayFactory.java   | 278 +++++++++
 .../sis/geometries/math/ArrayFactoryFFM.java       | 489 ++++++++++++++++
 .../{ArrayMemory.java => ArrayFactoryJava.java}    | 428 ++++----------
 .../sis/geometries/math/ArraySpliterator.java      |   6 +-
 .../sis/geometries/math/ArrayUnmodifiable.java     |  11 +-
 .../org/apache/sis/geometries/math/Cursor.java     |   2 +-
 .../sis/geometries/math/CursorUnmodifiable.java    |   8 +-
 .../main/org/apache/sis/geometries/math/Maths.java |  32 +-
 .../org/apache/sis/geometries/math/Matrices.java   | 338 +----------
 .../org/apache/sis/geometries/math/Matrix.java     | 137 ++++-
 .../org/apache/sis/geometries/math/Matrix2D.java   | 214 ++++++-
 .../org/apache/sis/geometries/math/Matrix3D.java   | 471 ++++++++++++++-
 .../org/apache/sis/geometries/math/Matrix4D.java   | 470 +++++++++++++--
 .../org/apache/sis/geometries/math/MatrixND.java   | 477 ++++++++++++++++
 .../org/apache/sis/geometries/math/NDArray.java    |  15 +-
 .../org/apache/sis/geometries/math/NDArrays.java   |  83 +--
 .../org/apache/sis/geometries/math/Quaternion.java |  53 +-
 .../apache/sis/geometries/math/Quaternions.java    |   2 +-
 .../org/apache/sis/geometries/math/ReadOnly.java   | 592 +++++++++++++++++++
 .../org/apache/sis/geometries/math/Similarity.java | 200 +++++++
 .../apache/sis/geometries/math/Similarity3D.java   | 197 +++++++
 .../apache/sis/geometries/math/SimilarityND.java   | 195 +++++++
 .../sis/geometries/math/SimplifiedTransform.java   | 106 ++++
 .../org/apache/sis/geometries/math/Transform.java  | 134 +++++
 .../{CursorUnmodifiable.java => Transform1D.java}  |  54 +-
 .../main/org/apache/sis/geometries/math/Tuple.java | 237 +-------
 .../sis/geometries/math/TupleUnmodifiable.java     |  24 +-
 .../org/apache/sis/geometries/math/Vector.java     |  93 +--
 .../org/apache/sis/geometries/math/Vector1D.java   |  26 +-
 .../org/apache/sis/geometries/math/Vector2D.java   |  26 +-
 .../org/apache/sis/geometries/math/Vector3D.java   |  31 +-
 .../org/apache/sis/geometries/math/Vector4D.java   |  42 +-
 .../org/apache/sis/geometries/math/VectorND.java   |  63 +-
 .../org/apache/sis/geometries/math/Vectors.java    |  30 +-
 .../apache/sis/geometries/math/package-info.java   |  20 +-
 .../apache/sis/geometries/mesh/MeshPrimitive.java  |  14 +-
 .../geometries/operation/GeometryOperations.java   |  10 +-
 .../{ => operation}/simplify/TextureAtlas.java     |   2 +-
 .../simplify/greedyinsert/Edge.java                |   2 +-
 .../simplify/greedyinsert/TINBuilder.java          |   2 +-
 .../simplify/greedyinsert/TinDistance.java         |   2 +-
 .../simplify/greedyinsert/WTriangle.java           |   8 +-
 .../{ => operation}/triangulate/EarClipping.java   |  18 +-
 .../triangulate/delaunay/Delaunay.java             |   2 +-
 .../triangulate/delaunay/OrientedEdge.java         |   2 +-
 .../triangulate/delaunay/OrientedTriangle.java     |   2 +-
 .../geometries/parametriccurvesurfaces/Sphere.java |  30 -
 .../processor/spatialedition/ToPrimitive.java      |   2 +-
 .../AbstractArray.java => scene/Animation.java}    |  67 +--
 .../AnimationSampler.java}                         |  63 +-
 .../org/apache/sis/geometries/scene/Camera.java    | 242 ++++++++
 .../org/apache/sis/geometries/scene/Material.java  | 627 ++++++++++++++++++++
 .../org/apache/sis/geometries/scene/Model.java     | 216 +++++++
 .../apache/sis/geometries/scene/MorphTarget.java   | 110 ++++
 .../org/apache/sis/geometries/scene/Sampler.java   | 172 ++++++
 .../org/apache/sis/geometries/scene/SceneNode.java | 510 +++++++++++++++++
 .../{math/AbstractArray.java => scene/Skin.java}   |  73 ++-
 .../org/apache/sis/geometries/scene/Surface.java   | 117 ++++
 .../org/apache/sis/geometries/scene/Texture.java   | 142 +++++
 .../apache/sis/geometries/scene}/package-info.java |  12 +-
 .../geometries/splinesurfaces/BSplineSurface.java  |   2 +-
 .../apache/sis/geometries/math/ArrayNbTest.java    |   2 +-
 .../apache/sis/geometries/math/ArrayNdTest.java    |   2 +-
 .../apache/sis/geometries/math/ArrayNfTest.java    |   2 +-
 .../apache/sis/geometries/math/ArrayNiTest.java    |   2 +-
 .../apache/sis/geometries/math/ArrayNlTest.java    |   2 +-
 .../apache/sis/geometries/math/ArrayNsTest.java    |   2 +-
 .../apache/sis/geometries/math/ArrayNubTest.java   |   2 +-
 .../apache/sis/geometries/math/ArrayNuiTest.java   |   2 +-
 .../apache/sis/geometries/math/ArrayNusTest.java   |   2 +-
 .../apache/sis/geometries/math/NDArraysTest.java   |   4 +-
 .../apache/sis/geometries/math/QuaternionTest.java |  35 +-
 .../{ => operation}/simplify/TextureAtlasTest.java |   2 +-
 .../triangulate/delaunay/DelaunayTest.java         |   2 +-
 .../triangulate/delaunay/OrientedEdgeTest.java     |   2 +-
 .../main/org/apache/sis/map/MapItem.java           |   8 +-
 .../apache/sis/storage/geoheif/FromImageIO.java    |   9 +-
 .../main/org/apache/sis/storage/geoheif/Image.java |   3 +-
 .../apache/sis/storage/geoheif/ImageResource.java  |  34 +-
 .../src/org.apache.sis.gui/main/module-info.java   |   2 +-
 .../main/org/apache/sis/gui/Widget.java            |   8 +-
 .../apache/sis/gui/controls/FormatApplicator.java  |   6 +-
 .../apache/sis/gui/controls/SyncWindowList.java    |   6 +-
 .../apache/sis/gui/controls/ValueColorMapper.java  |  12 +-
 .../apache/sis/gui/coverage/BandRangeTable.java    |   8 +-
 .../apache/sis/gui/coverage/CoverageCanvas.java    | 335 +++++++++--
 .../apache/sis/gui/coverage/CoverageControls.java  | 155 +++--
 .../apache/sis/gui/coverage/CoverageExplorer.java  |  36 +-
 .../apache/sis/gui/coverage/CoverageStyling.java   |  16 +-
 .../apache/sis/gui/coverage/GridSliceSelector.java |  12 +-
 .../sis/gui/coverage/ImagePropertyExplorer.java    |   6 +-
 ...IsolineRenderer.java => IsolineController.java} |  82 ++-
 .../apache/sis/gui/coverage/StyleController.java   | 173 ++++++
 .../sis/gui/coverage/StyledRenderingData.java      |   6 +-
 .../apache/sis/gui/coverage/TileMatrixSetPane.java | 499 ++++++++++++++++
 .../apache/sis/gui/coverage/ViewAndControls.java   |  22 +-
 .../org/apache/sis/gui/coverage/package-info.java  |   2 +-
 .../main/org/apache/sis/gui/dataset/LogViewer.java |   5 +-
 .../org/apache/sis/gui/dataset/ResourceCell.java   | 138 +++--
 .../apache/sis/gui/dataset/ResourceExplorer.java   |  52 +-
 .../org/apache/sis/gui/dataset/ResourceItem.java   | 178 ++++--
 .../org/apache/sis/gui/dataset/ResourceTree.java   |  50 +-
 .../org/apache/sis/gui/dataset/RootResource.java   |  37 +-
 .../org/apache/sis/gui/dataset/WindowHandler.java  |  27 +-
 .../org/apache/sis/gui/dataset/package-info.java   |   2 +-
 .../apache/sis/gui/internal/AlignedTableCell.java  |  87 +++
 .../apache/sis/gui/internal/BackgroundThreads.java |   8 +-
 .../apache/sis/gui/internal/DataStoreOpener.java   |  57 +-
 .../apache/sis/gui/internal/ExceptionReporter.java |  36 +-
 .../org/apache/sis/gui/internal/GUIUtilities.java  |  16 -
 .../org/apache/sis/gui/internal/LogHandler.java    |   2 +-
 .../org/apache/sis/gui/internal/Resources.java     |  20 +
 .../apache/sis/gui/internal/Resources.properties   |   4 +
 .../sis/gui/internal/Resources_fr.properties       |   4 +
 .../apache/sis/gui/internal/ShapeConverter.java    | 153 +++++
 .../main/org/apache/sis/gui/internal/Styles.java   |   6 +
 .../apache/sis/gui/internal/io/FileAccessView.java |   4 +-
 .../org/apache/sis/gui/map/GestureFollower.java    |  18 +-
 .../main/org/apache/sis/gui/map/MapCanvas.java     |  43 +-
 .../main/org/apache/sis/gui/map/MapCanvasAWT.java  |  14 +-
 .../main/org/apache/sis/gui/map/MapMenu.java       |  39 +-
 .../main/org/apache/sis/gui/map/StatusBar.java     | 165 ++++--
 .../main/org/apache/sis/gui/map/package-info.java  |   2 +-
 .../apache/sis/gui/map/style/ItemController.java   |  89 +++
 .../apache/sis/gui/map/style/MapContextView.java   | 143 +++++
 .../main/org/apache/sis/gui/map/style/MapItem.java |  35 +-
 .../org/apache/sis/gui/map/style/MapLayer.java     |  37 +-
 .../org/apache/sis/gui/map/style/package-info.java |  14 +-
 .../sis/gui/metadata/IdentificationInfo.java       |   2 +-
 .../apache/sis/gui/metadata/MetadataSummary.java   |   8 +-
 .../org/apache/sis/gui/referencing/MenuSync.java   |  57 +-
 .../gui/referencing/RecentReferenceSystems.java    | 103 ++--
 .../apache/sis/gui/referencing/package-info.java   |   2 +-
 .../sis/gui/controls/ValueColorMapperApp.java      |   7 +-
 .../main/org/apache/sis/storage/gdal/GDAL.java     | 147 +----
 .../apache/sis/storage/gdal/GDALStoreProvider.java | 126 +++-
 .../org/apache/sis/storage/gdal/TiledCoverage.java |  12 +-
 .../org/apache/sis/storage/gdal/TiledResource.java |  33 +-
 .../org/apache/sis/storage/gdal/package-info.java  |   2 +-
 .../apache/sis/storage/panama/LibraryLoader.java   | 192 ++++---
 .../sis/storage/panama/LibraryReference.java       | 207 +++++++
 .../apache/sis/storage/panama/LibraryStatus.java   |  51 +-
 .../apache/sis/storage/panama/NativeFunctions.java |  91 +--
 .../org/apache/sis/storage/gdal/GDALStoreTest.java |   3 +-
 294 files changed, 17472 insertions(+), 3629 deletions(-)

diff --cc 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileMatrixSetFormat.java
index 0000000000,a132628bb7..abfcbcd9d2
mode 000000,100644..100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileMatrixSetFormat.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileMatrixSetFormat.java
@@@ -1,0 -1,521 +1,524 @@@
+ /*
+  * 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.PrintWriter;
+ import java.io.StringWriter;
+ import java.io.IOException;
+ import java.io.UncheckedIOException;
+ import java.text.Format;
+ import java.util.Locale;
+ import java.util.List;
+ import java.util.ArrayList;
+ import java.util.Map;
+ import java.util.HashMap;
+ import java.util.TimeZone;
+ import java.util.Objects;
+ import java.util.Optional;
+ import java.util.Arrays;
+ import java.util.StringJoiner;
+ import java.text.NumberFormat;
+ import java.text.ParseException;
+ import java.text.ParsePosition;
+ import org.opengis.util.GenericName;
+ import org.opengis.referencing.crs.CoordinateReferenceSystem;
+ import org.opengis.referencing.operation.TransformException;
+ import org.opengis.metadata.extent.GeographicBoundingBox;
+ import org.apache.sis.util.ArraysExt;
+ import org.apache.sis.util.CharSequences;
+ import org.apache.sis.util.logging.Logging;
+ import org.apache.sis.util.resources.Errors;
+ import org.apache.sis.util.resources.Vocabulary;
+ import org.apache.sis.util.internal.shared.Numerics;
+ import org.apache.sis.util.collection.TableColumn;
+ import org.apache.sis.util.collection.TreeTableFormat;
+ import org.apache.sis.util.collection.BackingStoreException;
+ import org.apache.sis.referencing.IdentifiedObjects;
+ import org.apache.sis.coverage.grid.GridExtent;
+ import org.apache.sis.coverage.grid.IncompleteGridGeometryException;
+ import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
+ import org.apache.sis.io.CompoundFormat;
+ import org.apache.sis.io.TableAppender;
+ 
+ 
+ /**
+  * Formats Tile Matrix Sets (<abbr>TMS</abbr>) in a tabular format.
+  * This format assumes a monospaced font and a character encoding which 
supports the drawing of box characters,
+  * such as <abbr>UTF</abbr>-8.
+  *
+  * <h2>Limitations</h2>
+  * <ul>
+  *   <li>The current implementation can only format tile matrices — parsing 
is supported.</li>
+  *   <li>{@code TileMatrixSetFormat}, like most {@code java.text.Format} 
subclasses, is not thread-safe.</li>
+  * </ul>
+  *
+  * @author  Martin Desruisseaux (Geomatys)
+  * @version 1.7
+  * @since   1.7
+  */
+ public class TileMatrixSetFormat extends CompoundFormat<TileMatrixSet> {
+     /**
+      * For cross-version compatibility.
+      */
+     private static final long serialVersionUID = 2612127094991996016L;
+ 
+     /**
+      * Helper class for string representation of an image pyramid as a table.
+      * Each instance describes one table row for one {@link ImageTileMatrix}.
+      */
+     private static final class Row {
+         /** The tile matrix identifier. */
+         final String identifier;
+ 
+         /** The tile matrix resolution in each <abbr>CRS</abbr> dimensions. */
+         final double[] resolution;
+ 
+         /** The string representations of the tile matrix resolution. */
+         final String[] formattedResolution;
+ 
+         /** The number of tiles in each grid dimension. */
+         final String[] tileCount;
+ 
+         /** The tile sizes in pixels. */
+         final String[] tileSize;
+ 
+         /** The extent of the tiling scheme. */
+         private final GridExtent tilingScheme;
+ 
+         /**
+          * Creates one row in the table for the given matrix.
+          *
+          * @param  matrix         the matrix for which to store information.
+          * @param  integerFormat  a number format configured for integer 
values.
+          * @throws BackingStoreException if an error occurred while 
extracting information.
+          * @throws IncompleteGridGeometryException if the tiling scheme has 
not extent or resolution.
+          *         Tile matrices with such tiling scheme should not have been 
constructed in first place.
+          */
+         Row(final TileMatrix matrix, final NumberFormat integerFormat) {
+             final GenericName id = matrix.getIdentifier();
+             identifier = (id != null) ? id.toString() : "";
+             resolution = matrix.getResolution();
+             formattedResolution = new String[resolution.length];
+             tilingScheme = matrix.getTilingScheme().getExtent();
+             tileCount = new String[tilingScheme.getDimension()];
+             for (int i=0; i<tileCount.length; i++) {
+                 tileCount[i] = integerFormat.format(tilingScheme.getSize(i));
+             }
+             final int[] ts = ImageTileMatrix.getTileSize(matrix);
+             tileSize = new String[ts != null ? ts.length : 0];
+             for (int i=0; i<tileSize.length; i++) {
+                 tileSize[i] = integerFormat.format(ts[i]);
+             }
+         }
+ 
+         /**
+          * Updates the axis name in the dimension <var>i</var> of the grid 
extent.
+          * This method verifies that grid dimensions in all rows have the 
same axis names.
+          */
+         private void searchCommonAxisName(final String[] gridAxes, final int 
i) {
+             tilingScheme.getAxisType(i).ifPresent((axis) -> {
 -                final String name = axis.identifier().orElseGet(() -> 
axis.name().toLowerCase(Locale.US));
++                String name = axis.identifier();
++                if (name == null) {
++                    name = axis.name().toLowerCase(Locale.US);
++                }
+                 final String current = gridAxes[i];
+                 if (current == null) {
+                     gridAxes[i] = name;
+                 } else if (!current.equals(name)) {
+                     gridAxes[i] = "";
+                 }
+             });
+         }
+ 
+         /**
+          * Creates the string representation of the resolutions in all 
resolution columns of all rows.
+          * This method computes the number of fraction digits based on the 
resolution values of all rows.
+          *
+          * @param  rows    the rows in which to format the resolutions.
+          * @param  format  the number formats to use. Its number of fraction 
digits will be updated.
+          * @return the maximal number of resolution values found in all rows.
+          *         This value should be equal to the number of dimensions in 
the <abbr>CRS</abbr>.
+          */
+         static int formatResolutions(final List<Row> rows, final NumberFormat 
format) {
+             final var values = new double[rows.size()];
+             for (int i=0; ; i++) {
+                 int count = 0;
+                 for (final Row row : rows) {
+                     if (i < row.resolution.length) {
+                         values[count++] = row.resolution[i];
+                     }
+                 }
+                 if (count == 0) return i;
+                 final int n = 
Numerics.suggestFractionDigits(ArraysExt.resize(values, count));
+                 format.setMinimumFractionDigits(n);
+                 format.setMaximumFractionDigits(n);
+                 final int column = i;   // Because lambda requires final 
values.
+                 final String[] formatted = 
Numerics.formatAndTrimTrailingZeros(format, values.length, (j) -> {
+                     final double[] resolution = rows.get(j).resolution;
+                     return (column < resolution.length) ? resolution[column] 
: Double.NaN;
+                 });
+                 for (int j=0; j<values.length; j++) {
+                     final String[] resolution = 
rows.get(j).formattedResolution;
+                     if (i < resolution.length) {
+                         resolution[i] = formatted[j];
+                     }
+                 }
+             }
+         }
+     }
+ 
+     /**
+      * The error that occurred while formatting a Tile Matrix Set.
+      */
+     private transient Throwable error;
+ 
+     /**
+      * Creates a new formatter using the given locale and timezone.
+      *
+      * @param  locale    the locale for the new {@code Format}, or {@code 
null} for {@code Locale.ROOT}.
+      * @param  timezone  the timezone, or {@code null} for UTC.
+      */
+     public TileMatrixSetFormat(final Locale locale, final TimeZone timezone) {
+         super(locale, timezone);
+     }
+ 
+     /**
+      * Returns the type of values formatted by this {@code Format} instance.
+      *
+      * @return the type of values formatted by this {@code Format} instance.
+      */
+     @Override
+     public final Class<TileMatrixSet> getValueType() {
+         return TileMatrixSet.class;
+     }
+ 
+     /**
+      * Formats the properties of the given Tile Matrix Set for presentation 
before the main table.
+      * The properties are formatted as {@link String}s using the locale given 
at construction time.
+      * The returned map contains the following entries if the corresponding 
properties were found:
+      *
+      * <table class="sis">
+      *   <caption>Tile Matrix Set (<abbr>TMS</abbr>) formatted 
properties</caption>
+      *   <tr><th>Key</th>                  <th>Value type</th>                
           <th>Description</th></tr>
+      *   <tr><td>{@code "identifier"}</td> <td>{@link String}</td>            
           <td>Identifier of the <abbr>TMS</abbr>.</td></tr>
+      *   <tr><td>{@code "referencing"}</td><td>{@link String}</td>            
           <td>Name of the <abbr>CRS</abbr>, or reason why not 
available.</td></tr>
+      *   <tr><td>{@code "crs"}</td>        <td>{@link 
CoordinateReferenceSystem}</td>    <td>The <abbr>CRS</abbr>.</td></tr>
+      *   <tr><td>{@code "bbox"}</td>       <td>{@link 
DefaultGeographicBoundingBox}</td> <td>Bounding box of the 
<abbr>TMS</abbr>.</td></tr>
+      * </table>
+      *
+      * <p>If the {@code "crs"} property is non-null, then the {@code 
"referencing"} property is the <abbr>CRS</abbr> name.
+      * Conversely, if the {@code "crs"} property is null, then the {@code 
"referencing"} property is a message saying that
+      * the <abbr>CRS</abbr> was not available or the reason why it was not 
available.</p>
+      *
+      * The returned properties can be completed by a call to {@link 
#formatTable(Iterable, Map)}.
+      *
+      * @param  matrices  the tile matrices to format.
+      * @return properties of the header of the given tile matrix set.
+      */
+     public Map<String, Object> formatHeader(final TileMatrixSet matrices) {
+         final var addTo = new HashMap<String, Object>();
+         addTo.put("identifier", matrices.getIdentifier());
+         try {
+             try {
+                 final CoordinateReferenceSystem crs = 
matrices.getCoordinateReferenceSystem();
+                 addTo.put("referencing", 
IdentifiedObjects.getDisplayName(crs, getLocale()));
+                 addTo.put("crs", crs);
+             } catch (IncompleteGridGeometryException e) {
+                 addTo.put("referencing", e.getLocalizedMessage());
+             }
+             matrices.getEnvelope().ifPresent((envelope) -> {
+                 try {
+                     final var bbox = new DefaultGeographicBoundingBox();
+                     bbox.setBounds(envelope);
+                     bbox.setInclusion(null);
+                     addTo.put("bbox", bbox);
+                 } catch (TransformException e) {
+                     // Ignore because this exception may be normal if the 
envelope has no spatial component.
+                     Logging.ignorableException(ImageTileMatrix.LOGGER, 
TileMatrixSetFormat.class, "format", e);
+                 }
+             });
+         } catch (BackingStoreException e) {
+             // The CRS or envelope may be missing in the header, but we may 
still be able to format the table.
+             addError(e.getCause());
+         }
+         addTo.values().removeIf(Objects::isNull);
+         return addTo;
+     }
+ 
+     /**
+      * Formats the properties of the given Tile Matrices in a way suitable to 
a tabular format.
+      * The properties are formatted as {@link String}s using the locale given 
at construction time.
+      * The returned map contains the following entries if the corresponding 
properties were found:
+      *
+      * <table class="sis">
+      *   <caption>Tile Matrices formatted properties</caption>
+      *   <tr><th>Key</th>                   <th>Value type</th>         
<th>Description</th></tr>
+      *   <tr><td>{@code "identifiers"}</td> <td>{@code String[]}</td>   
<td>Column of the identifier of each Tile Matrix.</td></tr>
+      *   <tr><td>{@code "resolutions"}</td> <td>{@code String[][]}</td> 
<td>Columns of the resolution of each Tile Matrix.</td></tr>
+      *   <tr><td>{@code "tileCounts"}</td>  <td>{@code String[][]}</td> 
<td>Columns of the number of tiles of each Tile Matrix.</td></tr>
+      *   <tr><td>{@code "tileSizes"}</td>   <td>{@code String[][]}</td> 
<td>Columns of the tile size of each Tile Matrix.</td></tr>
+      *   <tr><td>{@code "gridAxes"}</td>    <td>{@code String[]}</td>   
<td>Name of grid axes.</td></tr>
+      * </table>
+      *
+      * The {@code "tileSizes"} property may be absent if not applicable.
+      * Implementations other than the default implementation may also choose 
to add or remove more properties.
+      *
+      * <p>This method returns the number of rows in the table to format.
+      * The length of the {@code "identifiers"} array is that number of rows.
+      * All other arrays have a length equal to the number of columns in a 
group of columns,
+      * which is 2 in the usual case of two-dimensional Tile Matrix Sets.
+      * The {@code "resolutions[i]"}, {@code "tileCounts[i]"} and {@code 
"tileSizes[i]"} arrays,
+      * where <var>i</var> is a column index, all have a length equal to the 
number of rows.
+      * Some element may be {@code null} if the corresponding data could not 
be extracted.</p>
+      *
+      * @param  matrices  the tile matrices to format.
+      * @param  addTo     where to put the properties of the given tile matrix 
set.
+      * @return number of rows in the table to format.
+      */
+     public int formatTable(final Iterable<? extends TileMatrix> matrices, 
final Map<String, Object> addTo) {
+         final var rows = new ArrayList<Row>();
+         int gridDimension = 0, sizeDimension = 0;
+         final var integerFormat = (NumberFormat) getFormat(Long.class);
+         for (final TileMatrix matrix : matrices) try {
+             final var row = new Row(matrix, integerFormat);
+             gridDimension = Math.max(gridDimension, row.tileCount.length);
+             sizeDimension = Math.max(sizeDimension, row.tileSize.length);
+             rows.add(row);  // Add only on success.
+         } catch (RuntimeException e) {
+             addError(e);    // Skip the row. Next row will be tried.
+         }
+         final int crsDimension = Row.formatResolutions(rows, (NumberFormat) 
getFormat(Double.class));
+         final int numRows     = rows.size();
+         final var identifiers = new String[numRows];
+         final var resolutions = new String[ crsDimension][numRows];
+         final var tileCounts  = new String[gridDimension][numRows];
+         final var tileSizes   = new String[sizeDimension][numRows];
+         final var gridAxes    = new String[gridDimension];
+         for (int j=0; j<numRows; j++) {
+             final Row row = rows.get(j);
+             identifiers[j] = row.identifier;
+             for (int i = Math.min(crsDimension, row.resolution.length); --i 
>= 0;) {
+                 resolutions[i][j] = row.formattedResolution[i];
+             }
+             for (int i = Math.min(gridDimension, row.tileCount.length); --i 
>= 0;) {
+                 tileCounts[i][j] = row.tileCount[i];
+                 row.searchCommonAxisName(gridAxes, i);
+             }
+             for (int i = Math.min(sizeDimension, row.tileSize.length); --i >= 
0;) {
+                 tileSizes[i][j] = row.tileSize[i];
+             }
+         }
+         if (numRows       != 0) addTo.put("identifiers", identifiers);
+         if (crsDimension  != 0) addTo.put("resolutions", resolutions);
+         if (gridDimension != 0) addTo.put("tileCounts",  tileCounts);
+         if (sizeDimension != 0) addTo.put("tileSizes",   tileSizes);
+         for (int i=0; i<gridAxes.length; i++) {
+             final String name = gridAxes[i];
+             if (name != null && name.isBlank()) {
+                 gridAxes[i] = null;
+             }
+         }
+         if (!ArraysExt.allEquals(gridAxes, null)) {
+             addTo.put("gridAxes", gridAxes);
+         }
+         return numRows;
+     }
+ 
+     /**
+      * Returns localized resources for the table header.
+      */
+     private Vocabulary vocabulary() {
+         return Vocabulary.forLocale(getLocale());
+     }
+ 
+     /**
+      * Formats a textual representation of the given tile matrices.
+      * This method delegates to {@link #format(TileMatrixSet, Appendable)}
+      * with a temporary buffer.
+      *
+      * @param  matrices  the tile matrices to format.
+      * @return a string representation of the given Tile Matrix Set.
+      */
+     public String format(TileMatrixSet matrices) {
+         return format(matrices, false);
+     }
+ 
+     /**
+      * Formats the given tile matrices, optionally with a report of 
exceptions.
+      *
+      * @param  matrices     the tile matrices to format.
+      * @param  reportError  whether to report exceptions.
+      * @return a string representation of the given Tile Matrix Set.
+      */
+     final String format(final TileMatrixSet matrices, final boolean 
reportError) {
+         final var buffer = new StringBuilder(1000);
+         try {
+             format(matrices, buffer);
+             if (!reportError || error == null) {
+                 return buffer.toString();
+             }
+             final var writer = new 
StringWriter(buffer.length()).append(buffer);
+             vocabulary().appendLabel(Vocabulary.Keys.Warnings, writer);
+             error.printStackTrace(new PrintWriter(writer.append(' ')));
+             return writer.append(System.lineSeparator()).toString();
+         } catch (IOException e) {
+             throw new UncheckedIOException(e);
+         }
+     }
+ 
+     /**
+      * Formats a textual representation of the given tile matrices.
+      * First, a header is formatted with the <abbr>TMS</abbr> identifier,
+      * the Coordinate Reference System and the geographic bounding box.
+      * Then, each tile matrix is formatted as a row in a table.
+      *
+      * @param  matrices    the tile matrices to format.
+      * @param  toAppendTo  where to format the object.
+      * @throws IOException if an error occurred while writing to the given 
appendable.
+      */
+     @Override
+     public void format(final TileMatrixSet matrices, final Appendable 
toAppendTo) throws IOException {
+         final Vocabulary vocabulary = vocabulary();
+         final Map<String, Object> properties = formatHeader(matrices);
+         final int numRows = formatTable(matrices.getTileMatrices().values(), 
properties);
+         Object value = properties.get("identifier");
+         if (value != null) {
+             
toAppendTo.append(vocabulary.getString(Vocabulary.Keys.TileMatrixSets)).append('
 ')
+                       .append(vocabulary.getString(Vocabulary.Keys.Quoted_1, 
value))
+                       .append(System.lineSeparator());
+         }
+         value = properties.get("referencing");
+         if (value != null) {
+             if (properties.get("crs") != null) {
+                 vocabulary.appendLabel(Vocabulary.Keys.ReferenceSystem, 
toAppendTo);
+                 toAppendTo.append(' ');
+             }
+             
toAppendTo.append(value.toString()).append(System.lineSeparator());
+         }
+         value = properties.get("bbox");
+         if (value != null) {
+             final var bbox = (DefaultGeographicBoundingBox) value;
+             final var mf = (TreeTableFormat) 
getFormat(GeographicBoundingBox.class);
+             mf.setColumns(TableColumn.NAME, TableColumn.VALUE);
+             toAppendTo.append(mf.format(bbox.asTreeTable()));
+         }
+         /*
+          * The header was formatted by above code. The following code formats 
the main table.
+          * First, we get the values to format in all columns and prepend the 
number of spaces
+          * needed for right alignment.
+          */
+         final var identifiers = (String[])   properties.get("identifiers");
+         final var resolutions = (String[][]) properties.get("resolutions");
+         final var tileCounts  = (String[][]) properties.get("tileCounts");
+         final var tileSizes   = (String[][]) properties.get("tileSizes");
+         String[][][] columnGroups = {resolutions, tileCounts, tileSizes};
+         columnGroups = ArraysExt.resize(columnGroups, 
ArraysExt.removeNulls(columnGroups));
+         for (final String[][] columns : columnGroups) {
+             for (final String[] column : columns) {
+                 
Arrays.stream(column).mapToInt(String::length).max().ifPresent((length) -> {
+                     for (int j=0; j<column.length; j++) {
+                         String e  = column[j];
+                         column[j] = CharSequences.spaces(length - e.length()) 
+ e;
+                     }
+                 });
+             }
+         }
+         final var table = new TableAppender(toAppendTo);
+         table.appendHorizontalSeparator();
+         if (identifiers != null) 
table.append(vocabulary.getString(Vocabulary.Keys.Identifier)).nextColumn();
+         if (resolutions != null) 
table.append(vocabulary.getString(Vocabulary.Keys.Resolution)).nextColumn();
+         if (tileCounts  != null) 
table.append(vocabulary.getString(Vocabulary.Keys.TileCount)) .nextColumn();
+         if (tileSizes   != null) 
table.append(vocabulary.getString(Vocabulary.Keys.TileSize))  .nextColumn();
+         table.appendHorizontalSeparator();
+         for (int j=0; j<numRows; j++) {
+             if (identifiers != null) {
+                 table.setCellAlignment(TableAppender.ALIGN_LEFT);
+                 table.append(identifiers[j]).nextColumn();
+                 table.setCellAlignment(TableAppender.ALIGN_RIGHT);
+             }
+             for (final String[][] columns : columnGroups) {
+                 final var joiner = new StringJoiner(" × ");
+                 for (String[] column : columns) {
+                     joiner.add(column[j]);
+                 }
+                 table.append(joiner.toString()).nextColumn();
+             }
+             table.nextLine();
+         }
+         table.appendHorizontalSeparator();
+         table.flush();
+     }
+ 
+     /**
+      * Not supported.
+      *
+      * @return currently never return.
+      * @throws ParseException currently always thrown.
+      * @hidden Not implemented.
+      */
+     @Override
+     public TileMatrixSet parse(CharSequence text, ParsePosition pos) throws 
ParseException {
+         throw new ParseException(Errors.forLocale(getLocale())
+                 .getString(Errors.Keys.UnsupportedOperation_1, "parse"), 
pos.getIndex());
+     }
+ 
+     /**
+      * Creates a new format to use for formatting values of the given type.
+      * This method adds the creation of {@link TreeTableFormat}.
+      *
+      * @param  valueType  the base type of values to parse or format.
+      * @return the format to use for parsing of formatting values of the 
given type, or {@code null} if none.
+      * @hidden the addition compared to parent class are implementation 
details.
+      */
+     @Override
+     protected Format createFormat(final Class<?> valueType) {
+         if (valueType == GeographicBoundingBox.class) {
+             return new TreeTableFormat(getLocale(), getTimeZone());
+         }
+         return super.createFormat(valueType);
+     }
+ 
+     /**
+      * Records that an error occurred.
+      *
+      * @param  e  the error that occurred.
+      */
+     private void addError(final Throwable e) {
+         if (error == null) {
+             error = e;
+         } else {
+             error.addSuppressed(e);
+         }
+     }
+ 
+     /**
+      * If an error occurred while formatting the Tile Matrix Set, returns 
that error.
+      *
+      * @return the error that occurred during formatting.
+      */
+     public Optional<Throwable> getError() {
+         return Optional.ofNullable(error);
+     }
+ 
+     /**
+      * Clears the error status. This method should be invoked if the same 
{@code TileMatrixSetFormat}
+      * instance is used for formatting many {@code TileMatrixSet} instances.
+      */
+     public void clear() {
+         error = null;
+     }
+ }
diff --cc 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverage.java
index 5b9a4d65e8,e820ce116b..9569abb254
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverage.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverage.java
@@@ -55,11 -53,16 +56,13 @@@ import org.opengis.geometry.MismatchedD
  // Specific to the geoapi-3.1 and geoapi-4.0 branches:
  import org.opengis.coverage.CannotEvaluateException;
  
 -// Specific to the geoapi-4.0 branch:
 -import org.opengis.coordinate.MismatchedDimensionException;
 -
  
  /**
-  * Base class of grid coverage read from a resource where data are stored in 
tiles.
+  * Base class of grid coverages that are read from resources with data stored 
in tiles.
   * This grid coverage may represent only a subset of the coverage resource.
-  * Tiles are read from the storage only when first needed.
+  * Tiles are read from the storage when first needed, then cached using weak 
references.
+  * The reading of tiles is done by the {@link #readTiles(TileIterator)} 
method,
+  * which must be defined by subclasses.
   *
   * <h2>Cell coordinates</h2>
   * When there is no subsampling, this coverage uses the same cell coordinates 
as the originating resource.
diff --cc 
endorsed/src/org.apache.sis.util/main/org/apache/sis/util/ArgumentChecks.java
index cafa992617,ca28d60e38..c393e45edb
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/ArgumentChecks.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/ArgumentChecks.java
@@@ -773,7 -773,31 +773,31 @@@ public final class ArgumentChecks 
          if (indices != null) {
              final int dimension = indices.length;
              if (dimension != expected) {
 -                throw new MismatchedDimensionException(Errors.format(
 +                throw new 
org.opengis.geometry.MismatchedDimensionException(Errors.format(
+                         Errors.Keys.MismatchedDimension_3, name, expected, 
dimension));
+             }
+         }
+     }
+ 
+     /**
+      * Ensures that the given array of indices, if non-null, has the expected 
number of dimensions
+      * (taken as its length). This method does nothing if the given array is 
null.
+      *
+      * @param  name      the name of the argument to be checked. Used only if 
an exception is thrown.
+      * @param  expected  the expected number of dimensions.
+      * @param  indices   the array of indices to check for its number of 
dimensions, or {@code null}.
+      * @throws MismatchedDimensionException if the given array of indices is 
non-null and does not have
+      *         the expected number of dimensions (taken as its length).
+      *
+      * @since 1.7
+      */
+     public static void ensureDimensionMatches(final String name, final int 
expected, final long[] indices)
+             throws MismatchedDimensionException
+     {
+         if (indices != null) {
+             final int dimension = indices.length;
+             if (dimension != expected) {
+                 throw new MismatchedDimensionException(Errors.format(
                          Errors.Keys.MismatchedDimension_3, name, expected, 
dimension));
              }
          }
diff --cc 
incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Sphere.java
index bceafeae88,4160a45cc5..9b8faafe56
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Sphere.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Sphere.java
@@@ -24,6 -25,10 +25,10 @@@ import org.apache.sis.geometries.math.V
  import org.apache.sis.geometries.math.Vectors;
  import org.apache.sis.geometry.GeneralEnvelope;
  import org.apache.sis.util.ArgumentChecks;
+ import static org.opengis.annotation.Specification.ISO_19107;
+ import org.opengis.annotation.UML;
+ import org.opengis.geometry.DirectPosition;
 -import org.opengis.metadata.Identifier;
++import org.opengis.referencing.ReferenceIdentifier;
  
  
  /**
@@@ -120,4 -127,61 +127,61 @@@ public final class Sphere extends Abstr
          return env;
      }
  
+     // methods from ParametricCurveSurface
+ 
+     @Override
+     public int getRows() {
+         throw new UnsupportedOperationException("Not supported yet.");
+     }
+ 
+     @Override
+     public int getColumns() {
+         throw new UnsupportedOperationException("Not supported yet.");
+     }
+ 
+     @Override
+     public List<DirectPosition> getControlPoints() {
+         throw new UnsupportedOperationException("Not supported yet.");
+     }
+ 
+     @Override
+     public List<DirectPosition> getDataPoints() {
+         throw new UnsupportedOperationException("Not supported yet.");
+     }
+ 
+     @Override
+     public GeometryType getHorizontalCurveType() {
+         throw new UnsupportedOperationException("Not supported yet.");
+     }
+ 
+     @Override
+     public GeometryType getVerticalCurveType() {
+         throw new UnsupportedOperationException("Not supported yet.");
+     }
+ 
+     @Override
+     public List<Knot> getKnots() {
+         throw new UnsupportedOperationException("Not supported yet.");
+     }
+ 
+     @Override
+     public Curve getHorizontalCurve(double v) {
+         throw new UnsupportedOperationException("Not supported yet.");
+     }
+ 
+     @Override
+     public Curve getVerticalCurve(double u) {
+         throw new UnsupportedOperationException("Not supported yet.");
+     }
+ 
+     @Override
+     public DirectPosition getSurface(double u, double v) {
+         throw new UnsupportedOperationException("Not supported yet.");
+     }
+ 
+     @Override
 -    public Identifier getName() {
++    public ReferenceIdentifier getName() {
+         throw new UnsupportedOperationException("Not supported yet.");
+     }
+ 
  }

Reply via email to