sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Exclude trailing rows containing only NaN values when building a localization grid.
Date Sun, 27 Jan 2019 23:05:50 GMT
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 9390dbe  Exclude trailing rows containing only NaN values when building a localization
grid.
9390dbe is described below

commit 9390dbea085fb218f8ca272a036ac2a3ec87b0ba
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Mon Jan 28 00:05:07 2019 +0100

    Exclude trailing rows containing only NaN values when building a localization grid.
---
 .../src/main/java/org/apache/sis/math/Vector.java  |   6 +-
 .../storage/earthobservation/LandsatReader.java    |  13 +-
 .../java/org/apache/sis/internal/netcdf/Axis.java  | 173 +++++++++++++++------
 .../org/apache/sis/internal/netcdf/CRSBuilder.java |   5 +-
 .../java/org/apache/sis/internal/netcdf/Grid.java  |   4 +-
 .../org/apache/sis/internal/netcdf/Variable.java   |   9 +-
 .../apache/sis/internal/netcdf/impl/GridInfo.java  |  17 +-
 .../sis/internal/netcdf/impl/VariableInfo.java     |  10 +-
 .../sis/internal/netcdf/ucar/GridWrapper.java      |   9 +-
 .../sis/internal/netcdf/ucar/VariableWrapper.java  |   3 +-
 .../apache/sis/storage/netcdf/MetadataReader.java  |   2 +-
 .../org/apache/sis/internal/netcdf/GridTest.java   |  12 +-
 .../sis/internal/storage/MetadataBuilder.java      |  11 +-
 13 files changed, 185 insertions(+), 89 deletions(-)

