Search in sources :

Example 1 with PixelOrientation

use of org.opengis.metadata.spatial.PixelOrientation in project geotoolkit by Geomatys.

the class CoverageToFeaturesProcess method convertToFeature.

/**
 * Create a Feature with a cell coordinate (x,y).
 *
 * @param type the FeatureType
 * @param x
 * @param y
 * @param coverage
 * @param resource
 * @param gridGeom
 * @return the cell Feature
 * @throws DataStoreException
 * @throws TransformException
 */
static Feature convertToFeature(FeatureType type, long x, long y, GridCoverage coverage, GridCoverageResource resource, GridGeometry gridGeom) throws DataStoreException, TransformException {
    final GeometryFactory geomFac = org.geotoolkit.geometry.jts.JTS.getFactory();
    // get the number of band contained in a cell
    final List<SampleDimension> dims = coverage.getSampleDimensions();
    final int nbBand = dims.size();
    // Define the pixel position in cells
    PixelInCell posPix = PixelInCell.CELL_CENTER;
    // rep.getPointInPixel();
    final PixelOrientation pixOr = PixelOrientation.CENTER;
    if (pixOr == PixelOrientation.CENTER) {
        posPix = PixelInCell.CELL_CENTER;
    } else if (pixOr == PixelOrientation.UPPER_LEFT) {
        posPix = PixelInCell.CELL_CORNER;
    }
    // get the MathTransform frome grid to the CRS
    final MathTransform transfo = gridGeom.getGridToCRS(posPix);
    double[] pt1 = new double[] { x, y };
    double[] pt2 = new double[2];
    // transform x,y cell coordinate with the gridToCRS MathTransform
    transfo.transform(pt1, 0, pt2, 0, 1);
    // make a Point2D with transformed coordinates in order to get cell bands
    DirectPosition2D point2d = new DirectPosition2D();
    point2d.setLocation(pt2[0], pt2[1]);
    double[] infoBand = coverage.evaluator().apply(point2d);
    final double[] resolution = gridGeom.getResolution(true);
    double gapX = resolution[0];
    double gapY = resolution[1];
    // compute the cell geometry from transform coordinates
    Coordinate[] coord;
    if (posPix == PixelInCell.CELL_CENTER) {
        coord = new Coordinate[] { new Coordinate(pt2[0] - gapX / 2, pt2[1] + gapY / 2), new Coordinate(pt2[0] + gapX / 2, pt2[1] + gapY / 2), new Coordinate(pt2[0] + gapX / 2, pt2[1] - gapY / 2), new Coordinate(pt2[0] - gapX / 2, pt2[1] - gapY / 2), new Coordinate(pt2[0] - gapX / 2, pt2[1] + gapY / 2) };
    } else {
        coord = new Coordinate[] { new Coordinate(pt2[0], pt2[1]), new Coordinate(pt2[0] + gapX, pt2[1]), new Coordinate(pt2[0] + gapX, pt2[1] - gapY), new Coordinate(pt2[0], pt2[1] - gapY), new Coordinate(pt2[0], pt2[1]) };
    }
    // create the Feature
    Feature myfeature = type.newInstance();
    myfeature.setPropertyValue(AttributeConvention.IDENTIFIER, "id-" + x + "-" + y);
    myfeature.setPropertyValue("cellgeom", geomFac.createPolygon(geomFac.createLinearRing(coord), null));
    myfeature.setPropertyValue("position", geomFac.createPoint(new Coordinate(pt2[0], pt2[1])));
    myfeature.setPropertyValue("orientation", posPix.name());
    for (int att = 0; att < nbBand; att++) {
        myfeature.setPropertyValue("band-" + att, infoBand[att]);
    }
    return myfeature;
}
Also used : PixelOrientation(org.opengis.metadata.spatial.PixelOrientation) GeometryFactory(org.locationtech.jts.geom.GeometryFactory) MathTransform(org.opengis.referencing.operation.MathTransform) SampleDimension(org.apache.sis.coverage.SampleDimension) DirectPosition2D(org.apache.sis.geometry.DirectPosition2D) Feature(org.opengis.feature.Feature) Point(org.locationtech.jts.geom.Point) PixelInCell(org.opengis.referencing.datum.PixelInCell) Coordinate(org.locationtech.jts.geom.Coordinate)

