Search in sources :

Example 1 with GridDerivation

use of org.apache.sis.coverage.grid.GridDerivation in project sis by apache.

the class CoverageReadConsistency method readAndCompareRandomRegions.

/**
 * Implementation of methods testing reading in random sub-regions with random sub-samplings.
 *
 * @param  label  a label for the test being run.
 * @throws DataStoreException if an error occurred while using the resource.
 */
private void readAndCompareRandomRegions(final String label) throws DataStoreException {
    randomConfigureResource();
    final GridGeometry gg = resource.getGridGeometry();
    final int dimension = gg.getDimension();
    final long[] low = new long[dimension];
    final long[] high = new long[dimension];
    final int[] subsampling = new int[dimension];
    final int[] subOffsets = new int[dimension];
    final int numBands = resource.getSampleDimensions().size();
    /*
         * We will collect statistics on execution time only if the
         * test is executed in a more verbose mode than the default.
         */
    final Statistics durations = (VERBOSE || !failOnMismatch) ? new Statistics(label) : null;
    int failuresCount = 0;
    for (int it = 0; it < numIterations; it++) {
        final GridGeometry domain = randomDomain(gg, low, high, subsampling);
        final int[] selectedBands = randomRange(numBands);
        /*
             * Read a coverage containing the requested sub-domain. Note that the reader is free to read
             * more data than requested. The extent actually read is `actualReadExtent`. It shall contain
             * fully the requested `domain`.
             */
        final long startTime = System.nanoTime();
        final GridCoverage subset = resource.read(domain, selectedBands);
        final GridExtent actualReadExtent = subset.getGridGeometry().getExtent();
        if (failOnMismatch) {
            assertEquals("Unexpected number of dimensions.", dimension, actualReadExtent.getDimension());
            for (int d = 0; d < dimension; d++) {
                if (subsampling[d] == 1) {
                    assertTrue("Actual extent is too small.", actualReadExtent.getSize(d) > high[d] - low[d]);
                    assertTrue("Actual extent is too small.", actualReadExtent.getLow(d) <= low[d]);
                    assertTrue("Actual extent is too small.", actualReadExtent.getHigh(d) >= high[d]);
                }
            }
        }
        /*
             * If subsampling was enabled, the factors selected by the reader may be different than
             * the subsampling factors that we specified. The following block updates those values.
             */
        if (allowSubsampling && full != null) {
            final GridDerivation change = full.getGridGeometry().derive().subgrid(subset.getGridGeometry());
            System.arraycopy(change.getSubsampling(), 0, subsampling, 0, dimension);
            System.arraycopy(change.getSubsamplingOffsets(), 0, subOffsets, 0, dimension);
        }
        /*
             * Iterate over all dimensions greater than 2. In the common case where we are reading a
             * two-dimensional image, the following loop will be executed only once. If reading a 3D
             * or 4D image, the loop is executed for all possible two-dimensional slices in the cube.
             */
        final int sd = actualReadExtent.getDimension();
        final long[] sliceMin = new long[sd];
        final long[] sliceMax = new long[sd];
        for (int i = 0; i < sd; i++) {
            sliceMin[i] = actualReadExtent.getLow(i);
            sliceMax[i] = actualReadExtent.getHigh(i);
        }
        nextSlice: for (; ; ) {
            System.arraycopy(sliceMin, BIDIMENSIONAL, sliceMax, BIDIMENSIONAL, dimension - BIDIMENSIONAL);
            final PixelIterator itr = iterator(full, sliceMin, sliceMax, subsampling, subOffsets, allowSubsampling);
            final PixelIterator itc = iterator(subset, sliceMin, sliceMax, subsampling, subOffsets, false);
            if (itr != null) {
                assertEquals(itr.getDomain().getSize(), itc.getDomain().getSize());
                final double[] expected = new double[selectedBands.length];
                double[] reference = null, actual = null;
                while (itr.next()) {
                    assertTrue(itc.next());
                    reference = itr.getPixel(reference);
                    actual = itc.getPixel(actual);
                    for (int i = 0; i < selectedBands.length; i++) {
                        expected[i] = reference[selectedBands[i]];
                    }
                    if (!Arrays.equals(expected, actual)) {
                        failuresCount++;
                        if (!failOnMismatch)
                            break;
                        final Point pr = itr.getPosition();
                        final Point pc = itc.getPosition();
                        final StringBuilder message = new StringBuilder(100).append("Mismatch at position (").append(pr.x).append(", ").append(pr.y).append(") in full image and (").append(pc.x).append(", ").append(pc.y).append(") in tested sub-image");
                        findMatchPosition(itr, pr, selectedBands, actual, message);
                        assertArrayEquals(message.toString(), expected, actual, STRICT);
                    /*
                             * POSSIBLE CAUSES FOR TEST FAILURE (known issues):
                             *
                             *   - If the `GridGeometry` has no `gridToCRS` transform, then `GridDerivation` manages
                             *     to save the scales (subsampling factors) anyway but the translations (subsampling
                             *     offsets) are lost. It causes an image shift if the offsets were not zero. Because
                             *     `gridToCRS` should never be null with spatial data, we do not complexify the code
                             *     for what may be a non-issue.
                             */
                    }
                }
                assertFalse(itc.next());
            } else {
                // Unable to create a reference image. Just check that no exception is thrown.
                double[] actual = null;
                while (itc.next()) {
                    actual = itc.getPixel(actual);
                }
            }
            /*
                 * Move to the next two-dimensional slice and read again.
                 * We stop the loop after we have read all 2D slices.
                 */
            for (int d = dimension; --d >= BIDIMENSIONAL; ) {
                if (sliceMin[d]++ <= actualReadExtent.getHigh(d))
                    continue nextSlice;
                sliceMin[d] = actualReadExtent.getLow(d);
            }
            break;
        }
        if (durations != null) {
            durations.accept((System.nanoTime() - startTime) / (double) StandardDateFormat.NANOS_PER_MILLISECOND);
        }
    }
    /*
         * Show statistics only if the test are executed with the `VERBOSE` flag set,
         * or if this `CoverageReadConsistency` is used for benchmark.
         */
    if (durations != null) {
        if (statistics == null) {
            statistics = new ArrayList<>();
        }
        statistics.add(durations);
        final int totalCount = durations.count();
        out.println("Number of failures: " + failuresCount + " / " + totalCount + " (" + (failuresCount / (totalCount / 100f)) + "%)");
    }
}
Also used : GridGeometry(org.apache.sis.coverage.grid.GridGeometry) GridExtent(org.apache.sis.coverage.grid.GridExtent) PixelIterator(org.apache.sis.image.PixelIterator) Point(java.awt.Point) Statistics(org.apache.sis.math.Statistics) Point(java.awt.Point) GridDerivation(org.apache.sis.coverage.grid.GridDerivation) GridCoverage(org.apache.sis.coverage.grid.GridCoverage)