diff --git a/core/sis-utility/src/main/java/org/apache/sis/math/Vector.java b/core/sis-utility/src/main/java/org/apache/sis/math/Vector.java
index c8d2c6b..d7b76b2 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/math/Vector.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/math/Vector.java
@@ -561,7 +561,7 @@ public abstract class Vector extends AbstractList<Number> implements
RandomAcces
         if (size >= 2) {
             /*
              * For the first level of repetitions, we rely on a method to be overridden by
subclasses
-             * for detecting the length of consecutive identical numbers. We could have use
the more
+             * for detecting the length of consecutive identical numbers. We could have used
the more
              * generic algorithm based on 'equals(int, int, Vector, int)' instead, but this
approach
              * is faster.
              */
@@ -593,7 +593,9 @@ search:     for (;;) {
                             r = size;                                       // Sentinel value
for repetition not found.
                             break search;
                         }
-                        r = r0 * candidates[candidateIndex++];
+                        final int n = candidates[candidateIndex++];
+                        ArgumentChecks.ensureStrictlyPositive("candidates", n);
+                        r = Math.multiplyExact(r0, n);
                     } while (r <= 0 || r >= size);
                 } else {
                     r += r0;
diff --git a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java
b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java
index 13ab435..2822a97 100644
--- a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java
+++ b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java
@@ -245,9 +245,8 @@ final class LandsatReader {
     private final double[] corners;
 
     /**
-     * Image width and hight, in pixels. Values are (<var>width</var>,<var>height</var>)
tuples.
-     * Tuples in this array are for {@link #PANCHROMATIC}, {@link #REFLECTIVE} or {@link
#THERMAL}
-     * bands, in that order.
+     * Image width and hight in pixels, as unsigned integers. Values are (<var>width</var>,<var>height</var>)
tuples.
+     * Tuples in this array are for {@link #PANCHROMATIC}, {@link #REFLECTIVE} or {@link
#THERMAL} bands, in that order.
      */
     private final int[] gridSizes;
 
@@ -408,7 +407,7 @@ final class LandsatReader {
      * @param  value  the value to parse.
      */
     private void parseGridSize(final int index, final String value) throws NumberFormatException
{
-        gridSizes[index] = Integer.parseInt(value);
+        gridSizes[index] = Integer.parseUnsignedInt(value);
     }
 
     /**
@@ -942,12 +941,12 @@ final class LandsatReader {
         for (int i = 0; i < gridSizes.length; i += DIM) {
             final int width  = gridSizes[i  ];
             final int height = gridSizes[i+1];
-            if (width != 0 || height != 0) {
+            if ((width | height) != 0) {
                 metadata.newGridRepresentation(MetadataBuilder.GridType.GEORECTIFIED);
                 metadata.setAxisName(0, DimensionNameType.SAMPLE);
                 metadata.setAxisName(1, DimensionNameType.LINE);
-                metadata.setAxisLength(0, width);
-                metadata.setAxisLength(1, height);
+                metadata.setAxisSize(0, Integer.toUnsignedLong(width));
+                metadata.setAxisSize(1, Integer.toUnsignedLong(height));
             }
         }
         /*
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java
index d015017..ed97e08 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java
@@ -32,6 +32,7 @@ import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
 import org.apache.sis.internal.metadata.AxisDirections;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.metadata.iso.citation.Citations;
@@ -113,15 +114,25 @@ public final class Axis extends NamedElement implements Comparable<Axis>
{
     final int[] sourceDimensions;
 
     /**
-     * The number of cell elements along the source grid dimensions. The length of this array
shall be
-     * equals to the {@link #sourceDimensions} length. For each element, {@code sourceSizes[i]}
shall
-     * be equals to the number of grid cells in the grid dimension at index {@code sourceDimensions[i]}.
+     * The number of cell elements along the source grid dimensions, as unsigned integers.
The length of this
+     * array shall be equal to the {@link #sourceDimensions} length. For each element, {@code
sourceSizes[i]}
+     * shall be equal to the number of grid cells in the grid dimension at index {@code sourceDimensions[i]}.
+     *
+     * <p>This array should contain the same information as {@code coordinates.getShape()}
but potentially in
+     * a different order and with potentially one element (not necessarily the first one)
set to a lower value
+     * in order to avoid trailing {@link Float#NaN} values.</p>
+     *
+     * <p>Note that while we defined those values as unsigned for consistency with
{@link Variable} dimensions,
+     * not all operations in this {@code Axis} class support values greater than the signed
integer range.</p>
+     *
+     * @see Variable#getShape()
      */
-    final int[] sourceSizes;
+    private final int[] sourceSizes;
 
     /**
      * Values of coordinates on this axis for given grid indices. This variables is often
one-dimensional,
-     * but can also be two-dimensional.
+     * but can also be two-dimensional. Coordinate values should be read with the {@link
#read()} method
+     * in this {@code Axis} class instead than {@link Variable#read()} for trimming trailing
NaN values.
      */
     final Variable coordinates;
 
@@ -129,14 +140,17 @@ public final class Axis extends NamedElement implements Comparable<Axis>
{
      * Constructs a new axis associated to an arbitrary number of grid dimension. The given
arrays are stored
      * as-in (not cloned) and their content may be modified after construction by {@link
Grid#getAxes()}.
      *
-     * @param  axis              an implementation-dependent object representing the axis.
      * @param  abbreviation      axis abbreviation, also identifying its type. This is a
controlled vocabulary.
      * @param  direction         direction of positive values ("up" or "down"), or {@code
null} if unknown.
-     * @param  sourceDimensions  the index of the grid dimension associated to this axis.
-     * @param  sourceSizes       the number of cell elements along that axis.
+     * @param  sourceDimensions  the index of the grid dimension associated to this axis,
initially in netCDF order.
+     * @param  sourceSizes       the number of cell elements along that axis, as unsigned
integers.
+     * @param  coordinates       coordinates of the localization grid used by this axis.
+     * @throws IOException if an I/O operation was necessary but failed.
+     * @throws DataStoreException if a logical error occurred.
+     * @throws ArithmeticException if the size of an axis exceeds {@link Integer#MAX_VALUE},
or other overflow occurs.
      */
-    public Axis(final Variable axis, char abbreviation, final String direction,
-                final int[] sourceDimensions, final int[] sourceSizes)
+    public Axis(final char abbreviation, final String direction, final int[] sourceDimensions,
final int[] sourceSizes,
+                final Variable coordinates) throws IOException, DataStoreException
     {
         /*
          * Try to get the axis direction from one of the following sources,
@@ -161,7 +175,7 @@ public final class Axis extends NamedElement implements Comparable<Axis>
{
             isConsistent = AxisDirections.isColinear(dir, check);
         }
         if (isConsistent) {
-            check = direction(axis.getUnitsString());
+            check = direction(coordinates.getUnitsString());
             if (dir == null) {
                 dir = check;
             } else if (check != null) {
@@ -169,8 +183,8 @@ public final class Axis extends NamedElement implements Comparable<Axis>
{
             }
         }
         if (!isConsistent) {
-            axis.warning(Grid.class, "getAxes",                     // Caller of this constructor.
-                         Resources.Keys.AmbiguousAxisDirection_4, axis.getFilename(), axis.getName(),
dir, check);
+            coordinates.warning(Grid.class, "getAxes",              // Caller of this constructor.
+                    Resources.Keys.AmbiguousAxisDirection_4, coordinates.getFilename(), coordinates.getName(),
dir, check);
             if (isSigned) {
                 if (AxisDirections.isOpposite(dir)) {
                     check = AxisDirections.opposite(check);         // Apply the sign of
'dir' on 'check'.
@@ -182,7 +196,23 @@ public final class Axis extends NamedElement implements Comparable<Axis>
{
         this.abbreviation     = abbreviation;
         this.sourceDimensions = sourceDimensions;
         this.sourceSizes      = sourceSizes;
-        this.coordinates      = axis;
+        this.coordinates      = coordinates;
+        /*
+         * If the variable for localization grid declares a fill value, maybe the last rows
are all NaN.
+         * We need to trim them from this axis, otherwise it will confuse the grid geometry
calculation.
+         * Following operation must be done before mainDimensionFirst(…) is invoked, otherwise
the order
+         * of elements in 'sourceSizes' would not be okay anymore.
+         */
+        if (coordinates.getAttributeType(CDM.FILL_VALUE) != null) {
+            final int page = getSizeProduct(1);            // Must exclude first dimension
from computation.
+            final Vector data = coordinates.read();
+            int n = data.size();
+            while (--n >= 0 && data.isNaN(n)) {}
+            final int nr = Numerics.ceilDiv(++n, page);
+            assert nr <= sourceSizes[0] : nr;
+            sourceSizes[0] = nr;
+            assert getSizeProduct(0) == n : n;
+        }
     }
 
     /**
@@ -226,16 +256,18 @@ public final class Axis extends NamedElement implements Comparable<Axis>
{
             final int[] other = axes[i].sourceDimensions;
             if (other.length != 0) {
                 final int first = other[0];
-                if  (first == d1) return;          // Swapping would cause a collision.
+                if  (first == d1) return;           // Swapping would cause a collision.
                 s = (first == d0);
-                if (s) break;                      // Need swapping for avoiding collision.
+                if (s) break;                       // Need swapping for avoiding collision.
             }
         }
         if (!s) {
-            final int up0  = sourceSizes[0];
-            final int up1  = sourceSizes[1];
-            final int mid0 = up0 / 2;
-            final int mid1 = up1 / 2;
+            int up0 = sourceSizes[0];
+            int up1 = sourceSizes[1];
+            final int mid0 = up0 >>> 1;             // Division by 2 of unsigned
integers.
+            final int mid1 = up1 >>> 1;
+            if (up0 < 0) up0 = Integer.MAX_VALUE;   // For unsigned integers, < 0 means
overflow.
+            if (up1 < 0) up1 = Integer.MAX_VALUE;
             final double inc0 = (coordinates.coordinateForAxis(    0, mid1) -
                                  coordinates.coordinateForAxis(up0-1, mid1)) / up0;
             final double inc1 = (coordinates.coordinateForAxis(mid0,     0) -
@@ -260,14 +292,43 @@ public final class Axis extends NamedElement implements Comparable<Axis>
{
     }
 
     /**
+     * Returns the product of all {@link #sourceSizes} values starting at the given index.
+     * The product of all sizes given by {@code getSizeProduct(0)} shall be the length of
+     * the vector returned by {@link #read()}.
+     *
+     * @param  i  index of the first size to include in the product.
+     * @return the product of all {@link #sourceSizes} values starting at the given index.
+     * @throws ArithmeticException if the product can not be represented as a signed 32 bits
integer.
+     */
+    private int getSizeProduct(int i) {
+        int length = 1;
+        while (i < sourceSizes.length) {
+            length = Math.multiplyExact(length, getSize(i++));
+        }
+        return length;
+    }
+
+    /**
+     * Returns the {@link #sourceSizes} value at the given index, making sure it is representable
as a
+     * signed integer value. This method is invoked by operations not designed for unsigned
integers.
+     *
+     * @throws ArithmeticException if the size can not be represented as a signed 32 bits
integer.
+     */
+    private int getSize(final int i) {
+        final int n = sourceSizes[i];
+        if (n >= 0) return n;
+        throw new ArithmeticException("signed integer overflow");
+    }
+
+    /**
      * Returns the number of cells in the first dimension of the localization grid used by
this axis.
      * If the localization grid has more than one dimension ({@link #getDimension()} {@literal
> 1}),
      * then all additional dimensions are ignored. The first dimension should be the main
one.
      *
      * @return number of cells in the first (main) dimension of the localization grid.
      */
-    public final int getLength() {
-        return (sourceSizes.length != 0) ? sourceSizes[0] : 0;
+    public final long getSize() {
+        return (sourceSizes.length != 0) ? Integer.toUnsignedLong(sourceSizes[0]) : 0;
     }
 
     /**
@@ -327,7 +388,7 @@ public final class Axis extends NamedElement implements Comparable<Axis>
{
             case 'φ': min =  Latitude.MIN_VALUE; wraparound = false; break;
             default: return false;
         }
-        final Vector data = coordinates.read();
+        final Vector data = read();
         final int size = data.size();
         if (size != 0) {
             Unit<?> unit = getUnit();
@@ -457,11 +518,12 @@ main:   switch (getDimension()) {
              * Normal case where the axis has only one dimension.
              */
             case 1: {
+                final Vector data = read();
                 final int srcDim = lastSrcDim - sourceDimensions[0];                // Convert
from netCDF to "natural" order.
-                if (coordinates.trySetTransform(gridToCRS, srcDim, tgtDim, null)) {
+                if (coordinates.trySetTransform(gridToCRS, srcDim, tgtDim, data)) {
                     return true;
                 } else {
-                    nonLinears.add(MathTransforms.interpolate(null, coordinates.read().doubleValues()));
+                    nonLinears.add(MathTransforms.interpolate(null, data.doubleValues()));
                     return false;
                 }
             }
@@ -486,15 +548,16 @@ main:   switch (getDimension()) {
              * be generalized to n-dimensional case if we resolve the default case in the
switch statement.
              */
             case 2: {
-                Vector data = coordinates.read();
+                Vector data = read();
                 final int[] repetitions = data.repetitions(sourceSizes);        // Detects
repetitions as illustrated above.
                 long repetitionLength = 1;
                 for (int r : repetitions) {
                     repetitionLength = Math.multiplyExact(repetitionLength, r);
                 }
+                final int ri = (sourceDimensions[0] <= sourceDimensions[1]) ? 0 : 1;
                 for (int i=0; i<=1; i++) {
-                    final int width  = sourceSizes[i    ];
-                    final int height = sourceSizes[i ^ 1];
+                    final int width  = getSize(ri ^ i    );
+                    final int height = getSize(ri ^ i ^ 1);
                     if (repetitionLength % width == 0) {            // Repetition length
shall be grid width (or a divisor).
                         final int length, step;
                         if (repetitions.length >= 2) {
@@ -542,27 +605,49 @@ main:   switch (getDimension()) {
             final int o2 = other.sourceDimensions[1];
             if ((o1 == d1 && o2 == d2) || (o1 == d2 && o2 == d1)) {
                 /*
-                 * Found two axes for the same set of dimensions, which implies that they
have
-                 * the same shape (width and height).
+                 * Found two axes for the same set of dimensions, which implies that they
have the same
+                 * shape (width and height) unless the two axes ignored a different amount
of NaN values.
+                 * Negative width and height means that their actual values overflow the
'int' capacity,
+                 * which we can not process here.
                  */
-                final int width  = sourceSizes[0];
-                final int height = sourceSizes[1];
-                final LocalizationGridBuilder grid = new LocalizationGridBuilder(width, height);
-                final Vector v1 =       coordinates.read();
-                final Vector v2 = other.coordinates.read();
-                final double[] target = new double[2];
-                int index = 0;
-                for (int y=0; y<height; y++) {
-                    for (int x=0; x<width; x++) {
-                        target[0] = v1.doubleValue(index);
-                        target[1] = v2.doubleValue(index);
-                        grid.setControlPoint(x, y, target);
-                        index++;
+                final int ri = (d1 <= d2) ? 0 : 1;  // Take in account that mainDimensionFirst(…)
may have reordered values.
+                final int ro = (o1 <= o2) ? 0 : 1;
+                final int width  = getSize(ri    );
+                final int height = getSize(ri ^ 1);
+                if (other.sourceSizes[ro    ] != width ||
+                    other.sourceSizes[ro ^ 1] != height)
+                {
+                    coordinates.error(Grid.class, "getGridGeometry", null,
+                            Errors.Keys.MismatchedGridGeometry_2, getName(), other.getName());
+                } else {
+                    final LocalizationGridBuilder grid = new LocalizationGridBuilder(width,
height);
+                    final Vector v1 =       read();
+                    final Vector v2 = other.read();
+                    final double[] target = new double[2];
+                    int index = 0;
+                    for (int y=0; y<height; y++) {
+                        for (int x=0; x<width; x++) {
+                            target[0] = v1.doubleValue(index);
+                            target[1] = v2.doubleValue(index);
+                            grid.setControlPoint(x, y, target);
+                            index++;
+                        }
                     }
+                    return grid;
                 }
-                return grid;
             }
         }
         return null;
     }
+
+    /**
+     * Returns the coordinates in the localization grid, excluding some trailing NaN values
if any.
+     * This method typically returns a cached vector if the coordinates have already been
read.
+     *
+     * @throws IOException if an error occurred while reading the data.
+     * @throws DataStoreException if a logical error occurred.
+     */
+    final Vector read() throws IOException, DataStoreException {
+        return coordinates.read().subList(0, getSizeProduct(0));
+    }
 }
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java
index 5aa2f12..a2367f4 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java
@@ -27,6 +27,7 @@ import java.io.IOException;
 import java.time.Instant;
 import javax.measure.Unit;
 import org.opengis.util.FactoryException;
+import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.cs.*;
 import org.opengis.referencing.datum.*;
 import org.opengis.referencing.crs.SingleCRS;
@@ -334,7 +335,7 @@ previous:   for (int i=components.size(); --i >= 0;) {
         for (int i=cs.getDimension(); --i >= 0;) {
             final CoordinateSystemAxis axis = cs.getAxis(i);
             if (RangeMeaning.WRAPAROUND.equals(axis.getRangeMeaning())) {
-                final Vector coordinates = axes[i].coordinates.read();
+                final Vector coordinates = axes[i].read();                          // Typically
a cached vector.
                 final int length = coordinates.size();
                 if (length != 0) {
                     final double first = coordinates.doubleValue(0);
@@ -368,7 +369,7 @@ previous:   for (int i=components.size(); --i >= 0;) {
      * @param  name  name of the geodetic object (datum, coordinate system, …) to create.
      */
     private static Map<String,?> properties(final Object name) {
-        return Collections.singletonMap(GeodeticDatum.NAME_KEY, name);
+        return Collections.singletonMap(IdentifiedObject.NAME_KEY, name);
     }
 
     /**
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
index 49ce6b7..b957391 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
@@ -185,9 +185,11 @@ public abstract class Grid extends NamedElement {
      * Creates the axes to be returned by {@link #getAxes()}. This method is invoked only
once when first needed.
      *
      * @return the CRS axes, in netCDF order (reverse of "natural" order).
+     * @throws IOException if an I/O operation was necessary but failed.
      * @throws DataStoreException if a logical error occurred.
+     * @throws ArithmeticException if the size of an axis exceeds {@link Integer#MAX_VALUE},
or other overflow occurs.
      */
-    protected abstract Axis[] createAxes() throws DataStoreException;
+    protected abstract Axis[] createAxes() throws IOException, DataStoreException;
 
     /**
      * Returns the coordinate reference system, or {@code null} if none.
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
index 825d60f..6a66ed9 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
@@ -663,7 +663,7 @@ public abstract class Variable extends NamedElement {
     }
 
     /**
-     * Maybe replace fill values and missing values by {@code NaN} values in the given array.
+     * Maybe replaces fill values and missing values by {@code NaN} values in the given array.
      * This method does nothing if {@link #hasRealValues()} returns {@code false}.
      * The NaN values used by this method must be consistent with the NaN values declared
in
      * the sample dimensions created by {@link org.apache.sis.storage.netcdf.GridResource}.
@@ -709,17 +709,14 @@ public abstract class Variable extends NamedElement {
      * @param  gridToCRS  the matrix in which to set scale and offset coefficient.
      * @param  srcDim     the source dimension, which is a dimension of the grid. Identifies
the matrix column of scale factor.
      * @param  tgtDim     the target dimension, which is a dimension of the CRS.  Identifies
the matrix row of scale factor.
-     * @param  values     the vector to use for computing scale and offset, or {@code null}
if it has not been read yet.
+     * @param  values     the vector to use for computing scale and offset.
      * @return whether this method has successfully set the scale and offset coefficients.
      * @throws IOException if an error occurred while reading the data.
      * @throws DataStoreException if a logical error occurred.
      */
-    protected boolean trySetTransform(final Matrix gridToCRS, final int srcDim, final int
tgtDim, Vector values)
+    protected boolean trySetTransform(final Matrix gridToCRS, final int srcDim, final int
tgtDim, final Vector values)
             throws IOException, DataStoreException
     {
-        if (values == null) {
-            values = read();
-        }
         final int n = values.size() - 1;
         if (n >= 0) {
             final double first = values.doubleValue(0);
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
index cf9d66a..2a03a29 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.netcdf.impl;
 
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.Locale;
 import java.util.Map;
@@ -76,8 +77,10 @@ final class GridInfo extends Grid {
     /**
      * Describes the input values expected by the function converting grid indices to geodetic
coordinates.
      * They are the dimensions of the grid (<strong>not</strong> the dimensions
of the CRS).
+     * Dimensions are listed in the order they appear in netCDF file (reverse of "natural"
order).
      *
      * @see #getShape()
+     * @see VariableInfo#dimensions
      */
     private final Dimension[] domain;
 
@@ -96,7 +99,7 @@ final class GridInfo extends Grid {
      * Constructs a new grid geometry information.
      * The {@code domain} and {@code range} arrays often have the same length, but not necessarily.
      *
-     * @param  domain    describes the input values of the "grid to CRS" conversion.
+     * @param  domain    describes the input values of the "grid to CRS" conversion, in netCDF
order.
      * @param  range     the output values of the "grid to CRS" conversion.
      * @param  sortAxes  whether axes should be sorted instead than relying on the order
found in netCDF file.
      */
@@ -170,7 +173,7 @@ final class GridInfo extends Grid {
         final int    dim  = domain.length;
         final long[] size = new long[dim];
         for (int i=0; i<dim; i++) {
-            size[(dim-1) - i] = Integer.toUnsignedLong(domain[i].length);
+            size[(dim-1) - i] = domain[i].length();
         }
         return size;
     }
@@ -188,10 +191,12 @@ final class GridInfo extends Grid {
      * "two-dimensional axes" (in {@link ucar.nc2.dataset.CoordinateAxis2D} sense).</p>
      *
      * @return the CRS axes, in netCDF order (reverse of "natural" order).
+     * @throws IOException if an I/O operation was necessary but failed.
      * @throws DataStoreException if a logical error occurred.
+     * @throws ArithmeticException if the size of an axis exceeds {@link Integer#MAX_VALUE},
or other overflow occurs.
      */
     @Override
-    protected Axis[] createAxes() throws DataStoreException {
+    protected Axis[] createAxes() throws IOException, DataStoreException {
         /*
          * Process the variables in the order the appear in the sequence of bytes that make
the netCDF files.
          * This is often the same order than the indices, but not necessarily. The intent
is to reduce the
@@ -231,7 +236,7 @@ final class GridInfo extends Grid {
             final int[] indices = new int[axisDomain.length];
             final int[] sizes   = new int[axisDomain.length];
             for (final Dimension dimension : axisDomain) {
-                for (int sourceDim = domain.length; --sourceDim >= 0;) {
+                for (int sourceDim = 0; sourceDim < domain.length; sourceDim++) {
                     if (domain[sourceDim] == dimension) {
                         indices[i] = sourceDim;
                         sizes[i++] = dimension.length;
@@ -239,8 +244,8 @@ final class GridInfo extends Grid {
                     }
                 }
             }
-            axes[targetDim] = new Axis(axis, abbreviation, axis.getAttributeAsString(CF.POSITIVE),
-                                       ArraysExt.resize(indices, i), ArraysExt.resize(sizes,
i));
+            axes[targetDim] = new Axis(abbreviation, axis.getAttributeAsString(CF.POSITIVE),
+                                       ArraysExt.resize(indices, i), ArraysExt.resize(sizes,
i), axis);
         }
         if (sortAxes) {
             Arrays.sort(axes);
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
index daa275e..664b990 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
@@ -96,6 +96,9 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo>
{
      * The dimensions of this variable, in the order they appear in netCDF file. When iterating
over the values stored in
      * this variable (a flattened one-dimensional sequence of values), index in the domain
of {@code dimensions[length-1]}
      * varies faster, followed by index in the domain of {@code dimensions[length-2]}, <i>etc.</i>
+     *
+     * @see #getShape()
+     * @see GridInfo#domain
      */
     final Dimension[] dimensions;
 
@@ -493,7 +496,6 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo>
{
     /**
      * Returns the length (number of cells) of each grid dimension. In ISO 19123 terminology,
this method
      * returns the upper corner of the grid envelope plus one. The lower corner is always
(0,0,…,0).
-     * This method is used mostly for building string representations of this variable.
      *
      * @return the number of grid cells for each dimension, as unsigned integers.
      */
@@ -820,8 +822,10 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo>
{
      */
     @Override
     protected double coordinateForAxis(final int j, final int i) throws IOException, DataStoreException
{
-        final int n = dimensions[0].length;
-        return read().doubleValue(j + n*i);
+        assert j >= 0 && j < dimensions[0].length : j;
+        assert i >= 0 && i < dimensions[1].length : i;
+        final long n = dimensions[0].length();
+        return read().doubleValue(Math.toIntExact(j + n*i));
     }
 
     /**
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
index 20f980a..7bd7b59 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.netcdf.ucar;
 
+import java.io.IOException;
 import java.util.List;
 import ucar.nc2.Dimension;
 import ucar.nc2.constants.AxisType;
@@ -123,10 +124,12 @@ final class GridWrapper extends Grid {
      * of {@link CoordinateAxis2D}.</p>
      *
      * @return the CRS axes, in netCDF order (reverse of "natural" order).
+     * @throws IOException if an I/O operation was necessary but failed.
      * @throws DataStoreException if a logical error occurred.
+     * @throws ArithmeticException if the size of an axis exceeds {@link Integer#MAX_VALUE},
or other overflow occurs.
      */
     @Override
-    protected Axis[] createAxes() throws DataStoreException {
+    protected Axis[] createAxes() throws IOException, DataStoreException {
         final List<Dimension> domain = netcdfCS.getDomain();
         final List<CoordinateAxis> range = netcdfCS.getCoordinateAxes();
         /*
@@ -178,8 +181,8 @@ final class GridWrapper extends Grid {
                  * package, we can proceed as if the dimension does not exist ('i' not incremented).
                  */
             }
-            axes[targetDim] = new Axis(decoder.getWrapperFor(axis), abbreviation, axis.getPositive(),
-                                       ArraysExt.resize(indices, i), ArraysExt.resize(sizes,
i));
+            axes[targetDim] = new Axis(abbreviation, axis.getPositive(),
+                    ArraysExt.resize(indices, i), ArraysExt.resize(sizes, i), decoder.getWrapperFor(axis));
         }
         return axes;
     }
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
index f91a90e..8927cb1 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
@@ -255,7 +255,6 @@ final class VariableWrapper extends Variable {
     /**
      * Returns the length (number of cells) of each grid dimension. In ISO 19123 terminology,
this method
      * returns the upper corner of the grid envelope plus one. The lower corner is always
(0,0,…,0).
-     * This method is used mostly for building string representations of this variable.
      */
     @Override
     public int[] getShape() {
@@ -438,7 +437,7 @@ final class VariableWrapper extends Variable {
     protected boolean trySetTransform(final Matrix gridToCRS, final int srcDim, final int
tgtDim, final Vector values)
             throws IOException, DataStoreException
     {
-        if (values == null && variable instanceof CoordinateAxis1D) {
+        if (variable instanceof CoordinateAxis1D) {
             final CoordinateAxis1D axis = (CoordinateAxis1D) variable;
             if (axis.isRegular()) {
                 final double start     = axis.getStart();
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
index 2127810..056ee2a 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
@@ -725,7 +725,7 @@ split:  while ((start = CharSequences.skipLeadingWhitespaces(value, start,
lengt
              * oriented toward the axis direction.
              */
             if (axis.getDimension() >= 1) {
-                setAxisLength(dim, axis.getLength());
+                setAxisSize(dim, axis.getSize());
             }
             final AttributeNames.Dimension attributeNames;
             switch (axis.abbreviation) {
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridTest.java
b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridTest.java
index 62b12ca..b8f7280 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridTest.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridTest.java
@@ -90,8 +90,8 @@ public strictfp class GridTest extends TestCase {
         assertArrayEquals(new int[] {1}, x.sourceDimensions);
         assertArrayEquals(new int[] {0}, y.sourceDimensions);
 
-        assertArrayEquals(new int[] {73}, x.sourceSizes);
-        assertArrayEquals(new int[] {73}, y.sourceSizes);
+        assertEquals(73, x.getSize());
+        assertEquals(73, y.getSize());
     }
 
     /**
@@ -120,9 +120,9 @@ public strictfp class GridTest extends TestCase {
         assertArrayEquals(new int[] {1}, z.sourceDimensions);
         assertArrayEquals(new int[] {0}, t.sourceDimensions);
 
-        assertArrayEquals(new int[] {38}, x.sourceSizes);
-        assertArrayEquals(new int[] {19}, y.sourceSizes);
-        assertArrayEquals(new int[] { 4}, z.sourceSizes);
-        assertArrayEquals(new int[] { 1}, t.sourceSizes);
+        assertEquals(38, x.getSize());
+        assertEquals(19, y.getSize());
+        assertEquals( 4, z.getSize());
+        assertEquals( 1, t.getSize());
     }
 }
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
index ae639fe..d80516d 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
@@ -1946,10 +1946,7 @@ parse:      for (int i = 0; i < length;) {
                     if (axisType.isPresent()) {
                         setAxisName(i, axisType.get());
                     }
-                    final long size = extent.getSize(i);
-                    if (size >= 0 && size <= Integer.MAX_VALUE) {
-                        setAxisLength(i, (int) size);
-                    }
+                    setAxisSize(i, extent.getSize(i));
                 }
             }
             if (addResolution && grid.isDefined(GridGeometry.RESOLUTION)) {
@@ -2179,8 +2176,10 @@ parse:      for (int i = 0; i < length;) {
      * @param  dimension  the axis dimension.
      * @param  length     number of cell values along the given dimension.
      */
-    public final void setAxisLength(final int dimension, final int length) {
-        axis(dimension).setDimensionSize(shared(length));
+    public final void setAxisSize(final int dimension, final long length) {
+        if (length >= 0) {
+            axis(dimension).setDimensionSize(shared(length > Integer.MAX_VALUE ? Integer.MAX_VALUE
: (int) length));
+        }
     }
 
     /**


Mime
View raw message