Example 2 with PixelOrientation

use of org.opengis.metadata.spatial.PixelOrientation in project geotoolkit by Geomatys.

the class AsciiGridWriter method prepareHeader.

/**
 * Fills the given {@code header} map with values extracted from the given image metadata.
 * The {@code "NCOLS"} and {@code "NROWS"} attributes are already defined when this method
 * is invoked. This method is responsible for filling the remaining attributes.
 *
 * @param  metadata The metadata.
 * @param  header The map in which to store the (<var>key</var>, <var>value</var>) pairs
 *         to be written.
 * @return The fill value, or {@code Double#NaN} if none.
 * @throws IOException If the metadata can not be prepared.
 */
private String prepareHeader(final SpatialMetadata metadata, final Map<String, String> header, final ImageWriteParam param) throws IOException {
    final MetadataHelper helper = new MetadataHelper(this);
    final Georectified spatialRp = metadata.getInstanceForType(Georectified.class);
    final RectifiedGrid domain = metadata.getInstanceForType(RectifiedGrid.class);
    final PixelOrientation ptInPixel = (spatialRp != null) ? spatialRp.getPointInPixel() : null;
    final AffineTransform gridToCRS = helper.getAffineTransform(domain, param);
    String xll = "XLLCORNER";
    String yll = "YLLCORNER";
    // reverted (i.e. the corresponding value in OffsetVectors is negative).
    if (ptInPixel != null && !ptInPixel.equals(PixelOrientation.UPPER_LEFT)) {
        if (ptInPixel.equals(PixelOrientation.CENTER)) {
            xll = "XLLCENTER";
            yll = "YLLCENTER";
        } else if (ptInPixel.equals(PixelOrientation.valueOf("UPPER"))) {
            yll = "YLLCENTER";
        } else if (ptInPixel.equals(PixelOrientation.valueOf("LEFT"))) {
            xll = "XLLCENTER";
        } else {
            throw new ImageMetadataException(Warnings.message(this, Errors.Keys.IllegalParameterValue_2, "pointInPixel", ptInPixel));
        }
    }
    header.put(xll, String.valueOf(gridToCRS.getTranslateX()));
    header.put(yll, String.valueOf(gridToCRS.getTranslateY()));
    /*
         * Use the CELLSIZE attribute if the pixels are square, or the DX, DY attibutes
         * if they are rectangular and we are allowed to use those non-standard attributes.
         */
    try {
        header.put("CELLSIZE", String.valueOf(helper.getCellSize(gridToCRS)));
    } catch (IIOException e) {
        final Dimension2D size;
        if (strictCellSize || (size = helper.getCellDimension(gridToCRS)) == null) {
            throw e;
        }
        Warnings.log(this, null, AsciiGridWriter.class, "writeHeader", e);
        header.put("DX", String.valueOf(size.getWidth()));
        header.put("DY", String.valueOf(size.getHeight()));
    }
    /*
         * Get the fill sample value, which is optional. The default defined by
         * the ASCII grid format is -9999.
         */
    String fillValue = DEFAULT_FILL;
    final List<SampleDimension> dimensions = metadata.getListForType(SampleDimension.class);
    if (!isNullOrEmpty(dimensions)) {
        final SampleDimension dim = dimensions.get(0);
        if (dim != null) {
            final double[] fillValues = dim.getFillSampleValues();
            if (fillValues != null && fillValues.length != 0) {
                final double value = fillValues[0];
                if (!Double.isNaN(value)) {
                    fillValue = CharSequences.trimFractionalPart(String.valueOf(value)).toString();
                    header.put("NODATA_VALUE", fillValue);
                }
            }
        }
    }
    return fillValue;
}
Also used : PixelOrientation(org.opengis.metadata.spatial.PixelOrientation) Dimension2D(java.awt.geom.Dimension2D) IIOException(javax.imageio.IIOException) Georectified(org.opengis.metadata.spatial.Georectified) SampleDimension(org.geotoolkit.image.io.metadata.SampleDimension) MetadataHelper(org.geotoolkit.image.io.metadata.MetadataHelper) RectifiedGrid(org.opengis.coverage.grid.RectifiedGrid) AffineTransform(java.awt.geom.AffineTransform) ImageMetadataException(org.geotoolkit.image.io.ImageMetadataException)