Example 2 with GridDerivation

use of org.apache.sis.coverage.grid.GridDerivation in project sis by apache.

the class RasterResource method read.

/**
 * Loads a subset of the grid coverage represented by this resource.
 *
 * @param  domain  desired grid extent and resolution, or {@code null} for reading the whole domain.
 * @param  range   0-based indices of sample dimensions to read, or {@code null} or an empty sequence for reading them all.
 * @return the grid coverage for the specified domain and range.
 * @throws DataStoreException if an error occurred while reading the grid coverage data.
 */
@Override
public GridCoverage read(final GridGeometry domain, final int... range) throws DataStoreException {
    final long startTime = System.nanoTime();
    final RangeArgument rangeIndices = validateRangeArgument(ranges.length, range);
    final Variable first = data[bandDimension >= 0 ? 0 : rangeIndices.getFirstSpecified()];
    final DataType dataType = first.getDataType();
    if (bandDimension < 0) {
        for (int i = 0; i < rangeIndices.getNumBands(); i++) {
            final Variable variable = data[rangeIndices.getSourceIndex(i)];
            if (!dataType.equals(variable.getDataType())) {
                throw new DataStoreContentException(Resources.forLocale(getLocale()).getString(Resources.Keys.MismatchedVariableType_3, getFilename(), first.getName(), variable.getName()));
            }
        }
    }
    /*
         * At this point the arguments and the state of this resource have been validated.
         * There is three ways to read the data, determined by `bandDimension` value:
         *
         *   • (bandDimension < 0): one variable per band (usual case).
         *   • (bandDimension = 0): one variable containing all bands, with bands in the first dimension.
         *   • (bandDimension > 0): one variable containing all bands, with bands in the last dimension.
         */
    final GridGeometry targetDomain;
    final DataBuffer imageBuffer;
    final SampleDimension[] bands = new SampleDimension[rangeIndices.getNumBands()];
    // By default, all bands start at index 0.
    int[] bandOffsets = null;
    try {
        final GridDerivation targetGeometry = gridGeometry.derive().rounding(GridRoundingMode.ENCLOSING).subgrid((domain != null) ? domain : gridGeometry);
        // Pixel indices of data to read.
        GridExtent areaOfInterest = targetGeometry.getIntersection();
        // Slice to read or subsampling to apply.
        int[] subsampling = targetGeometry.getSubsampling();
        // By default, one variable per band.
        int numBuffers = bands.length;
        // Adjust user-specified domain to data geometry.
        targetDomain = targetGeometry.build();
        if (bandDimension >= 0) {
            areaOfInterest = rangeIndices.insertBandDimension(areaOfInterest, bandDimension);
            subsampling = rangeIndices.insertSubsampling(subsampling, bandDimension);
            if (bandDimension == 0) {
                // Will be set to non-zero values later.
                bandOffsets = new int[numBuffers];
            }
            // One variable for all bands.
            numBuffers = 1;
        }
        /*
             * Iterate over netCDF variables in the order they appear in the file, not in the order requested
             * by the `range` argument.  The intent is to perform sequential I/O as much as possible, without
             * seeking backward. In the (uncommon) case where bands are one of the variable dimension instead
             * than different variables, the reading of the whole variable occurs during the first iteration.
             */
        Buffer[] sampleValues = new Buffer[numBuffers];
        synchronized (lock) {
            for (int i = 0; i < bands.length; i++) {
                // In strictly increasing order.
                int indexInResource = rangeIndices.getSourceIndex(i);
                int indexInRaster = rangeIndices.getTargetIndex(i);
                Variable variable = getVariable(indexInResource);
                SampleDimension b = ranges[indexInResource];
                if (b == null) {
                    ranges[indexInResource] = b = createSampleDimension(rangeIndices.builder(), variable, i);
                }
                bands[indexInRaster] = b;
                if (bandOffsets != null) {
                    bandOffsets[indexInRaster] = i;
                    // Pixels interleaved in one bank: sampleValues.length = 1.
                    indexInRaster = 0;
                }
                if (i < numBuffers)
                    try {
                        // Optional.orElseThrow() below should never fail since Variable.read(…) wraps primitive array.
                        sampleValues[indexInRaster] = variable.read(areaOfInterest, subsampling).buffer().get();
                    } catch (ArithmeticException e) {
                        throw variable.canNotComputePosition(e);
                    }
            }
        }
        /*
             * The following block is executed only if all bands are in a single variable, and the bands dimension is
             * the last one (in "natural" order). In such case, the sample model to construct is a BandedSampleModel.
             * Contrarily to PixelInterleavedSampleModel (the case when the band dimension is first), banded sample
             * model force us to split the buffer in a buffer for each band.
             */
        if (bandDimension > 0) {
            // Really > 0, not >= 0.
            final int stride = Math.toIntExact(data[0].getBandStride());
            Buffer values = sampleValues[0].limit(stride);
            sampleValues = new Buffer[bands.length];
            for (int i = 0; i < sampleValues.length; i++) {
                if (i != 0) {
                    values = JDK9.duplicate(values);
                    final int p = values.limit();
                    values.position(p).limit(Math.addExact(p, stride));
                }
                sampleValues[i] = values;
            }
        }
        /*
             * Convert NIO Buffer into Java2D DataBuffer. May throw various RuntimeException.
             */
        imageBuffer = RasterFactory.wrap(dataType.rasterDataType, sampleValues);
    } catch (IOException | RuntimeException e) {
        throw canNotRead(getFilename(), domain, e);
    }
    /*
         * At this point the I/O operation is completed and sample values have been stored in a NIO buffer.
         * Provide to `Raster` all information needed for building a `RenderedImage` when requested.
         */
    if (imageBuffer == null) {
        throw new DataStoreContentException(Errors.getResources(getLocale()).getString(Errors.Keys.UnsupportedType_1, dataType.name()));
    }
    final Variable main = data[visibleBand];
    final Raster raster = new Raster(targetDomain, UnmodifiableArrayList.wrap(bands), imageBuffer, String.valueOf(identifier), rangeIndices.getPixelStride(), bandOffsets, visibleBand, main.decoder.convention().getColors(main));
    logReadOperation(location, targetDomain, startTime);
    return raster;
}
Also used : Buffer(java.nio.Buffer) DataBuffer(java.awt.image.DataBuffer) GridGeometry(org.apache.sis.coverage.grid.GridGeometry) GridExtent(org.apache.sis.coverage.grid.GridExtent) IOException(java.io.IOException) SampleDimension(org.apache.sis.coverage.SampleDimension) GridDerivation(org.apache.sis.coverage.grid.GridDerivation) DataStoreContentException(org.apache.sis.storage.DataStoreContentException) DataBuffer(java.awt.image.DataBuffer)

