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 a3003a5d58 Pyramid levels should be ordered from coarsest to finest
resolution. https://issues.apache.org/jira/browse/SIS-628
a3003a5d58 is described below
commit a3003a5d58690bfc73790f1d1aedbfb02e77bd72
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Mar 25 17:51:14 2026 +0100
Pyramid levels should be ordered from coarsest to finest resolution.
https://issues.apache.org/jira/browse/SIS-628
---
.../coverage/MultiResolutionCoverageLoader.java | 32 ++++++------
.../org/apache/sis/map/coverage/RenderingData.java | 7 ++-
.../MultiResolutionCoverageLoaderTest.java | 16 +++---
.../sis/storage/geotiff/ImageFileDirectory.java | 36 +++++++++-----
.../org/apache/sis/storage/CoverageSubset.java | 2 +-
.../apache/sis/storage/GridCoverageResource.java | 13 +++--
.../sis/storage/base/GridResourceWrapper.java | 2 +-
.../apache/sis/storage/tiling/ImagePyramid.java | 7 +--
.../apache/sis/storage/tiling/TileReadEvent.java | 6 +--
.../storage/tiling/TiledGridCoverageResource.java | 57 ++++++++++++++++------
.../apache/sis/gui/coverage/CoverageCanvas.java | 21 +-------
11 files changed, 114 insertions(+), 85 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/MultiResolutionCoverageLoader.java
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/MultiResolutionCoverageLoader.java
index 6fc7eafc60..3cb9209229 100644
---
a/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/MultiResolutionCoverageLoader.java
+++
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/MultiResolutionCoverageLoader.java
@@ -85,7 +85,7 @@ public class MultiResolutionCoverageLoader {
public final GridCoverageResource resource;
/**
- * Squares of resolution at each pyramid level, from finest (smaller
numbers) to coarsest (largest numbers).
+ * Squares of resolution at each pyramid level, from coarsest (largest
numbers) to finest (smaller numbers).
* This is same same order as {@link
GridCoverageResource#getResolutions()}. For a given level, the array
* {@code resolutionSquared[level]} gives the squares of the resolution
for each CRS dimension.
*/
@@ -156,7 +156,7 @@ public class MultiResolutionCoverageLoader {
*
* @param envelope bounding box of the coverage in units of the coverage
CRS.
* @param base resolution of the finest level.
- * @return default resolutions from finest to coarsest. The first element
is always {@code base}.
+ * @return default resolutions from coarsest to finest. The last element
is always {@code base}.
*/
private static double[][] defaultResolutions(final GridGeometry gg,
double[] base) {
/*
@@ -179,12 +179,13 @@ public class MultiResolutionCoverageLoader {
numLevels = DEFAULT_NUM_LEVELS; // Arbitrary number of levels
if we cannot compute it.
}
/*
- * Build the arrays of resolutions from finest to coarsest.
+ * Build the arrays of resolutions from coarsest to finest.
* The `base` array is cloned then updated to become the base of next
level.
*/
final var resolutions = new double[numLevels][];
- resolutions[0] = base;
- for (int j=1; j<numLevels; j++) {
+ int j = numLevels - 1;
+ resolutions[j] = base;
+ while (--j >= 0) {
resolutions[j] = base = base.clone();
for (int i=0; i<base.length; i++) {
base[i] *= (1 << DEFAULT_SCALE_LOG);
@@ -194,9 +195,9 @@ public class MultiResolutionCoverageLoader {
}
/**
- * Returns the maximal level (the level with coarsest resolution).
+ * Returns the maximal level (the level with finest resolution).
*/
- final int getLastLevel() {
+ private int getLastLevel() {
return Math.max(resolutionSquared.length - 1, 0);
}
@@ -208,14 +209,14 @@ public class MultiResolutionCoverageLoader {
* @param objectiveToDisplay transform used for rendering the coverage
on screen.
* @param objectivePOI point where to compute resolution, in
coordinates of objective CRS.
* Can be null if {@code dataToObjective} is
null or linear.
- * @return pyramid level for the zoom determined by the given transform.
Finest level is 0.
+ * @return pyramid level for the zoom determined by the given transform.
coarsest level is 0.
* @throws TransformException if an error occurred while computing
resolution from given transforms.
*/
final int findPyramidLevel(final MathTransform dataToObjective, final
LinearTransform objectiveToDisplay,
final DirectPosition objectivePOI) throws
TransformException
{
- int level = getLastLevel();
- if (level != 0) {
+ int level = 0;
+ if (resolutionSquared.length > 1) {
final LinearTransform displayToObjective =
objectiveToDisplay.inverse();
final Matrix m = displayToObjective.getMatrix();
final Matrix d;
@@ -250,7 +251,7 @@ dimensions: for (int j=0; j<tgtDim; j++) {
}
/*
* Cannot use `Arrays.binarySearch(…)` because elements are
not guaranteed to be sorted.
- * Even if `GridCoverageResource.getResolutions()` contract
said "finest to coarsest",
+ * Even if `GridCoverageResource.getResolutions()` contract
said "coarsest to finest",
* it may not be possible to respect this condition on all
dimensions in same time.
* The main goal is to have a `level` value as high as
possible while having a resolution
* equals or better than `sum`.
@@ -262,11 +263,10 @@ dimensions: for (int j=0; j<tgtDim; j++) {
minimum = r;
levelOfMin = level;
}
- if (level == 0) {
+ if (++level == resolutionSquared.length) {
level = levelOfMin;
break dimensions;
}
- level--;
}
}
}
@@ -315,7 +315,7 @@ dimensions: for (int j=0; j<tgtDim; j++) {
}
/**
- * If the a grid coverage for the given domain and range is in the cache,
returns that coverage.
+ * If a grid coverage for the given domain and range is in the cache,
returns that coverage.
* Otherwise loads the coverage and eventually caches it. The caching
happens only if the given
* domain and range are managed by this loader.
*
@@ -330,7 +330,7 @@ dimensions: for (int j=0; j<tgtDim; j++) {
* Fot now we leverage the cache only at level 0.
* Future versions of this class may try to use the cache at other
levels too.
*/
- return getOrLoad(0);
+ return getOrLoad(getLastLevel());
}
if (domain == null) {
domain = resource.getGridGeometry();
@@ -350,7 +350,7 @@ dimensions: for (int j=0; j<tgtDim; j++) {
final int count = getLastLevel();
double delta = magnitude(0);
if (count != 0) {
- delta = (magnitude(count) - delta) / count;
+ delta = (delta - magnitude(count)) / count;
}
final int n =
Math.max(Math.min(DecimalFunctions.fractionDigitsForDelta(delta, false), 6), 0);
final NumberFormat f = NumberFormat.getInstance();
diff --git
a/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/RenderingData.java
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/RenderingData.java
index 3792d369ea..3e93c01d82 100644
---
a/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/RenderingData.java
+++
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/RenderingData.java
@@ -148,7 +148,7 @@ public class RenderingData implements CloneAccess {
/**
* The pyramid level of {@linkplain #data} loaded by the {@linkplain
#coverageLoader}.
- * Value 0 is finest resolution.
+ * Value 0 is coarsest resolution (the overview).
*/
private int currentPyramidLevel;
@@ -546,13 +546,12 @@ public class RenderingData implements CloneAccess {
RenderedImage image = data;
final MultiResolutionCoverageLoader loader = coverageLoader;
if (loader != null) {
- final int level = loader.getLastLevel();
- if (level != currentPyramidLevel) {
+ if (currentPyramidLevel != 0) {
/*
* If coarser data are available, we will compute
statistics on those data instead of on the
* current pyramid level. We need to adjust the slice
extent to the coordinates of coarser data.
*/
- final GridCoverage coarse =
loader.getOrLoad(level).forConvertedValues(true);
+ final GridCoverage coarse =
loader.getOrLoad(0).forConvertedValues(true);
GridExtent sliceExtent = currentSlice;
if (sliceExtent != null) {
if (sliceExtent.getDimension() <= BIDIMENSIONAL) {
diff --git
a/endorsed/src/org.apache.sis.portrayal/test/org/apache/sis/map/coverage/MultiResolutionCoverageLoaderTest.java
b/endorsed/src/org.apache.sis.portrayal/test/org/apache/sis/map/coverage/MultiResolutionCoverageLoaderTest.java
index 2cfa93f0a4..0ec37ee89b 100644
---
a/endorsed/src/org.apache.sis.portrayal/test/org/apache/sis/map/coverage/MultiResolutionCoverageLoaderTest.java
+++
b/endorsed/src/org.apache.sis.portrayal/test/org/apache/sis/map/coverage/MultiResolutionCoverageLoaderTest.java
@@ -96,7 +96,7 @@ public final class MultiResolutionCoverageLoaderTest extends
TestCase {
/**
* A dummy resource with arbitrary resolutions for testing purpose.
- * Resolutions are ordered from finest (smallest numbers) to coarsest
(largest numbers).
+ * Resolutions are ordered from coarsest (largest numbers) to finest
(smallest numbers).
*/
private static final class DummyResource extends
AbstractGridCoverageResource {
/** Creates a dummy resource. */
@@ -106,9 +106,9 @@ public final class MultiResolutionCoverageLoaderTest
extends TestCase {
/** Returns the preferred resolutions in units of CRS axes. */
@Override public List<double[]> getResolutions() {
- return List.of(new double[] {2, 3, 1},
+ return List.of(new double[] {8, 9, 5},
new double[] {4, 4, 3},
- new double[] {8, 9, 5});
+ new double[] {2, 3, 1});
}
/** Returns a grid geometry with the resolution of finest level. */
@@ -141,10 +141,10 @@ public final class MultiResolutionCoverageLoaderTest
extends TestCase {
*/
@Test
public void testFindPyramidLevel() throws TransformException {
- assertLevelEquals(3, 2, 2, 0);
- assertLevelEquals(4, 5, 2, 0);
+ assertLevelEquals(3, 2, 2, 2);
+ assertLevelEquals(4, 5, 2, 2);
assertLevelEquals(4, 5, 4, 1);
- assertLevelEquals(9, 9, 5, 2);
+ assertLevelEquals(9, 9, 5, 0);
assertLevelEquals(9, 8, 5, 1);
}
@@ -168,8 +168,8 @@ public final class MultiResolutionCoverageLoaderTest
extends TestCase {
*/
@Test
public void testGetOrLoad() throws DataStoreException {
- assertLoadEquals(2, 8, 9, 5);
- assertLoadEquals(0, 2, 3, 1);
+ assertLoadEquals(0, 8, 9, 5);
+ assertLoadEquals(2, 2, 3, 1);
assertLoadEquals(1, 4, 4, 3);
}
}
diff --git
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
index ddfde1137e..476836cb3b 100644
---
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
+++
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
@@ -2024,7 +2024,7 @@ final class ImageFileDirectory extends DataCube {
}
/**
- * Sets a list of overviews from finest resolution to coarsest resolution.
+ * Sets a list of overviews from coarsest resolution (the overview) to
finest resolution.
* The full-resolution image shall be {@code this} and shall not be
included in the given list.
*/
final void setOverviews(final List<ImageFileDirectory> images) {
@@ -2034,7 +2034,7 @@ final class ImageFileDirectory extends DataCube {
}
/**
- * A list of Image File Directories (FID) where the first entry is the
image at finest resolution
+ * A list of Image File Directories (FID) where the first entry is the
image at coarsest resolution
* and following entries are images at finer resolutions. The entry at
finest resolution is the
* enclosing {@link ImageFileDirectory}.
*/
@@ -2052,7 +2052,7 @@ final class ImageFileDirectory extends DataCube {
private final ImageFileDirectory[] levels;
/**
- * Creates a list of overviews from finest resolution to coarsest
resolution.
+ * Creates a list of overviews from coarsest resolution to finest
resolution.
* The full-resolution image shall be the enclosing {@link
ImageFileDirectory}
* and is not included in the given list.
*/
@@ -2068,24 +2068,38 @@ final class ImageFileDirectory extends DataCube {
return OptionalInt.of(levels.length + 1);
}
+ /**
+ * Returns a resource which is representative of all pyramid levels
except for the resolution.
+ * This method is invoked for fetching metadata such as the Coordinate
Reference System
+ * when the resolution does not matter. For a <abbr>TIFF</abbr> file,
this is the image
+ * with the finest resolution.
+ *
+ * @return a resource representative of all levels (ignoring
resolution).
+ */
+ @Override
+ public TiledGridCoverageResource representative() {
+ return ImageFileDirectory.this;
+ }
+
/**
* Completes and returns the image at the given pyramid level.
- * Indices are in the same order as the images appear in the
<abbr>TIFF</abbr> file,
- * with 0 for the full resolution image.
+ * Indices are in the reverse order of the images in the
<abbr>TIFF</abbr> file,
+ * with 0 for the image at the coarsest resolution (the overview).
*
- * @param level image index (level) in the pyramid, with 0 for
finest resolution.
+ * @param level image index (level) in the pyramid, with 0 for
coarsest resolution (the overview).
* @return image at the given pyramid level, or {@code null} if the
given level is out of bounds.
*/
@Override
public TiledGridCoverageResource forPyramidLevel(final int level)
throws DataStoreException {
- if (level == 0) {
- return ImageFileDirectory.this;
- }
- if (level > levels.length) {
+ final int n;
+ if (level < 0 || (n = levels.length - 1 - level) < -1) {
return null;
}
+ if (n == -1) {
+ return ImageFileDirectory.this;
+ }
synchronized (getSynchronizationLock()) {
- final ImageFileDirectory image = levels[level - 1];
+ final ImageFileDirectory image = levels[n];
final Reader reader = image.reader;
try {
// Effective the first time that this method is invoked,
no-op on other invocations.
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/CoverageSubset.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/CoverageSubset.java
index e764690ba0..2544cc414e 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/CoverageSubset.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/CoverageSubset.java
@@ -144,7 +144,7 @@ final class CoverageSubset extends
AbstractGridCoverageResource {
public List<double[]> getResolutions() throws DataStoreException {
List<double[]> resolutions = source.getResolutions();
if (reduction != null) try {
- JDK16.toList(resolutions.stream()
+ resolutions = JDK16.toList(resolutions.stream()
.map((resolution) -> reduction.apply(new
DirectPositionView.Double(resolution)).getCoordinates()));
} catch (BackingStoreException e) {
throw e.unwrapOrRethrow(DataStoreException.class);
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/GridCoverageResource.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/GridCoverageResource.java
index eec1a421cb..88e2ef6be4 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/GridCoverageResource.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/GridCoverageResource.java
@@ -42,7 +42,7 @@ import org.apache.sis.util.ArraysExt;
*
* @author Martin Desruisseaux (Geomatys)
* @author Johann Sorel (Geomatys)
- * @version 1.5
+ * @version 1.7
* @since 1.0
*/
public interface GridCoverageResource extends DataSet {
@@ -131,9 +131,13 @@ public interface GridCoverageResource extends DataSet {
/**
* Returns the preferred resolutions (in units of CRS axes) for read
operations in this data store.
* If the storage supports pyramid, then the list should contain the
resolution at each pyramid level
- * ordered from finest (smallest numerical values) to coarsest (largest
numerical values) resolution.
- * Otherwise, the list contains a single element which is the {@linkplain
#getGridGeometry() grid geometry}
- * resolution, or an empty list if no resolution is applicable to the
coverage (e.g. because non-constant).
+ * ordered from coarsest (largest numerical values) resolution to finest
(smallest numerical values).
+ * This ordering should be the same as in {@link
org.apache.sis.storage.tiling.TileMatrixSet},
+ * which is itself based on the order specified by <abbr>OGC</abbr> tile
matrix specifications.
+ *
+ * <p>If the storage does not support pyramid, then the returned list
contains a single element which
+ * is the {@linkplain #getGridGeometry() grid geometry} resolution, or an
empty list if no resolution
+ * is applicable to the coverage (e.g. because non-constant).</p>
*
* <p>Each element shall be an array with a length equals to the number of
<abbr>CRS</abbr> dimensions.
* In each array, value at index <var>i</var> is the cell size along
<abbr>CRS</abbr> dimension <var>i</var>
@@ -147,6 +151,7 @@ public interface GridCoverageResource extends DataSet {
* @throws DataStoreException if an error occurred while reading
definitions from the underlying data store.
*
* @see GridGeometry#getResolution(boolean)
+ * @see org.apache.sis.storage.tiling.TileMatrixSet#getTileMatrices()
*
* @since 1.2
*/
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/GridResourceWrapper.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/GridResourceWrapper.java
index 8780fb42e5..0f3f6c8023 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/GridResourceWrapper.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/GridResourceWrapper.java
@@ -157,7 +157,7 @@ public abstract class GridResourceWrapper implements
GridCoverageResource {
/**
* Returns the preferred resolutions (in units of CRS axes) for read
operations in this data store.
- * Elements are ordered from finest (smallest numbers) to coarsest
(largest numbers) resolution.
+ * Elements are ordered from coarsest (largest numbers) resolution to
finest (smallest numbers).
*
* @return preferred resolutions for read operations in this data store,
or an empty array if none.
* @throws DataStoreException if an error occurred while reading
definitions from the underlying data store.
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImagePyramid.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImagePyramid.java
index da376fb1f8..740323171c 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImagePyramid.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImagePyramid.java
@@ -210,8 +210,9 @@ final class ImagePyramid extends AbstractMap<GenericName,
ImageTileMatrix>
/**
* Compares two generic names for order based on the resolution of the
associated tile matrix.
- * If a call to {@code compare(o1, o2)}, the comparator returns a positive
number of {@code o1}
- * is the identifier of a tile matrix having a finer resolution than
{@code o2}.
+ * If a call to {@code compare(o1, o2)}, the comparator returns a positive
number if {@code o1}
+ * is the identifier of a tile matrix having a finer resolution than
{@code o2}
+ * (i.e., is ordered after the coarser tile matrix).
*/
@Override
public Comparator<GenericName> comparator() {
@@ -375,7 +376,7 @@ final class ImagePyramid extends AbstractMap<GenericName,
ImageTileMatrix>
final ImageTileMatrix tm;
synchronized (matrices) {
final int size = size(); // Implementation of `size()` fills
the list.
- tm = (size != 0) ? matrices.get(size - 1) : null;
+ tm = (size != 0) ? matrices.get(lowerMatrixIndex + (size - 1)) :
null;
}
if (tm != null) {
return tm.getIdentifier();
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileReadEvent.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileReadEvent.java
index 4ff4cd8958..c15f30b9b9 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileReadEvent.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileReadEvent.java
@@ -64,7 +64,7 @@ public class TileReadEvent extends StoreEvent {
/**
* Zero-based index of the pyramid level of the tile which is read.
- * The level with finest resolution is the level 0.
+ * The level with coarsest resolution (the overview) is the level 0.
*
* @see #getPyramidLevel()
* @see #getResolution()
@@ -101,7 +101,7 @@ public class TileReadEvent extends StoreEvent {
/**
* Creates a new context.
*
- * @param pyramidLevel index of the pyramid level of the tile which
is read, where 0 is the level with finest resolution.
+ * @param pyramidLevel index of the pyramid level of the tile which
is read, where 0 is the level with coarsest resolution.
* @param domain the grid geometry of the coverage of which a
slice is rendered as an image.
* @param aoi the coordinates requested by the user.
* @param xDimension dimension of the grid which is mapped to the
<var>x</var> axis in rendered images.
@@ -170,7 +170,7 @@ public class TileReadEvent extends StoreEvent {
* Returns the zero-based index of the pyramid level of the tile which is
read.
* This is typically the index in the {@linkplain
TiledGridCoverageResource#getResolutions() list
* of resource's resolution} where the values returned by {@link
#getResolution()} can be found.
- * The level with finest resolution is the level 0.
+ * The level with coarsest resolution (the overview) is the level 0.
*
* @return zero-based index of the pyramid level of the tile which is read.
*
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
index d8e6142da1..feb89429e5 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
@@ -422,7 +422,7 @@ check: if (dataType.isInteger()) {
/**
* Returns the preferred resolutions (in units of <abbr>CRS</abbr> axes)
for read operations in this data store.
- * The list elements are ordered from finest (smallest numerical values)
to coarsest (largest numerical values).
+ * The list elements are ordered from coarsest (largest numerical values)
to finest (smallest numerical values).
*
* <p>The default implementation uses information in the first element
returned by {@link #getPyramids()}.
* It is generally easier for subclasses to override {@link
#getPyramids()} instead of this method.</p>
@@ -889,22 +889,33 @@ check: if (dataType.isInteger()) {
* the requested resolution.
*/
final Pyramid pyramid = choosePyramid(domain, ranges);
- if (pyramid == null || (bestFit = pyramid.forPyramidLevel(0)) ==
null) {
+ if (pyramid == null || (bestFit = pyramid.representative()) ==
null) {
return readAtThisPyramidLevel(domain, ranges, null);
}
int level = 0;
final double[] request = bestFit.convertResolutionOf(domain);
- if (request != null) {
+ bestFit = null;
+ if (request == null) {
+ final OptionalInt numberOfLevels = pyramid.numberOfLevels();
+ if (numberOfLevels.isPresent()) {
+ level = numberOfLevels.getAsInt() - 1;
+ bestFit = pyramid.forPyramidLevel(level);
+ }
+ }
+ if (bestFit == null) {
+ level = -1;
TiledGridCoverageResource c;
- while ((c = pyramid.forPyramidLevel(level)) != null) {
- final double[] resolution =
c.getGridGeometry().getResolution(true);
- if (!(request[xDimension] >= resolution[xDimension] && //
Use `!` for catching NaN.
- request[yDimension] >= resolution[yDimension]))
break;
+ while ((c = pyramid.forPyramidLevel(level + 1)) != null) {
bestFit = c;
level++;
+ if (request != null) {
+ final double[] resolution =
c.getGridGeometry().getResolution(true);
+ if (!(request[xDimension] < resolution[xDimension] ||
// Use `!` for catching NaN.
+ request[yDimension] < resolution[yDimension]))
break;
+ }
}
}
- if (bestFit == this) {
+ if (bestFit == null || bestFit == this) {
return readAtThisPyramidLevel(domain, ranges, null);
}
bestFit.pyramidLevel = level;
@@ -1141,7 +1152,7 @@ check: if (dataType.isInteger()) {
*
* <p>Each pyramid can have an arbitrary number of levels.
* It is recommended to have one pyramid level for each {@linkplain
#getResolutions() preferred resolutions}.
- * The pyramid levels must be sorted from finest resolution (at level 0)
to coarsest resolution.</p>
+ * The pyramid levels must be sorted from coarsest resolution (at level 0)
to finest resolution.</p>
*
* <p>The number of levels is unspecified because some data stores cannot
provide this information in advance.
* Instead, the {@link #forPyramidLevel(int)} method will be invoked with
different argument values when each
@@ -1171,7 +1182,7 @@ check: if (dataType.isInteger()) {
* Returns an identifier for the given level of this pyramid. The
returned identifier
* will be local in the namespace of the pyramid {@linkplain
#identifier() identifier}.
*
- * @param level the pyramid level where 0 is the level with the
finest resolution.
+ * @param level the pyramid level where 0 is the level with the
coarsest resolution.
* @return a local identifier for the specified level.
*/
default String identifierOfLevel(int level) {
@@ -1207,18 +1218,34 @@ check: if (dataType.isInteger()) {
return OptionalInt.empty();
}
+ /**
+ * Returns a resource which is representative of all pyramid levels
except for the resolution.
+ * The default implementation returns the resource at level 0,
<i>i.e.</i> the overview.
+ * Some formats such as <abbr>TIFF</abbr> rather use the image at the
finest resolution
+ * as the base image from which other images are derived.
+ *
+ * <p>This method is invoked for fetching metadata such as the
Coordinate Reference System.
+ * It is usually not invoked for reading pixel values, as the
resolution can be anything.</p>
+ *
+ * @return a resource representative of all levels (ignoring
resolution), or {@code null} if none.
+ * @throws DataStoreException if an error occurred while creating the
resource.
+ */
+ default TiledGridCoverageResource representative() throws
DataStoreException {
+ return forPyramidLevel(0);
+ }
+
/**
* Returns a resource for the same data as this resource but at a
different resolution level.
- * The resource at index 0 shall be the resource with the finest
resolution, and resources at
- * increasing index values shall be resources with increasingly
coarser resolutions.
+ * The resource at index 0 shall be the resource with the coarsest
resolution (the overview),
+ * and resources at increasing index values shall be resources with
increasingly finer resolutions.
* If the specified level is equal or greater than the number of
levels in this pyramid,
* then this method shall return {@code null}.
*
* <p>If this method returns a non-null instance <var>r</var>, then
the following condition should hold:
- * {@code r.getGridGeometry().getResolution(false)} should be equal,
ignoring NaN values and rounding
- * errors, to {@code getResolutions().get(level)}.</p>
+ * {@code r.getGridGeometry().getResolution(false)} should be equal,
ignoring NaN values and rounding errors,
+ * to {@code getResolutions().get(level)}.</p>
*
- * @param level the pyramid level where 0 is the level with the
finest resolution.
+ * @param level the pyramid level where 0 is the level with the
coarsest resolution (the overview).
* @return a resource for data at the specified pyramid level, or
{@code null} if the given level is too high.
* @throws DataStoreException if an error occurred while creating the
resource.
*
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageCanvas.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageCanvas.java
index a6a90d2f23..635cb296d6 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageCanvas.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageCanvas.java
@@ -95,6 +95,7 @@ import org.apache.sis.util.Debug;
import org.apache.sis.util.Exceptions;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.util.collection.BackingStoreException;
+import org.apache.sis.util.collection.Containers;
import org.apache.sis.io.TableAppender;
import org.apache.sis.measure.Units;
import static org.apache.sis.gui.internal.LogHandler.LOGGER;
@@ -665,7 +666,7 @@ public class CoverageCanvas extends MapCanvasAWT {
} else try {
domain = resource.getGridGeometry();
ranges = resource.getSampleDimensions();
- scales = lastNonNull(resource.getResolutions());
+ scales =
Containers.peekFirst(resource.getResolutions());
} catch (BackingStoreException e) {
throw e.unwrapOrRethrow(DataStoreException.class);
}
@@ -747,24 +748,6 @@ public class CoverageCanvas extends MapCanvasAWT {
}
}
- /**
- * Returns the last non-null element of the given list.
- *
- * @param <T> the type of elements contained in the list.
- * @param list the list from which to get the last non-null element, or
{@code null}.
- * @return the last non-null element, or {@code null} if the given list is
null or empty.
- */
- private static <T> T lastNonNull(final List<T> list) {
- if (list != null) {
- int i = list.size();
- while (--i >= 0) {
- T e = list.get(i);
- if (e != null) return e;
- }
- }
- return null;
- }
-
/**
* Clears the rendered image but keep the resource, coverage, grid
geometry and sample dimensions unchanged.
* Invoking this method alone is useful when only the selected
two-dimensional slice changed.