Search in sources :

Example 11 with SampleDimension

use of org.apache.sis.coverage.SampleDimension in project sis by apache.

the class MetadataBuilder method mergeMetadata.

/**
 * Merge the given metadata into the metadata created by this builder.
 * The given source should be an instance of {@link Metadata},
 * but some types of metadata components are accepted as well.
 *
 * <p>This method should be invoked last, just before the call to {@link #build(boolean)}.
 * Any identification information, responsible party, extent, coverage description, <i>etc.</i>
 * added after this method call will be stored in new metadata object (not merged).</p>
 *
 * @param  source  the source metadata to merge. Will never be modified.
 * @param  locale  the locale to use for error message in exceptions, or {@code null} for the default locale.
 * @return {@code true} if the given source has been merged,
 *         or {@code false} if its type is not managed by this builder.
 * @throws RuntimeException if the merge failed (may be {@link IllegalArgumentException},
 *         {@link ClassCastException}, {@link org.apache.sis.metadata.InvalidMetadataException}…)
 *
 * @see Merger
 */
public boolean mergeMetadata(final Object source, final Locale locale) {
    flush();
    final ModifiableMetadata target;
    if (source instanceof Metadata)
        target = metadata();
    else if (source instanceof DataIdentification)
        target = identification();
    else if (source instanceof Citation)
        target = citation();
    else if (source instanceof Series)
        target = series();
    else if (source instanceof DefaultResponsibleParty)
        target = responsibility();
    else if (source instanceof AbstractParty)
        target = party();
    else if (source instanceof LegalConstraints)
        target = constraints();
    else if (source instanceof Extent)
        target = extent();
    else if (source instanceof AcquisitionInformation)
        target = acquisition();
    else if (source instanceof Platform)
        target = platform();
    else if (source instanceof FeatureCatalogueDescription)
        target = featureDescription();
    else if (source instanceof CoverageDescription)
        target = coverageDescription();
    else if (source instanceof DefaultAttributeGroup)
        target = attributeGroup();
    else if (source instanceof SampleDimension)
        target = sampleDimension();
    else if (source instanceof GridSpatialRepresentation)
        target = gridRepresentation();
    else if (source instanceof GCPCollection)
        target = groundControlPoints();
    else if (source instanceof Distribution)
        target = distribution();
    else if (source instanceof Format)
        target = format();
    else if (source instanceof Lineage)
        target = lineage();
    else if (source instanceof ProcessStep)
        target = processStep();
    else if (source instanceof Processing)
        target = processing();
    else
        return false;
    final Merger merger = new Merger(locale);
    merger.copy(source, target);
    return true;
}
Also used : GridExtent(org.apache.sis.coverage.grid.GridExtent) ModifiableMetadata(org.apache.sis.metadata.ModifiableMetadata) SampleDimension(org.apache.sis.coverage.SampleDimension) ModifiableMetadata(org.apache.sis.metadata.ModifiableMetadata) Merger(org.apache.sis.internal.metadata.Merger)

Example 12 with SampleDimension

use of org.apache.sis.coverage.SampleDimension 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 13 with SampleDimension

use of org.apache.sis.coverage.SampleDimension in project sis by apache.

the class RasterResource method getSampleDimensions.

/**
 * Returns the ranges of sample values together with the conversion from samples to real values.
 *
 * @return ranges of sample values together with their mapping to "real values".
 * @throws DataStoreException if an error occurred while reading definitions from the underlying data store.
 */
@Override
@SuppressWarnings("ReturnOfCollectionOrArrayField")
public List<SampleDimension> getSampleDimensions() throws DataStoreException {
    SampleDimension.Builder builder = null;
    try {
        synchronized (lock) {
            for (int i = 0; i < ranges.length; i++) {
                if (ranges[i] == null) {
                    if (builder == null) {
                        builder = new SampleDimension.Builder();
                    }
                    ranges[i] = createSampleDimension(builder, getVariable(i), i);
                    builder.clear();
                }
            }
        }
    } catch (RuntimeException e) {
        throw new DataStoreContentException(e);
    }
    return UnmodifiableArrayList.wrap(ranges);
}
Also used : DataStoreContentException(org.apache.sis.storage.DataStoreContentException) SampleDimension(org.apache.sis.coverage.SampleDimension)

Example 14 with SampleDimension

use of org.apache.sis.coverage.SampleDimension 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 15 with SampleDimension

use of org.apache.sis.coverage.SampleDimension in project sis by apache.

the class BandRangeTable method getStringValue.

/**
 * Invoked when the table needs to render a textual cell in the sample dimension table.
 */
private static ObservableValue<String> getStringValue(final CellDataFeatures<SampleDimension, String> cell) {
    final Optional<?> text;
    final SampleDimension sd = cell.getValue();
    switch(cell.getTableColumn().getId()) {
        case NAME:
            text = Optional.ofNullable(sd.getName());
            break;
        case UNITS:
            text = sd.getUnits();
            break;
        // Should not happen.
        default:
            throw new AssertionError();
    }
    return text.map(Object::toString).map(ReadOnlyObjectWrapper::new).orElse(null);
}
Also used : SampleDimension(org.apache.sis.coverage.SampleDimension)

Aggregations

SampleDimension (org.apache.sis.coverage.SampleDimension)26 GridGeometry (org.apache.sis.coverage.grid.GridGeometry)5 Category (org.apache.sis.coverage.Category)4 GridExtent (org.apache.sis.coverage.grid.GridExtent)4 MathTransform1D (org.opengis.referencing.operation.MathTransform1D)4 RenderedImage (java.awt.image.RenderedImage)3 Test (org.junit.Test)3 IndexColorModel (java.awt.image.IndexColorModel)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 DoubleUnaryOperator (java.util.function.DoubleUnaryOperator)2 MeasurementRange (org.apache.sis.measure.MeasurementRange)2 NumberRange (org.apache.sis.measure.NumberRange)2 DataStoreContentException (org.apache.sis.storage.DataStoreContentException)2 CoordinateReferenceSystem (org.opengis.referencing.crs.CoordinateReferenceSystem)2 TransformException (org.opengis.referencing.operation.TransformException)2 Color (java.awt.Color)1 Dimension (java.awt.Dimension)1 Shape (java.awt.Shape)1 BufferedImage (java.awt.image.BufferedImage)1