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
commit a4f26d4229b3bc599f26bbf8c8f3805a01608de7 Author: Martin Desruisseaux <[email protected]> AuthorDate: Tue Aug 2 14:55:35 2022 +0200 Make the netCDF reader more robust to the case where a coordinate system axis has zero dimension. Such axes are omitted, but we need to adjust the number of dimensions accordingly. --- .../java/org/apache/sis/internal/netcdf/Grid.java | 31 +++++++++------------- .../apache/sis/internal/netcdf/impl/GridInfo.java | 19 +++++++------ .../sis/internal/netcdf/impl/package-info.java | 2 +- .../sis/internal/netcdf/ucar/GridWrapper.java | 29 ++++++++++---------- .../apache/sis/storage/netcdf/MetadataReader.java | 21 +++++++-------- .../org/apache/sis/internal/netcdf/GridTest.java | 6 ++--- .../sis/internal/netcdf/impl/GridInfoTest.java | 4 +-- 7 files changed, 52 insertions(+), 60 deletions(-) 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 71af070182..0438456f1a 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 @@ -48,7 +48,7 @@ import org.apache.sis.util.ArraysExt; * if a variable dimensions should considered as bands instead of spatiotemporal dimensions. * * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.3 * * @see Decoder#getGridCandidates() * @@ -144,20 +144,17 @@ public abstract class Grid extends NamedElement { * This is the number of dimensions of the <em>grid</em>. * It should be equal to the size of {@link #getDimensions()} list. * + * <h4>Note on target dimensions</h4> + * A {@code getTargetDimensions()} method would return the number of dimensions of the + * <em>coordinate reference system</em>, which is the target of the <cite>"grid to CRS"</cite> conversion. + * However we do not provide that method because, while it should be equal to {@code getAxes(decoder).length}, + * it sometime differs because {@link #getAxes(Decoder)} may exclude axis with zero dimensions. + * The latter method should be used as the authoritative one. + * * @return number of grid dimensions. */ public abstract int getSourceDimensions(); - /** - * Returns the number of dimensions of target coordinates in the <cite>"grid to CRS"</cite> conversion. - * This is the number of dimensions of the <em>coordinate reference system</em>. - * It should be equal to the length of the array returned by {@link #getAxes(Decoder)}, - * but caller should be robust to inconsistencies. - * - * @return number of CRS dimensions. - */ - public abstract int getTargetDimensions(); - /** * Returns the dimensions of this grid, in netCDF (reverse of "natural") order. Each element in the list * contains the number of cells in the dimension, together with implementation-specific information. @@ -182,10 +179,8 @@ public abstract class Grid extends NamedElement { protected abstract List<Dimension> getDimensions(); /** - * Returns the axes of the coordinate reference system. The size of this array is expected equals to the - * value returned by {@link #getTargetDimensions()}, but the caller should be robust to inconsistencies. - * The axis order is CRS order (reverse of netCDF order) for consistency with the common practice in the - * {@code "coordinates"} attribute. + * Returns the axes of the coordinate reference system. The axis order is CRS order (reverse of netCDF order) + * for consistency with the common practice in the {@code "coordinates"} attribute. * * <p>This method returns a direct reference to the cached array; do not modify.</p> * @@ -397,9 +392,9 @@ public abstract class Grid extends NamedElement { * (the source) +1, and the number of rows is the number of dimensions in the CRS (the target) +1. * The order of dimensions in the transform is the reverse of the netCDF dimension order. */ - int lastSrcDim = getSourceDimensions(); // Will be decremented later, then kept final. - int lastTgtDim = getTargetDimensions(); - final int[] deferred = new int[axes.length]; // Indices of axes that have been deferred. + int lastSrcDim = getSourceDimensions(); // Will be decremented later, then kept final. + int lastTgtDim = axes.length; // Should be `getTargetDimensions()` but some axes may have been excluded. + final int[] deferred = new int[axes.length]; // Indices of axes that have been deferred. final List<MathTransform> nonLinears = new ArrayList<>(axes.length); final Matrix affine = Matrices.createZero(lastTgtDim + 1, lastSrcDim + 1); affine.setElement(lastTgtDim--, lastSrcDim--, 1); 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 27c97fd734..f41c864edf 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 @@ -42,7 +42,7 @@ import ucar.nc2.constants.CF; * * @author Martin Desruisseaux (Geomatys) * @author Johann Sorel (Geomatys) - * @version 1.0 + * @version 1.3 * @since 0.3 * @module */ @@ -120,16 +120,15 @@ final class GridInfo extends Grid { return domain.length; } - /** - * Returns the number of dimensions of target coordinates in the <cite>"grid to CRS"</cite> conversion. - * This is the number of dimensions of the <em>coordinate reference system</em>. - * It should be equal to the size of the array returned by {@link #getAxes(Decoder)}, - * but caller should be robust to inconsistencies. + /* + * A `getTargetDimensions()` method would be like below, but is + * excluded because `getAxes(…).length` is the authoritative value: + * + * @Override + * public int getTargetDimensions() { + * return range.length; + * } */ - @Override - public int getTargetDimensions() { - return range.length; - } /** * Returns the dimensions of this grid, in netCDF (reverse of "natural") order. diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java index 2319110d21..c44733af16 100644 --- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java +++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java @@ -30,7 +30,7 @@ * * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 1.3 * @since 0.3 * @module */ 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 2d0cde99b6..2eb9b2a8fc 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 @@ -45,7 +45,7 @@ import org.apache.sis.util.ArraysExt; * Many netCDF variables may be associated to the same {@code GridWrapper} instance.</p> * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.3 * @since 0.3 * @module */ @@ -193,16 +193,15 @@ final class GridWrapper extends Grid { return netcdfCS.getRankDomain(); } - /** - * Returns the number of dimensions of target coordinates in the <cite>"grid to CRS"</cite> conversion. - * This is the number of dimensions of the <em>coordinate reference system</em>. - * It should be equal to the length of the array returned by {@link #getAxes(Decoder)}, - * but caller should be robust to inconsistencies. + /* + * A `getTargetDimensions()` method would be like below, but is + * excluded because `getAxes(…).length` is the authoritative value: + * + * @Override + * public int getTargetDimensions() { + * return netcdfCS.getRankRange(); + * } */ - @Override - public int getTargetDimensions() { - return netcdfCS.getRankRange(); - } /** * Returns the dimensions of this grid, in netCDF (reverse of "natural") order. @@ -257,9 +256,9 @@ next: for (final String name : axisNames) { * In this method, `sourceDim` and `targetDim` are relative to "grid to CRS" conversion. * So `sourceDim` is the grid (domain) dimension and `targetDim` is the CRS (range) dimension. */ + int axisCount = 0; int targetDim = range.size(); final Axis[] axes = new Axis[targetDim]; - final int lastDim = targetDim - 1; while (--targetDim >= 0) { final CoordinateAxis axis = range.get(targetDim); final Variable wrapper = ((DecoderWrapper) decoder).getWrapperFor(axis); @@ -307,9 +306,11 @@ next: for (final String name : axisNames) { * package, we can proceed as if the dimension does not exist (`i` not incremented). */ } - axes[lastDim - targetDim] = new Axis(abbreviation, axis.getPositive(), - ArraysExt.resize(indices, i), ArraysExt.resize(sizes, i), wrapper); + if (i != 0) { // Variables with 0 dimensions sometime happen. + axes[axisCount++] = new Axis(abbreviation, axis.getPositive(), + ArraysExt.resize(indices, i), ArraysExt.resize(sizes, i), wrapper); + } } - return axes; + return ArraysExt.resize(axes, axisCount); } } 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 15c099b14b..d4996187bc 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 @@ -113,7 +113,7 @@ import static org.apache.sis.internal.util.CollectionsExt.first; * @author Martin Desruisseaux (Geomatys) * @author Thi Phuong Hao Nguyen (VNSC) * @author Alexis Manin (Geomatys) - * @version 1.2 + * @version 1.3 * @since 0.3 * @module */ @@ -684,17 +684,13 @@ split: while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt /** * Adds information about axes and cell geometry. * This is the {@code <mdb:spatialRepresentationInfo>} element in XML. + * We work on grid axes instead of Coordinate Reference System axes because + * {@code metadata/spatialRepresentationInfo/axisDimensionProperties/dimensionSize} seems to imply that. * * @param cs the grid geometry (related to the netCDF coordinate system). * @throws ArithmeticException if the size of an axis exceeds {@link Integer#MAX_VALUE}, or other overflow occurs. */ - private void addSpatialRepresentationInfo(final Grid cs) throws IOException, DataStoreException { - /* - * We work on grid axes instead of Coordinate Reference System axes because - * `metadata/spatialRepresentationInfo/axisDimensionProperties/dimensionSize` - * seems to imply that. - */ - final Axis[] axes = cs.getAxes(decoder); + private void addSpatialRepresentationInfo(final Axis[] axes) throws IOException, DataStoreException { for (int i=0; i<axes.length; i++) { final Axis axis = axes[i]; /* @@ -1059,10 +1055,11 @@ split: while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt * is built from the netCDF CoordinateSystem objects. */ for (final Grid cs : decoder.getGridCandidates()) { - if (cs.getSourceDimensions() >= Grid.MIN_DIMENSION && - cs.getTargetDimensions() >= Grid.MIN_DIMENSION) - { - addSpatialRepresentationInfo(cs); + if (cs.getSourceDimensions() >= Grid.MIN_DIMENSION) { + final Axis[] axes = cs.getAxes(decoder); + if (axes.length >= Grid.MIN_DIMENSION) { + addSpatialRepresentationInfo(axes); + } } } setISOStandards(hasGridCoverages); 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 f9f487d1e1..7f14447fb2 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 @@ -63,7 +63,7 @@ public strictfp class GridTest extends TestCase { } /** - * Tests {@link Grid#getSourceDimensions()} and {@link Grid#getTargetDimensions()}. + * Tests {@link Grid#getSourceDimensions()} and {@code Grid.getTargetDimensions()}. * * @throws IOException if an I/O error occurred while opening the file. * @throws DataStoreException if a logical error occurred. @@ -72,12 +72,12 @@ public strictfp class GridTest extends TestCase { public void testDimensions() throws IOException, DataStoreException { Grid geometry = getSingleton(filter(selectDataset(TestData.NETCDF_2D_GEOGRAPHIC).getGridCandidates())); assertEquals("getSourceDimensions()", 2, geometry.getSourceDimensions()); - assertEquals("getTargetDimensions()", 2, geometry.getTargetDimensions()); + assertEquals("getTargetDimensions()", 2, geometry.getAxes(decoder()).length); final int n = includeRuntimeDimension ? 5 : 4; geometry = getSingleton(filter(selectDataset(TestData.NETCDF_4D_PROJECTED).getGridCandidates())); assertEquals("getSourceDimensions()", 4, geometry.getSourceDimensions()); - assertEquals("getTargetDimensions()", n, geometry.getTargetDimensions()); + assertEquals("getTargetDimensions()", n, geometry.getAxes(decoder()).length); } /** diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/GridInfoTest.java b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/GridInfoTest.java index 3ed876279a..e084c7b054 100644 --- a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/GridInfoTest.java +++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/GridInfoTest.java @@ -34,7 +34,7 @@ import org.opengis.test.dataset.TestData; * passed. * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.3 * @since 0.3 * @module */ @@ -70,7 +70,7 @@ public final strictfp class GridInfoTest extends GridTest { final Grid[] copy = new Grid[geometries.length]; int count = 0; for (final Grid geometry : geometries) { - if (geometry.getSourceDimensions() != 1 || geometry.getTargetDimensions() != 1) { + if (geometry.getSourceDimensions() != 1) { copy[count++] = geometry; } }
