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;
}
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;
}
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;
}
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());
}
}
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);
}
}
Aggregations