This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits 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 ccfa3c1130 Fix the order of pyramid levels in HEIF file. Opportunistic
fix in the formatting of scale factors.
ccfa3c1130 is described below
commit ccfa3c11306edc60f8adcddc9b4cea8d3c6a69d3
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Jun 18 18:02:54 2026 +0200
Fix the order of pyramid levels in HEIF file.
Opportunistic fix in the formatting of scale factors.
---
.../org/apache/sis/coverage/grid/GridExtent.java | 38 ++++++++
.../org/apache/sis/coverage/grid/GridGeometry.java | 6 +-
.../main/org/apache/sis/io/wkt/Formatter.java | 2 +-
.../apache/sis/storage/tiling/TileMatrixSet.java | 2 +-
.../sis/storage/tiling/TileMatrixSetFormat.java | 43 +++++----
.../apache/sis/util/internal/shared/Numerics.java | 100 ++-------------------
.../sis/storage/geoheif/CoverageBuilder.java | 3 +-
.../org/apache/sis/storage/geoheif/ImageModel.java | 6 +-
.../apache/sis/storage/geoheif/ImageResource.java | 14 +--
.../org/apache/sis/storage/geoheif/Pyramid.java | 40 ++++++++-
.../isobmff/mpeg/CompressionConfiguration.java | 4 +
11 files changed, 126 insertions(+), 132 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java
index e8aff27060..45b5d7e4bf 100644
---
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java
+++
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java
@@ -22,6 +22,7 @@ import java.util.SortedMap;
import java.util.Arrays;
import java.util.Optional;
import java.util.Objects;
+import java.util.Comparator;
import java.util.Spliterator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@@ -919,6 +920,7 @@ public class GridExtent implements GridEnvelope,
LenientComparable, Serializable
* @see #getLow(int)
* @see #getHigh(int)
* @see #resize(long...)
+ * @see #SIZES_COMPARATOR
*/
@Override
public long getSize(final int index) {
@@ -936,6 +938,8 @@ public class GridExtent implements GridEnvelope,
LenientComparable, Serializable
* @param index the dimension for which to obtain the size.
* @param minusOne {@code true} for returning <var>size</var>−1 instead
of <var>size</var>.
* @return the number of cells along the given dimension, optionally minus
one.
+ *
+ * @see #SIZES_COMPARATOR
*/
public double getSize(final int index, final boolean minusOne) {
final int dimension = getDimension();
@@ -947,6 +951,40 @@ public class GridExtent implements GridEnvelope,
LenientComparable, Serializable
return Numerics.toUnsignedDouble(size);
}
+ /**
+ * A comparator of grid extent sizes where each dimension is compared in
increasing index order.
+ * For a given pair of {@code GridExtent} instances, the comparison begins
with the
+ * {@linkplain #getSize(int) size} of each extent in the first dimension
(index 0):
+ *
+ * <ul>
+ * <li>If the first extent has a smaller size, a negative number is
returned.</li>
+ * <li>If the second extent has a smaller size, a positive number is
returned.</li>
+ * <li>Otherwise, the comparison is repeated with the next dimensions
(1, 2, …,
+ * {@linkplain #getDimension() dimension} - 1) until a dimension is
found
+ * where the sizes are not equal.
+ * </ul>
+ *
+ * If all dimensions have the same {@linkplain #getSize(int) size},
+ * then the extent with the smallest number of dimensions is considered
before the other extent.
+ * Null values are considered after all non-null values.
+ *
+ * @since 1.7
+ */
+ public static final Comparator<GridExtent> SIZES_COMPARATOR = (e1, e2) -> {
+ if (e1 == e2) return 0;
+ if (e1 == null) return +1;
+ if (e2 == null) return -1;
+ final int d1 = e1.getDimension();
+ final int d2 = e2.getDimension();
+ final int dim = Math.min(d1, d2);
+ for (int i=0; i<dim; i++) {
+ int c = Long.compareUnsigned(e1.coordinates[d1 + i] -
e1.coordinates[i],
+ e2.coordinates[d2 + i] -
e2.coordinates[i]);
+ if (c != 0) return c;
+ }
+ return d1 - d2;
+ };
+
/**
* Returns the low and high coordinates packaged in a single array.
* The length of this array is twice the number of dimensions.
diff --git
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java
index 77e8cffc39..46f7035f68 100644
---
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java
+++
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java
@@ -2460,8 +2460,8 @@ public class GridGeometry implements LenientComparable,
Serializable {
final double lower = envelope.getLower(i);
final double upper = envelope.getUpper(i);
final double delta = (resolution != null) ? resolution[i]
: Double.NaN;
-
nf.setMinimumFractionDigits(Numerics.fractionDigitsForDelta(delta));
-
nf.setMaximumFractionDigits(Numerics.suggestFractionDigits(lower, upper) - 1);
// The -1 is for rounding errors.
+
nf.setMaximumFractionDigits(Numerics.fractionDigitsForRange(lower, upper) - 1);
// The -1 is for rounding errors.
+
nf.setMinimumFractionDigits(Numerics.fractionDigitsForDelta(delta));
// May adjust above max value.
final CoordinateSystemAxis axis = (cs != null) ?
cs.getAxis(i) : null;
final String name = (axis != null) ?
axis.getName().getCode() : vocabulary.getString(Vocabulary.Keys.Dimension_1, i);
table.append(name).append(": ").nextColumn();
@@ -2633,7 +2633,7 @@ public class GridGeometry implements LenientComparable,
Serializable {
} else {
final NumberFormat nf = numberFormat();
final int n = Double.isNaN(delta)
- ? Numerics.suggestFractionDigits(value) / 2
+ ? Numerics.fractionDigitsForDelta(value) / 2
: Numerics.fractionDigitsForDelta(delta);
nf.setMaximumFractionDigits(n + 1);
out.append(nf.format(value));
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Formatter.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Formatter.java
index 45aa889fc3..9b45a63daa 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Formatter.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Formatter.java
@@ -1018,7 +1018,7 @@ public class Formatter implements Localized {
final double max = range.getMaxDouble();
int minimumFractionDigits = Numerics.fractionDigitsForDelta(max -
min);
int maximumFractionDigits = Math.min(Math.min(
- Numerics.suggestFractionDigits(min, max),
+ Numerics.fractionDigitsForRange(min, max),
minimumFractionDigits + 2), VERTICAL_ACCURACY);
// Arbitrarily limit to 2 more digits.
openElement(true, WKTKeywords.VerticalExtent);
setColor(ElementKind.EXTENT);
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileMatrixSet.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileMatrixSet.java
index 11e37f43af..a25843f0e0 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileMatrixSet.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileMatrixSet.java
@@ -129,7 +129,7 @@ public interface TileMatrixSet {
/**
* Returns all {@code TileMatrix} instances in this set, together with
their identifiers.
* For each value in the map, the associated key is {@link
TileMatrix#getIdentifier()}.
- * Entries are sorted from coarser resolution (highest scale denominator)
to most detailed
+ * Entries are sorted from coarsest resolution (highest scale denominator)
to most detailed
* resolution (lowest scale denominator).
* This is not necessarily the natural ordering of the {@link GenericName}
instances used as keys.
*
diff --git
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
index 321700a504..b528691764 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
@@ -43,7 +43,6 @@ 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;
@@ -52,6 +51,7 @@ 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.math.DecimalFunctions;
import org.apache.sis.io.CompoundFormat;
import org.apache.sis.io.TableAppender;
@@ -113,6 +113,8 @@ public class TileMatrixSetFormat extends
CompoundFormat<TileMatrixSet> {
/**
* Creates one row in the table for the given matrix.
+ * This constructor prepares string representations of all values
except resolutions.
+ * Resolutions must be formatted by a call to {@link
#formatResolutions(List, NumberFormat)}.
*
* @param matrix the matrix for which to store information.
* @param integerFormat a number format configured for integer
values.
@@ -176,27 +178,34 @@ public class TileMatrixSetFormat extends
CompoundFormat<TileMatrixSet> {
* 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;
+ final int numRow = rows.size();
+ for (int column = 0; ; column++) {
+ boolean found = false;
+ double maximum = 0;
+ int n = 0;
for (final Row row : rows) {
- if (i < row.resolution.length) {
- values[count++] = row.resolution[i];
+ if (column < row.resolution.length) {
+ found = true;
+ double value = Math.abs(row.resolution[column]);
+ if (value > maximum) maximum = value;
+ value -= Math.floor(value);
+ if (value > 0) {
+ n = Math.max(n,
DecimalFunctions.fractionDigitsForDelta(value, true));
+ }
}
}
- if (count == 0) return i;
- final int n =
Numerics.suggestFractionDigits(ArraysExt.resize(values, count));
+ if (!found) return column;
+ if (n != 0) n++; // TODO: should do a better work for
finding the number of fraction digits.
+ n = Math.min(n,
DecimalFunctions.fractionDigitsForValue(maximum));
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];
+ for (int i=0; i<numRow; i++) {
+ final Row row = rows.get(i);
+ final String[] target = row.formattedResolution;
+ if (column < target.length) {
+ final double[] resolution = row.resolution;
+ final double value = (column < resolution.length) ?
resolution[column] : Double.NaN;
+ target[column] = format.format(value);
}
}
}
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Numerics.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Numerics.java
index 6440d7ac52..a9de7d6262 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Numerics.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Numerics.java
@@ -16,14 +16,10 @@
*/
package org.apache.sis.util.internal.shared;
-import java.util.Arrays;
import java.text.Format;
-import java.text.NumberFormat;
import java.text.DecimalFormat;
-import java.text.FieldPosition;
import java.math.BigInteger;
import java.util.function.BiFunction;
-import java.util.function.IntToDoubleFunction;
import static java.lang.Math.min;
import static java.lang.Math.max;
import static java.lang.Math.abs;
@@ -597,46 +593,20 @@ public final class Numerics {
}
/**
- * Suggests a number of fraction digits for the given values, ignoring NaN
and infinities.
+ * Suggests a number of fraction digits for the given range of values.
* This method uses heuristic rules that may change in any future
<abbr>SIS</abbr> version.
* Current implementation returns a value which avoid printing "garbage"
digits with highest numbers,
* at the cost of loosing significant digits on smallest numbers. It may
further reduce the number of
* digits if this is sufficient for distinguishing the given values.
- * An arbitrary limit is set to 16 digits, which is the number of digits
for {@code Math.ulp(1.0)}}.
*
- * <p>This method modifies the given array in-place. Callers should not
pass original data.</p>
- *
- * @param values the values for which to get suggested number of
fraction digits.
+ * @param minimum the minimum value of the range.
+ * @param maximum the maximum value of the range.
* @return suggested number of fraction digits for the given values.
Always positive.
*/
- public static int suggestFractionDigits(final double... values) {
- switch (values.length) {
- case 0: return 0;
- case 1: return DecimalFunctions.fractionDigitsForValue(values[0]);
- }
- for (int i=0; i<values.length; i++) {
- values[i] = abs(values[i]);
- }
- Arrays.sort(values);
- double ulp = 0;
- double delta = Double.POSITIVE_INFINITY;
- for (int i = values.length; --i >= 0;) {
- double value = values[i];
- if (Double.isFinite(value)) {
- ulp = ulp(value);
- while (--i >= 0) {
- final double lower = values[i];
- final double diff = value - lower;
- if (diff > 0 && diff < delta) {
- delta = diff;
- }
- value = lower;
- }
- break;
- }
- }
- // Arbitrarily add 6 digits the difference between values.
- return min(fractionDigitsForDelta(ulp), fractionDigitsForDelta(delta)
+ 6);
+ public static int fractionDigitsForRange(final double minimum, final
double maximum) {
+ final double ulp = max(ulp(minimum), ulp(maximum));
+ // Arbitrarily add 6 digits to the value computed from the difference
between values.
+ return min(fractionDigitsForDelta(ulp), fractionDigitsForDelta(maximum
- minimum) + 6);
}
/**
@@ -670,62 +640,6 @@ public final class Numerics {
return fractionDigitsForDelta(delta);
}
- /**
- * Gets the character used for zero.
- * If the given format is not a {@link DecimalFormat}, arbitrarily returns
the white space.
- *
- * @param format the format for which to get the zero digit.
- * @return the zero digit, or {@code ' '} if the format is not decimal.
- */
- private static char getZeroDigit(final Format format) {
- return (format instanceof DecimalFormat) ? ((DecimalFormat)
format).getDecimalFormatSymbols().getZeroDigit() : ' ';
- }
-
- /**
- * Formats values then removes the same number of trailing zeros in the
fraction digits of all values.
- * For this method to be useful, the given format should use a fixed
number of fraction digits.
- * NaN and infinite values are formatted as usual but ignored in the
removal of trailing zeros.
- *
- * @param format the format to use.
- * @param count number of values to format.
- * @param values provider of values to format.
- * @return an array of length {@code count} with the formatted values.
- */
- public static String[] formatAndTrimTrailingZeros(final NumberFormat
format, final int count, final IntToDoubleFunction values) {
- final var formatted = new String[count];
- final var buffer = new StringBuffer();
- final var fractionEnd = new int[count];
- final var fractionField = new
FieldPosition(NumberFormat.Field.FRACTION);
- final char zeroDigit = getZeroDigit(format);
- int numberOfTrailingZeros = Integer.MAX_VALUE;
- for (int i=0; i<count; i++) {
- final double value = values.applyAsDouble(i);
- String text = format.format(value, buffer,
fractionField).toString();
- formatted[i] = text;
- if (numberOfTrailingZeros != 0 && Double.isFinite(value)) {
- final int end = fractionField.getEndIndex();
- fractionEnd[i] = end;
- int firstNonZero = end;
- final int start = Math.max(fractionField.getBeginIndex(), end
- numberOfTrailingZeros);
- while (--firstNonZero > start) {
- if (text.charAt(firstNonZero) != zeroDigit) break;
- }
- numberOfTrailingZeros = Math.min(numberOfTrailingZeros, end -
(firstNonZero + 1));
- }
- buffer.setLength(0);
- }
- if (numberOfTrailingZeros != 0) {
- for (int i=0; i<count; i++) {
- final int end = fractionEnd[i];
- if (end != 0) {
- formatted[i] = buffer.append(formatted[i]).delete(end -
numberOfTrailingZeros, end).toString();
- buffer.setLength(0);
- }
- }
- }
- return formatted;
- }
-
/**
* Formats the given value with the given format, using scientific
notation if needed.
* This is a workaround for {@link DecimalFormat} not switching
automatically to scientific notation for large numbers.
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java
index 551fc2fec8..16690e47a9 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java
@@ -596,8 +596,9 @@ final class CoverageBuilder implements Emptiable {
* This method should be invoked at most once.
* It may be invoked not at all when this object is used for building a
tile instead of an image.
*
- * @todo Need to add information from the {@code ExtraDimensionProperty}
box.
+ * @todo Need to add information from the {@code ExtraDimensionProperty}
(edim) box.
* These information include name, minimum, maximum and resolution.
+ * See https://docs.ogc.org/per/24-038r1.html
*
* @return the grid geometry.
* @throws DataStoreException if the "grid to <abbr>CRS</abbr>" transform
cannot be created.
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageModel.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageModel.java
index 0da11c285f..a8d64494bd 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageModel.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageModel.java
@@ -85,8 +85,9 @@ final class ImageModel {
/**
* Computes date type, color model, sample model, and sample dimensions.
*
- * @todo Need to add information from the {@code CellPropertyTypeProperty}
box.
+ * @todo Need to add information from the {@code CellPropertyTypeProperty}
("pcel") box.
* These information include sample dimension name and unit of
measurement.
+ * See https://docs.ogc.org/per/24-038r1.html
*
* @param width the width (in pixels) of the reconstructed
image.
* @param height the height (in pixels) of the reconstructed
image.
@@ -156,7 +157,8 @@ final class ImageModel {
}
/*
* Create the sample dimension and derive metadata from it.
- * TODO: parse CellPropertyTypeProperty and
CellPropertyCategoriesProperty boxes.
+ * TODO: parse CellPropertyTypeProperty (pcel) and
CellPropertyCategoriesProperty (pcat) boxes.
+ * See https://docs.ogc.org/per/24-038r1.html
*/
if (colorType != null) {
sb.setName(colorType.toString());
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageResource.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageResource.java
index 1aa77f32c1..c1a0f9ee4b 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageResource.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageResource.java
@@ -182,18 +182,10 @@ final class ImageResource extends
TiledGridCoverageResource implements StoreReso
* Declares that this image is the pyramid level of the given base grid.
* This method does nothing if this image already has its own "grid to
<abbr>CRS</abbr>" transform.
*
- * <p>If {@code base} is null, then the base is assumed to be the grid
geometry of this level.
- * Configuring a level relative to itself is useful when the grid geometry
is incomplete,
- * in which case the resolution of the base level is set to 1.
- * This is needed because resolutions are mandatory in a grid.</p>
- *
- * @param base grid geometry of the pyramid level at the finest
resolution, or {@code null} if this level.
- * @return grid geometry of the pyramid level at the finest resolution
({@code base} if it was non-null).
+ * @param base grid geometry of the pyramid level at the finest
resolution.
* @throws TransformException if an error occurred while deriving the
"grid to <abbr>CRS</abbr>" transform.
*/
- final GridGeometry setPyramidLevelOf(GridGeometry base) throws
TransformException {
- final boolean self = (base == null);
- if (self) base = gridGeometry;
+ final void setPyramidLevelOf(final GridGeometry base) throws
TransformException {
if (!gridGeometry.isDefined(GridGeometry.GRID_TO_CRS)) {
final GridExtent levelExtent = gridGeometry.getExtent();
final GridExtent baseExtent = base.getExtent();
@@ -202,9 +194,7 @@ final class ImageResource extends TiledGridCoverageResource
implements StoreReso
factors[i] = 1 / Numerics.divide(levelExtent.getSize(i),
baseExtent.getSize(i));
}
gridGeometry = new GridGeometry(base, levelExtent,
MathTransforms.scale(factors));
- if (self) base = gridGeometry;
}
- return base;
}
/**
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/Pyramid.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/Pyramid.java
index 9cf9d01abd..234dcbb2e9 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/Pyramid.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/Pyramid.java
@@ -16,6 +16,8 @@
*/
package org.apache.sis.storage.geoheif;
+import java.util.Arrays;
+import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
@@ -23,6 +25,7 @@ import org.opengis.util.GenericName;
import org.opengis.util.NameFactory;
import org.opengis.referencing.operation.TransformException;
import org.apache.sis.coverage.SampleDimension;
+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.isobmff.image.ImagePyramid;
@@ -58,13 +61,22 @@ final class Pyramid extends TiledGridCoverageResource
implements TiledGridCovera
*/
private final ImageResource[] levels;
+ /**
+ * A comparator of pyramid level based on the size of their grid extent.
+ * We use the grid extent because this is sometime the only information
which is known.
+ * The "grid to <abbr>CRS</abbr>", and therefore the resolution, may not
have been computed yet.
+ */
+ private static final Comparator<ImageResource> LEVEL_COMPARATOR =
+ Comparator.comparing((image) ->
image.getGridGeometry().getExtent(),
+ GridExtent.SIZES_COMPARATOR.reversed());
+
/**
* Creates a new pyramid.
*
* @param store the parent of this pyramid.
* @param name the name of this pyramid, or {@code null} if none.
* @param pyramid information about the pyramid.
- * @param levels the child resources from finest resolution to coarsest
resolution.
+ * @param levels the child resources in arbitrary order. This array
will be sorted in-place.
* @throws TransformException if an error occurred while deriving a "grid
to <abbr>CRS</abbr>" transform.
*/
Pyramid(final GeoHeifStore store, final GenericName name, final
ImagePyramid pyramid, final ImageResource[] levels)
@@ -75,9 +87,33 @@ final class Pyramid extends TiledGridCoverageResource
implements TiledGridCovera
tileSizeX = pyramid.tileSizeX;
tileSizeY = pyramid.tileSizeY;
this.levels = levels;
+ Arrays.sort(levels, LEVEL_COMPARATOR);
+ /*
+ * Select the finest level for which the "grid to CRS" transform, and
therefore the resolution,
+ * is defined. If none, select the very fist level, which should have
the finest resolution.
+ */
GridGeometry base = null;
+ boolean updateBase = true;
+ for (final ImageResource level : levels) {
+ final GridGeometry grid = level.getGridGeometry();
+ if (grid.isDefined(GridGeometry.GRID_TO_CRS)) {
+ updateBase = false; // Base is already complete.
+ base = grid;
+ break;
+ } else if (base == null) {
+ base = grid;
+ }
+ }
+ /*
+ * Now compute the "grid to CRS" transform for each pyramid level.
+ * It may include the base level itself if the transform was not
specified anywhere.
+ */
for (ImageResource level : levels) {
- base = level.setPyramidLevelOf(base);
+ level.setPyramidLevelOf(base);
+ if (updateBase) {
+ updateBase = false;
+ base = level.getGridGeometry();
+ }
}
}
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionConfiguration.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionConfiguration.java
index 1a050b4356..cb79b3b409 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionConfiguration.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionConfiguration.java
@@ -39,11 +39,15 @@ public final class CompressionConfiguration extends FullBox
{
/**
* The {@code "zlib"} value for {@link #compressionType}.
+ *
+ * @see <a href="https://www.ietf.org/rfc/rfc1950.pdf">IETF RFC 1950</a>
*/
public static final int COMPRESSION_ZLIB = ((((('z' << 8) | 'l') << 8) |
'i') << 8) | 'b';
/**
* The {@code "defl"} value for {@link #compressionType}.
+ *
+ * @see <a href="https://www.ietf.org/rfc/rfc1951.pdf">IETF RFC 1951</a>
*/
public static final int COMPRESSION_DEFLATE = ((((('d' << 8) | 'e') << 8)
| 'f') << 8) | 'l';