Example 3 with GridDerivation

use of org.apache.sis.coverage.grid.GridDerivation in project sis by apache.

the class CoverageSubset method clip.

/**
 * Clips the given domain to the area of interest specified by the query. If any grid geometry is null,
 * the other one is returned. The {@code domain} argument should be the domain to read as specified to
 * {@link #read(GridGeometry, int...)}, or the full {@code CoverageSubset} domain if no value were given
 * to the {@code read(…)} method.
 *
 * @param  domain    the domain requested in a read operation, or {@code null}.
 * @param  rounding  whether to clip to nearest box or an enclosing box.
 * @param  clipping  whether to clip the resulting extent to the specified {@code domain} extent.
 * @return intersection of the given grid geometry with the query domain.
 * @throws DataStoreException if the intersection can not be computed.
 */
private GridGeometry clip(final GridGeometry domain, final GridRoundingMode rounding, final GridClippingMode clipping) throws DataStoreException {
    final GridGeometry areaOfInterest = query.getSelection();
    if (domain == null)
        return areaOfInterest;
    if (areaOfInterest == null)
        return domain;
    try {
        final GridDerivation derivation = domain.derive().rounding(rounding).clipping(clipping);
        final int expansion = query.getSourceDomainExpansion();
        if (expansion != 0) {
            final int[] margins = new int[domain.getDimension()];
            Arrays.fill(margins, expansion);
            derivation.margin(margins);
        }
        return derivation.subgrid(areaOfInterest).build();
    } catch (IllegalArgumentException | IllegalStateException e) {
        final String msg = Resources.forLocale(getLocale()).getString(Resources.Keys.CanNotIntersectDataWithQuery_1, getSourceName());
        final Throwable cause = e.getCause();
        if (cause instanceof FactoryException || cause instanceof TransformException) {
            throw new DataStoreReferencingException(msg, cause);
        } else if (e instanceof DisjointExtentException) {
            throw new NoSuchDataException(msg, e);
        } else {
            throw new DataStoreException(msg, e);
        }
    }
}
Also used : GridGeometry(org.apache.sis.coverage.grid.GridGeometry) DisjointExtentException(org.apache.sis.coverage.grid.DisjointExtentException) FactoryException(org.opengis.util.FactoryException) TransformException(org.opengis.referencing.operation.TransformException) GridDerivation(org.apache.sis.coverage.grid.GridDerivation)

Aggregations

GridDerivation (org.apache.sis.coverage.grid.GridDerivation)3 GridGeometry (org.apache.sis.coverage.grid.GridGeometry)3 GridExtent (org.apache.sis.coverage.grid.GridExtent)2 Point (java.awt.Point)1 DataBuffer (java.awt.image.DataBuffer)1 IOException (java.io.IOException)1 Buffer (java.nio.Buffer)1 SampleDimension (org.apache.sis.coverage.SampleDimension)1 DisjointExtentException (org.apache.sis.coverage.grid.DisjointExtentException)1 GridCoverage (org.apache.sis.coverage.grid.GridCoverage)1 PixelIterator (org.apache.sis.image.PixelIterator)1 Statistics (org.apache.sis.math.Statistics)1 DataStoreContentException (org.apache.sis.storage.DataStoreContentException)1 TransformException (org.opengis.referencing.operation.TransformException)1 FactoryException (org.opengis.util.FactoryException)1