Search in sources :

Example 6 with GridExtent

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

the class MemoryGridResource method read.

/**
 * Returns a subset of the wrapped grid coverage. If a non-null grid geometry is specified, then
 * this method tries to return a grid coverage matching the given grid geometry on a best-effort basis.
 * In current implementation this is either a {@link org.apache.sis.coverage.grid.GridCoverage2D} or
 * the original grid coverage.
 *
 * @param  domain  desired grid extent and resolution, or {@code null} for 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.
 */
@Override
public GridCoverage read(GridGeometry domain, final int... range) {
    List<SampleDimension> bands = coverage.getSampleDimensions();
    final RangeArgument rangeIndices = validateRangeArgument(bands.size(), range);
    /*
         * The given `domain` may use arbitrary `gridToCRS` and `CRS` properties.
         * For this simple implementation we need the same `gridToCRS` and `CRS`
         * than the wrapped coverage; only domain `extent` is allowed to differ.
         * Subsampling is ignored for now because it is an expensive operation.
         * Clipping and range selection are light and do not copy any data.
         *
         * TODO: a future implementation may apply subsampling efficiently,
         *       by adjusting the pixel stride in SampleModel.
         */
    GridExtent intersection = null;
    final GridGeometry source = coverage.getGridGeometry();
    if (domain == null) {
        domain = source;
    } else {
        intersection = source.derive().rounding(GridRoundingMode.ENCLOSING).subgrid(domain).getIntersection();
        if (intersection.equals(source.getExtent())) {
            // Will request the whole image.
            intersection = null;
            domain = source;
        }
    }
    /*
         * Quick check before to invoke the potentially costly `coverage.render(…)` method.
         */
    final boolean sameBands = rangeIndices.isIdentity();
    if (sameBands && intersection == null) {
        return coverage;
    }
    /*
         * After `render(…)` execution, the (minX, minY) image coordinates are the differences between
         * the extent that we requested and the one that we got. If that differences is not zero, then
         * we need to translate the `GridExtent` in order to make it matches what we got. But before to
         * apply that translation, we adjust the grid size (because it may add another translation).
         */
    RenderedImage data = coverage.render(intersection);
    if (intersection != null) {
        final int[] sd = intersection.getSubspaceDimensions(2);
        final int dimX = sd[0];
        final int dimY = sd[1];
        final long ox = intersection.getLow(dimX);
        final long oy = intersection.getLow(dimY);
        final long[] changes = new long[Math.max(dimX, dimY) + 1];
        for (int i = changes.length; --i >= 0; ) {
            // We need only the dimensions that may change.
            changes[i] = intersection.getSize(i);
        }
        changes[dimX] = data.getWidth();
        changes[dimY] = data.getHeight();
        intersection = intersection.resize(changes);
        /*
             * Apply the translation after we resized the grid extent, because the resize operation
             * may have caused an additional translation. We cancel that translation with terms that
             * restore the (ox,oy) lower coordinates before to add the data minimum X,Y.
             */
        Arrays.fill(changes, 0);
        changes[dimX] = Math.addExact(ox - intersection.getLow(dimX), data.getMinX());
        changes[dimY] = Math.addExact(oy - intersection.getLow(dimY), data.getMinX());
        intersection = intersection.translate(changes);
        /*
             * If the result is the same intersection than the source coverage,
             * we may be able to return that coverage directly.
             */
        if (intersection.equals(source.getExtent())) {
            if (sameBands) {
                return coverage;
            }
            domain = source;
        } else {
            domain = new GridGeometry(intersection, PixelInCell.CELL_CORNER, source.getGridToCRS(PixelInCell.CELL_CORNER), source.getCoordinateReferenceSystem());
        }
    }
    if (!sameBands) {
        data = new ImageProcessor().selectBands(data, range);
        bands = UnmodifiableArrayList.wrap(rangeIndices.select(bands));
    }
    return new GridCoverageBuilder().setValues(data).setRanges(bands).setDomain(domain).build();
}
Also used : GridGeometry(org.apache.sis.coverage.grid.GridGeometry) GridExtent(org.apache.sis.coverage.grid.GridExtent) SampleDimension(org.apache.sis.coverage.SampleDimension) ImageProcessor(org.apache.sis.image.ImageProcessor) GridCoverageBuilder(org.apache.sis.coverage.grid.GridCoverageBuilder) RenderedImage(java.awt.image.RenderedImage)

Example 7 with GridExtent

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

the class CoverageReadConsistency method randomDomain.

/**
 * Creates a random domain to be used as a query on the {@link #resource} to test.
 * All arrays given to this method will have their values overwritten.
 *
 * @param  gg           value of {@link GridCoverage#getGridGeometry()} on the resource to test.
 * @param  low          pre-allocated array where to write the lower grid coordinates, inclusive.
 * @param  high         pre-allocated array where to write the upper grid coordinates, inclusive.
 * @param  subsampling  pre-allocated array where to write the subsampling.
 */