Example 3 with PixelOrientation

use of org.opengis.metadata.spatial.PixelOrientation in project geotoolkit by Geomatys.

the class ImageCoverageReader method getGridGeometry.

/**
 * Returns the grid geometry for the {@link GridCoverage2D} to be read at the given index.
 * The default implementation performs the following:
 * <p>
 * <ul>
 *   <li>The {@link GridExtent} is determined from the
 *       {@linkplain SpatialImageReader#getGridEnvelope(int) spatial image reader}
 *       if possible, or from the image {@linkplain ImageReader#getWidth(int) width}
 *       and {@linkplain ImageReader#getHeight(int) height} otherwise.</li>
 *   <li>The {@link CoordinateReferenceSystem} and the "<cite>grid to CRS</cite>" conversion
 *       are determined from the {@link SpatialMetadata} if any.</li>
 * </ul>
 *
 * @return The grid geometry for the {@link GridCoverage} at the specified index.
 * @throws IllegalStateException If the input source has not been set.
 * @throws IndexOutOfBoundsException If the supplied index is out of bounds.
 * @throws CoverageStoreException If an error occurs while reading the information from the input source.
 * @throws CancellationException If {@link #abort()} has been invoked in an other thread during
 *         the execution of this method.
 *
 * @see ImageReader#getWidth(int)
 * @see ImageReader#getHeight(int)
 */
public GridGeometry getGridGeometry() throws DataStoreException {
    final int index = 0;
    GridGeometry gridGeometry = getCached(gridGeometries, index);
    if (gridGeometry == null) {
        // Protect from changes.
        final ImageReader imageReader = this.imageReader;
        if (imageReader == null) {
            throw new IllegalStateException(formatErrorMessage(Errors.Keys.NoImageInput));
        }
        /*
             * Get the required information from the SpatialMetadata, if any.
             * For now we just collect them - they will be processed later.
             */
        CoordinateReferenceSystem crs = null;
        MathTransform gridToCRS = null;
        PixelOrientation pointInPixel = null;
        final int width, height;
        try {
            width = imageReader.getWidth(index);
            height = imageReader.getHeight(index);
            final SpatialMetadata metadata = getImageMetadata(imageReader, index);
            if (metadata != null) {
                crs = metadata.getInstanceForType(CoordinateReferenceSystem.class);
                if (crs == null) {
                    crs = PredefinedCRS.GRID_2D;
                }
                if (crs instanceof GridGeometry) {
                    // Some formats (e.g. NetCDF) do that.
                    gridToCRS = ((GridGeometry) crs).getGridToCRS(PixelInCell.CELL_CENTER);
                } else {
                    final RectifiedGrid grid = metadata.getInstanceForType(RectifiedGrid.class);
                    if (grid != null) {
                        gridToCRS = getMetadataHelper().getGridToCRS(grid);
                    }
                    final Georectified georect = metadata.getInstanceForType(Georectified.class);
                    if (georect != null) {
                        pointInPixel = georect.getPointInPixel();
                    }
                }
            }
        } catch (IOException e) {
            throw new CoverageStoreException(formatErrorMessage(e), e);
        }
        /*
             * If any metadata are still null, replace them by their default values. Those default
             * values are selected in order to be as neutral as possible: An ImageCRS which is not
             * convertible to GeodeticCRS, an identity "grid to CRS" conversion, a PixelOrientation
             * equivalent to performing no shift at all in the "grid to CRS" conversion.
             */
        if (crs == null) {
            crs = PredefinedCRS.GRID_2D;
        }
        final int dimension = crs.getCoordinateSystem().getDimension();
        if (gridToCRS == null) {
            gridToCRS = MathTransforms.identity(dimension);
        }
        if (pointInPixel == null) {
            pointInPixel = PixelOrientation.CENTER;
        }
        /*
             * Now build the grid geometry. Note that the grid extent spans shall be set to 1
             * for all dimensions other than X and Y, even if the original file has more data,
             * since this is a GridGeometry2D requirement.
             */
        final long[] lower = new long[dimension];
        final long[] upper = new long[dimension];
        Arrays.fill(upper, 1);
        upper[X_DIMENSION] = width;
        upper[Y_DIMENSION] = height;
        final GridExtent gridExtent = new GridExtent(null, lower, upper, false);
        final PixelInCell pixelInCell = pointInPixel == PixelOrientation.CENTER ? PixelInCell.CELL_CENTER : PixelInCell.CELL_CORNER;
        gridGeometry = new GridGeometry(gridExtent, pixelInCell, gridToCRS, crs);
        Map.Entry<Map<Integer, GridGeometry>, GridGeometry> entry = setCached(gridGeometry, gridGeometries, index);
        gridGeometries = entry.getKey();
        gridGeometry = entry.getValue();
    }
    return gridGeometry;
}
Also used : PixelOrientation(org.opengis.metadata.spatial.PixelOrientation) GridGeometry(org.apache.sis.coverage.grid.GridGeometry) GridExtent(org.apache.sis.coverage.grid.GridExtent) MathTransform(org.opengis.referencing.operation.MathTransform) SpatialMetadata(org.geotoolkit.image.io.metadata.SpatialMetadata) IOException(java.io.IOException) Georectified(org.opengis.metadata.spatial.Georectified) PixelInCell(org.opengis.referencing.datum.PixelInCell) RectifiedGrid(org.opengis.coverage.grid.RectifiedGrid) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem) ImageReader(javax.imageio.ImageReader) SpatialImageReader(org.geotoolkit.image.io.SpatialImageReader) Map(java.util.Map) HashMap(java.util.HashMap)

