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 7190f99  RasterResource needs to take subsampling in account when 
computing the offset for reading a multi-banded variable.
7190f99 is described below

commit 7190f99935f9c4af79c438481c1ac9e3195843cb
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Mar 21 21:21:13 2019 +0100

    RasterResource needs to take subsampling in account when computing the 
offset for reading a multi-banded variable.
---
 .../java/org/apache/sis/math/MathFunctions.java    |  6 +-
 .../org/apache/sis/math/MathFunctionsTest.java     |  7 +-
 .../org/apache/sis/internal/netcdf/Raster.java     |  2 +-
 .../apache/sis/internal/netcdf/RasterResource.java | 16 ++--
 .../sis/internal/storage/AbstractGridResource.java | 91 +++++++++++++++++++---
 5 files changed, 98 insertions(+), 24 deletions(-)

diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java 
b/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
index 6269415..7b0e279 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
@@ -861,9 +861,11 @@ testNextNumber:         while (true) {      // Simulate a 
"goto" statement (usua
     }
 
     /**
-     * Returns the divisors which are common to all the specified numbers.
+     * Returns the positive divisors which are common to all the specified 
numbers.
+     * The returned array always starts with value 1, unless the given value 
is 0
+     * in which case this method returns an empty array.
      *
-     * @param  numbers  the numbers for which to compute the divisors.
+     * @param  numbers  the numbers for which to compute the divisors, in any 
order.
      * @return the divisors common to all the given numbers, in strictly 
increasing order.
      */
     public static int[] commonDivisors(final int... numbers) {
diff --git 
a/core/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java 
b/core/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java
index cb0664a..5e6b35f 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java
@@ -418,8 +418,9 @@ public final strictfp class MathFunctionsTest extends 
TestCase {
     @Test
     @DependsOnMethod("testDivisors")
     public void testCommonDivisors() {
-        assertArrayEquals(new int[] {
-            1, 5
-        }, commonDivisors(2000, 15));
+        assertArrayEquals(new int[] {1, 2, 4, 8}, commonDivisors(8));
+        assertArrayEquals(new int[] {1, 5}, commonDivisors(2000, 15));
+        assertArrayEquals(new int[] {1, 2}, commonDivisors(-4, 2));
+        assertArrayEquals(new int[] {}, commonDivisors(0));
     }
 }
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java
index a916d5b..e65ded4 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java
@@ -50,7 +50,7 @@ final class Raster extends GridCoverage {
     /**
      * Creates a new raster from the given resource.
      */
-    Raster(final GridGeometry domain, final List<SampleDimension> range, final 
DataBuffer data, final String label) {
+    Raster(final GridGeometry domain, final List<SampleDimension> range, final 
DataBuffer data, final int bandStride, final String label) {
         super(domain, range);
         this.data  = data;
         this.label = label;
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/RasterResource.java
 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/RasterResource.java
index 3501ee1..6403def 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/RasterResource.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/RasterResource.java
@@ -44,7 +44,6 @@ import org.apache.sis.math.MathFunctions;
 import org.apache.sis.measure.MeasurementRange;
 import org.apache.sis.measure.NumberRange;
 import org.apache.sis.util.Numbers;
-import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.resources.Vocabulary;
 
@@ -444,7 +443,7 @@ public final class RasterResource extends 
AbstractGridResource implements Resour
         if (domain == null) {
             domain = gridGeometry;
         }
-        final Variable first = data[rangeIndices.first()];
+        final Variable first = data[rangeIndices.getFirstSpecified()];
         final DataType dataType = first.getDataType();
         if (bandDimension < 0) {
             for (int i=0; i<rangeIndices.getNumBands(); i++) {
@@ -473,8 +472,7 @@ public final class RasterResource extends 
AbstractGridResource implements Resour
             int[] subsamplings = scales;
             if (bandDimension >= 0) {
                 areaOfInterest = 
rangeIndices.insertBandDimension(areaOfInterest, bandDimension);
-                subsamplings   = ArraysExt.insert(subsamplings, bandDimension, 
1);
-                subsamplings[bandDimension] = 1;
+                subsamplings   = rangeIndices.insertSubsampling  
(subsamplings,   bandDimension);
             }
             /*
              * Iterate over netCDF variables in the order they appear in the 
file, not in the order requested
@@ -499,7 +497,13 @@ public final class RasterResource extends 
AbstractGridResource implements Resour
                         values = variable.read(areaOfInterest, 
subsamplings).buffer().get();
                     }
                     if (bandDimension == 0) {
-                        values.position(r);
+                        /*
+                         * This block is executed only if the band dimension 
is first, in which case we have interleaved
+                         * values like (band0, band1) for each pixel. Those 
values are read only once in above block.
+                         * This block sets the offset of the first value to 
read. The pixel stride is not specified here;
+                         * it will be specified later, at 
java.awt.image.SampleModel construction time.
+                         */
+                        values.position(rangeIndices.getSubsampledIndex(i));
                     }
                     final int p = rangeIndices.getTargetIndex(i);
                     sampleValues[p] = values;
@@ -522,7 +526,7 @@ public final class RasterResource extends 
AbstractGridResource implements Resour
         if (imageBuffer == null) {
             throw new 
DataStoreContentException(Errors.getResources(getLocale()).getString(Errors.Keys.UnsupportedType_1,
 dataType.name()));
         }
-        return new Raster(domain, UnmodifiableArrayList.wrap(bands), 
imageBuffer, first.getStandardName());
+        return new Raster(domain, UnmodifiableArrayList.wrap(bands), 
imageBuffer, rangeIndices.getBandStride(), first.getStandardName());
     }
 
     /**
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractGridResource.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractGridResource.java
index 5ffb2a9..defb835 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractGridResource.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractGridResource.java
@@ -24,9 +24,11 @@ import org.apache.sis.storage.GridCoverageResource;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.math.MathFunctions;
 import org.apache.sis.storage.Resource;
 import org.apache.sis.util.logging.WarningListeners;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ArraysExt;
 import org.opengis.metadata.spatial.DimensionNameType;
 
 
@@ -150,6 +152,13 @@ public abstract class AbstractGridResource extends 
AbstractResource implements G
         private final long[] packed;
 
         /**
+         * If a {@linkplain #insertSubsampling subsampling} has been applied, 
indices of the first and last band
+         * to read, together with the interval (stride) between bands.  Those 
information are computed only when
+         * the {@code insertFoo(…)} methods are invoked.
+         */
+        private int first, last, interval;
+
+        /**
          * A builder for sample dimensions, created when first needed.
          */
         private SampleDimension.Builder builder;
@@ -159,6 +168,7 @@ public abstract class AbstractGridResource extends 
AbstractResource implements G
          */
         RangeArgument(final long[] packed) {
             this.packed = packed;
+            interval = 1;
         }
 
         /**
@@ -171,6 +181,21 @@ public abstract class AbstractGridResource extends 
AbstractResource implements G
         }
 
         /**
+         * Returns the value of the first index specified by the user. This is 
not necessarily equal to
+         * {@code getBandIndex(0)} if the user specified the bands out of 
order.
+         *
+         * @return index of the first value in the user-specified {@code 
range} array.
+         */
+        public int getFirstSpecified() {
+            for (final long p : packed) {
+                if (((int) p) == 0) {
+                    return (int) (p >>> Integer.SIZE);
+                }
+            }
+            throw new IllegalStateException();              // Should never 
happen.
+        }
+
+        /**
          * Returns the i<sup>th</sup> index of the band to read from the 
resource.
          * Indices are returned in strictly increasing order.
          *
@@ -193,30 +218,72 @@ public abstract class AbstractGridResource extends 
AbstractResource implements G
         }
 
         /**
-         * Returns the value of the first index specified by the user. This is 
not necessarily equal to
-         * {@code getBandIndex(0)} if the user specified bands out of order.
+         * Returns the i<sup>th</sup> index of the band to read from the 
resource, after subsampling has been applied.
+         * The subsampling results from calls to {@link 
#insertBandDimension(GridExtent, int)} and
+         * {@link #insertSubsampling(int[], int)} methods.
          *
-         * @return index of the first value in the user-specified {@code 
range} array.
+         * {@preformat java
+         *     areaOfInterest = 
rangeIndices.insertBandDimension(areaOfInterest, bandDimension);
+         *     subsamplings   = rangeIndices.insertSubsampling  (subsamplings, 
  bandDimension);
+         *     data = myReadMethod(areaOfInterest, subsamplings);
+         *     for (int i=0; i<numBands; i++) {
+         *         int bandIndexInTheDataWeJustRead = getSubsampledIndex(i);
+         *     }
+         * }
+         *
+         * If the {@code insert} methods have never been invoked, then this 
method is equivalent to {@link #getSourceIndex(int)}.
+         *
+         * @param  i  index of the range index to get, from 0 inclusive to 
{@link #getNumBands()} exclusive.
+         * @return index of the i<sup>th</sup> band to read from the resource, 
after subsampling.
          */
-        public int first() {
-            for (final long p : packed) {
-                if (((int) p) == 0) {
-                    return (int) (p >>> Integer.SIZE);
-                }
-            }
-            throw new IllegalStateException();              // Should never 
happen.
+        public int getSubsampledIndex(final int i) {
+            return (getSourceIndex(i) - first) / interval;
+        }
+
+        /**
+         * Returns the increment to apply on index for moving to the next 
pixel in the same band.
+         * If the {@code insert} methods have never been invoked, then this 
method returns the number of bands.
+         *
+         * @return the increment to apply on index for moving to the next 
pixel in the same band.
+         */
+        public int getBandStride() {
+            return (1 + last - first) / interval;
         }
 
         /**
          * Returns the given extent with a new dimension added for the bands. 
The extent in the new dimension
          * will range from the minimum {@code range} value to the maximum 
{@code range} value inclusive.
+         * This method should be used together with {@link 
#insertSubsampling(int[], int)}.
          *
          * @param  areaOfInterest  the extent to which to add a new dimension 
for bands.
          * @param  bandDimension   index of the band dimension.
-         * @return a new extent with the same value than the given extent plus 
one dimension for bands.
+         * @return a new extent with the same values than the given extent 
plus one dimension for bands.
          */
         public GridExtent insertBandDimension(final GridExtent areaOfInterest, 
final int bandDimension) {
-            return areaOfInterest.insert(bandDimension, BAND, 
getSourceIndex(0), getSourceIndex(packed.length - 1), true);
+            first = getSourceIndex(0);
+            last  = getSourceIndex(packed.length - 1);
+            return areaOfInterest.insert(bandDimension, BAND, first, last, 
true);
+        }
+
+        /**
+         * Returns the given subsampling with a new dimension added for the 
bands. The subsampling in the new
+         * dimension will be the greatest common divisor of the difference 
between all user-specified values.
+         * This method should be used together with {@link 
#insertBandDimension(GridExtent, int)}.
+         *
+         * @param  subsamplings   the subsampling to which to add a new 
dimension for bands.
+         * @param  bandDimension  index of the band dimension.
+         * @return a new subsampling array with the same values than the given 
array plus one dimension for bands.
+         */
+        public int[] insertSubsampling(int[] subsamplings, final int 
bandDimension) {
+            final int[] delta = new int[packed.length - 1];
+            for (int i=0; i<delta.length; i++) {
+                delta[i] = getSourceIndex(i+1) - getSourceIndex(i);
+            }
+            final int[] divisors = MathFunctions.commonDivisors(delta);
+            interval = (divisors.length != 0) ? divisors[divisors.length - 1] 
: 1;
+            subsamplings = ArraysExt.insert(subsamplings, bandDimension, 1);
+            subsamplings[bandDimension] = interval;
+            return subsamplings;
         }
 
         /**

Reply via email to