private GridGeometry randomDomain(final GridGeometry gg, final long[] low, final long[] high, final int[] subsampling) {
    final GridExtent fullExtent = gg.getExtent();
    final int dimension = fullExtent.getDimension();
    for (int d = 0; d < dimension; d++) {
        final int span = StrictMath.toIntExact(fullExtent.getSize(d));
        // Span of the sub-region - 1.
        final int rs = random.nextInt(span);
        if (allowOffsets) {
            // Note: (span - rs) > 0.
            low[d] = random.nextInt(span - rs);
        }
        high[d] = low[d] + rs;
        subsampling[d] = 1;
        if (allowSubsampling) {
            subsampling[d] += random.nextInt(StrictMath.max(rs / 16, 1));
        }
    }
    return gg.derive().subgrid(new GridExtent(null, low, high, true), subsampling).build();
}
Also used : GridExtent(org.apache.sis.coverage.grid.GridExtent) Point(java.awt.Point)

Example 8 with GridExtent

use of org.apache.sis.coverage.grid.GridExtent 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 9 with GridExtent

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

the class GridResourceMock method read.

/**
 * Returns a grid geometry wrapping a dummy image having exactly the requested size.
 * The image will always be a {@link BufferedImage} with pixel coordinates starting at (0,0).
 *
 * @param  domain  desired grid extent and resolution, or {@code null} for the whole domain.
 * @param  range   must be null, empty or a singleton containing only value 0.
 * @return the grid coverage for the specified domain.
 */
@Override
public GridCoverage read(GridGeometry domain, final int... range) {
    assertTrue(range == null || range.length == 0 || (range.length == 1 && range[0] == 0));
    if (domain == null) {
        domain = gridGeometry;
    } else {
        domain = gridGeometry.derive().subgrid(domain).build();
    }
    final GridExtent extent = domain.getExtent();
    final BufferedImage img = new BufferedImage(StrictMath.toIntExact(extent.getSize(0)), StrictMath.toIntExact(extent.getSize(1)), BufferedImage.TYPE_BYTE_BINARY);
    return new GridCoverage2D(domain, sampleDimensions, img);
}
Also used : GridExtent(org.apache.sis.coverage.grid.GridExtent) GridCoverage2D(org.apache.sis.coverage.grid.GridCoverage2D) BufferedImage(java.awt.image.BufferedImage)

Example 10 with GridExtent

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

the class GridMapping method createGridCRS.

/**
 * Creates a new grid geometry for the given extent.
 * This method should be invoked only when no existing {@link GridGeometry} can be used as template.
 */
GridGeometry createGridCRS(final Variable variable) {
    final List<Dimension> dimensions = variable.getGridDimensions();
    final long[] upper = new long[dimensions.size()];
    for (int i = 0; i < upper.length; i++) {
        // Convert CRS dimension to netCDF dimension.
        final int d = (upper.length - 1) - i;
        upper[i] = dimensions.get(d).length();
    }
    return new GridGeometry(new GridExtent(null, null, upper, false), PixelInCell.CELL_CENTER, gridToCRS, crs);
}
Also used : GridGeometry(org.apache.sis.coverage.grid.GridGeometry) GridExtent(org.apache.sis.coverage.grid.GridExtent)

Aggregations

GridExtent (org.apache.sis.coverage.grid.GridExtent)22 GridGeometry (org.apache.sis.coverage.grid.GridGeometry)10 CoordinateReferenceSystem (org.opengis.referencing.crs.CoordinateReferenceSystem)6 Point (java.awt.Point)4 RenderedImage (java.awt.image.RenderedImage)3 IOException (java.io.IOException)3 SampleDimension (org.apache.sis.coverage.SampleDimension)3 GridCoverage (org.apache.sis.coverage.grid.GridCoverage)3 TransformException (org.opengis.referencing.operation.TransformException)3 Rectangle (java.awt.Rectangle)2 BufferedImage (java.awt.image.BufferedImage)2 GridCoverage2D (org.apache.sis.coverage.grid.GridCoverage2D)2 GridDerivation (org.apache.sis.coverage.grid.GridDerivation)2 RenderException (org.apache.sis.portrayal.RenderException)2 DimensionNameType (org.opengis.metadata.spatial.DimensionNameType)2 CoordinateSystem (org.opengis.referencing.cs.CoordinateSystem)2 MathTransform (org.opengis.referencing.operation.MathTransform)2 AffineTransform (java.awt.geom.AffineTransform)1 NoninvertibleTransformException (java.awt.geom.NoninvertibleTransformException)1 Rectangle2D (java.awt.geom.Rectangle2D)1