Example 4 with PixelOrientation

use of org.opengis.metadata.spatial.PixelOrientation in project sis by apache.

the class CRSBuilder method complete.

/**
 * Completes ISO 19115 metadata with some GeoTIFF values that are for documentation purposes.
 * Those values do not participate directly to the construction of the Coordinate Reference System objects.
 *
 * <p><b>Pre-requite:</b></p>
 * <ul>
 *   <li>{@link #build(Vector, Vector, String)} must have been invoked before this method.</li>
 *   <li>{@link ImageFileDirectory} must have filled its part of metadata before to invoke this method.</li>
 *   <li>{@link MetadataBuilder#newGridRepresentation(MetadataBuilder.GridType)} should have been invoked
 *       with the appropriate {@code GEORECTIFIED} or {@code GEOREFERENCEABLE} type.</li>
 * </ul>
 *
 * After execution, this method emits a warning for unprocessed GeoTIFF tags.
 *
 * @param  metadata  the helper class where to write metadata values.
 * @throws NumberFormatException if a numeric value was stored as a string and can not be parsed.
 */
final void complete(final MetadataBuilder metadata) {
    /*
         * ASCII reference to published documentation on the overall configuration of the GeoTIFF file.
         * Often the projected CRS name, despite GeoKeys.PCSCitation being already for that purpose.
         * Checked first because this code is unlikely to throw an exception, while other parsings may
         * interrupt this method with an exception.
         */
    final String title = getAsString(GeoKeys.Citation);
    if (title != null) {
        metadata.setGridToCRS(title);
    }
    /*
         * Whether the pixel value is thought of as filling the cell area or is considered as point measurements at
         * the vertices of the grid (not in the interior of a cell).  This is determined by the value associated to
         * GeoKeys.RasterType, which can be GeoCodes.RasterPixelIsArea or GeoCodes.RasterPixelIsPoint.
         */
    CellGeometry cg = null;
    PixelOrientation po = null;
    int code = getAsInteger(GeoKeys.RasterType);
    switch(code) {
        case GeoCodes.undefined:
            break;
        case GeoCodes.RasterPixelIsArea:
            cg = CellGeometry.AREA;
            po = PixelOrientation.CENTER;
            break;
        case GeoCodes.RasterPixelIsPoint:
            cg = CellGeometry.POINT;
            po = PixelOrientation.UPPER_LEFT;
            break;
        default:
            invalidValue(GeoKeys.RasterType, code);
            break;
    }
    metadata.setCellGeometry(cg);
    metadata.setPointInPixel(po);
    /*
         * Build a list of remaining GeoKeys.
         */
    if (!geoKeys.isEmpty()) {
        final StringJoiner joiner = new StringJoiner(", ");
        for (final short key : remainingKeys()) {
            joiner.add(GeoKeys.name(key));
        }
        warning(Resources.Keys.IgnoredGeoKeys_1, joiner.toString());
    }
}
Also used : PixelOrientation(org.opengis.metadata.spatial.PixelOrientation) CellGeometry(org.opengis.metadata.spatial.CellGeometry) StringJoiner(java.util.StringJoiner)

Example 5 with PixelOrientation

use of org.opengis.metadata.spatial.PixelOrientation in project sis by apache.

the class GridGeometryBuilder method completeMetadata.

/**
 * Completes ISO 19115 metadata with some GeoTIFF values inferred from the geotags.
 *
 * <h4>Pre-requite</h4>
 * <ul>
 *   <li>{@link #build(Reader, long, long)} must have been invoked successfully before this method.</li>
 *   <li>{@link ImageFileDirectory} must have filled its part of metadata before to invoke this method.</li>
 * </ul>
 *
 * This method invokes {@link MetadataBuilder#newGridRepresentation(MetadataBuilder.GridType)}
 * with the appropriate {@code GEORECTIFIED} or {@code GEOREFERENCEABLE} type.
 * Storage locations are:
 *
 * <ul>
 *   <li>{@code metadata/spatialRepresentationInfo/*}</li>
 *   <li>{@code metadata/identificationInfo/spatialRepresentationType}</li>
 *   <li>{@code metadata/referenceSystemInfo}</li>
 * </ul>
 *
 * @param  gridGeometry  the grid geometry computed by {@link #build(Reader, long, long)}.
 * @param  metadata      the helper class where to write metadata values.
 * @throws NumberFormatException if a numeric value was stored as a string and can not be parsed.
 */
public void completeMetadata(final GridGeometry gridGeometry, final MetadataBuilder metadata) {
    if (metadata.addSpatialRepresentation(description, gridGeometry, true)) {
        /*
             * Whether the pixel value is thought of as filling the cell area or is considered as point measurements at
             * the vertices of the grid (not in the interior of a cell).  This is determined by the value associated to
             * GeoKeys.RasterType, which can be GeoCodes.RasterPixelIsArea or GeoCodes.RasterPixelIsPoint.
             *
             * Note: the pixel orientation (UPPER_LEFT versus CENTER) should be kept consistent with the discussion in
             * GridGeometryBuilder class javadoc.
             */
        metadata.setCellGeometry(cellGeometry);
        final PixelOrientation po;
        if (CellGeometry.POINT.equals(cellGeometry)) {
            po = PixelOrientation.CENTER;
        } else if (CellGeometry.AREA.equals(cellGeometry)) {
            po = PixelOrientation.UPPER_LEFT;
        } else {
            return;
        }
        metadata.setPointInPixel(po);
    }
}
Also used : PixelOrientation(org.opengis.metadata.spatial.PixelOrientation)

Aggregations

PixelOrientation (org.opengis.metadata.spatial.PixelOrientation)8 AffineTransform (java.awt.geom.AffineTransform)3 GridDomainAccessor (org.geotoolkit.internal.image.io.GridDomainAccessor)3 RectifiedGrid (org.opengis.coverage.grid.RectifiedGrid)3 CellGeometry (org.opengis.metadata.spatial.CellGeometry)3 Georectified (org.opengis.metadata.spatial.Georectified)3 IOException (java.io.IOException)2 SpatialMetadata (org.geotoolkit.image.io.metadata.SpatialMetadata)2 CoordinateReferenceSystem (org.opengis.referencing.crs.CoordinateReferenceSystem)2 PixelInCell (org.opengis.referencing.datum.PixelInCell)2 MathTransform (org.opengis.referencing.operation.MathTransform)2 Rectangle (java.awt.Rectangle)1 Dimension2D (java.awt.geom.Dimension2D)1 Date (java.util.Date)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 StringJoiner (java.util.StringJoiner)1 IIOException (javax.imageio.IIOException)1 ImageReader (javax.imageio.ImageReader)1 SampleDimension (org.apache.sis.coverage.SampleDimension)1