use of org.opengis.metadata.spatial.DimensionNameType in project sis by apache.
the class GridExtent method validateAxisTypes.
/**
* Verifies that the given array (if non-null) contains no duplicated values, then returns a copy of that array.
* The returned copy may be shared by many {@code GridExtent} instances. Consequently it shall not be modified.
*
* @throws IllegalArgumentException if the given array contains duplicated elements.
*/
@SuppressWarnings("ReturnOfCollectionOrArrayField")
private static DimensionNameType[] validateAxisTypes(DimensionNameType[] types) throws IllegalArgumentException {
if (types == null) {
return null;
}
if (Arrays.equals(DEFAULT_TYPES, types)) {
// Common case verified before POOL synchronized lock.
return DEFAULT_TYPES;
}
DimensionNameType[] shared = POOL.get(types);
if (shared == null) {
/*
* Verify the array only if it was not found in the pool. Arrays in the pool were already validated,
* so do not need to be verified again. The check performed here is inefficient (nested loop), but it
* should be okay since the arrays are usually small (less than 5 elements) and the checks should not
* be done often (because of the pool).
*/
types = types.clone();
for (int i = 1; i < types.length; i++) {
final DimensionNameType t = types[i];
if (t != null) {
for (int j = i; --j >= 0; ) {
if (t.equals(types[j])) {
throw new IllegalArgumentException(Errors.format(Errors.Keys.DuplicatedElement_1, t));
}
}
}
}
shared = POOL.putIfAbsent(types, types);
if (shared == null) {
return types;
}
}
return shared;
}
use of org.opengis.metadata.spatial.DimensionNameType in project sis by apache.
the class CanvasExtent method suggestAxisTypes.
/**
* Suggests axis types for supplemental dimensions not managed by the {@link Canvas}.
* Those types are only a help for debugging purpose, by providing more information
* to the developers. They should not be used for any "real" work.
*
* @param crs the coordinate reference system to use for inferring axis types.
* @param displayDimension number of dimensions managed by the {@link Canvas}.
* @return suggested axis types. Never null, but contains null elements.
*
* @see Canvas#axisTypes
*/
static DimensionNameType[] suggestAxisTypes(final CoordinateReferenceSystem crs, final int displayDimension) {
if (crs != null) {
final CoordinateSystem cs = crs.getCoordinateSystem();
if (cs != null) {
// Should never be null, but we are paranoiac.
int i = cs.getDimension();
final DimensionNameType[] axisTypes = new DimensionNameType[i];
while (--i >= displayDimension) {
final AxisDirection dir = AxisDirections.absolute(cs.getAxis(i).getDirection());
if (AxisDirection.FUTURE.equals(dir)) {
axisTypes[i] = DimensionNameType.TIME;
} else if (AxisDirection.UP.equals(dir)) {
axisTypes[i] = DimensionNameType.VERTICAL;
}
}
return axisTypes;
}
}
return new DimensionNameType[displayDimension];
}
use of org.opengis.metadata.spatial.DimensionNameType in project sis by apache.
the class GridExtentCRS method build.
/**
* Builds a coordinate reference system for the given axis types. The CRS type is always engineering.
* We can not create temporal CRS because we do not know the temporal datum origin.
*
* @param gridToCRS matrix of the transform used for converting grid cell indices to envelope coordinates.
* It does not matter whether it maps pixel center or corner (translation coefficients are ignored).
* @param types the value of {@link GridExtent#types} or a default value (shall not be {@code null}).
* @param locale locale to use for axis names, or {@code null} for default.
* @return CRS for the grid, or {@code null}.
*
* @see GridExtent#typeFromAxes(CoordinateReferenceSystem, int)
*/
static EngineeringCRS build(final Matrix gridToCRS, final DimensionNameType[] types, final Locale locale) throws FactoryException {
final int tgtDim = gridToCRS.getNumRow() - 1;
final int srcDim = Math.min(gridToCRS.getNumCol() - 1, types.length);
final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[tgtDim];
final CSFactory csFactory = DefaultFactories.forBuildin(CSFactory.class);
boolean hasVertical = false;
boolean hasTime = false;
boolean hasOther = false;
for (int i = 0; i < srcDim; i++) {
final DimensionNameType type = types[i];
if (type != null) {
/*
* Try to locate the CRS dimension corresponding to grid dimension j.
* We expect a one-to-one matching; if it is not the case, return null.
* Current version does not accept scale factors, but we could revisit
* in a future version if there is a need for it.
*/
int target = -1;
double scale = 0;
for (int j = 0; j < tgtDim; j++) {
final double m = gridToCRS.getElement(j, i);
if (m != 0) {
if (target >= 0 || axes[j] != null || Math.abs(m) != 1) {
return null;
}
target = j;
scale = m;
}
}
if (target < 0) {
return null;
}
/*
* This hard-coded set of axis directions is the converse of
* GridExtent.AXIS_DIRECTIONS map.
*/
String abbreviation;
AxisDirection direction;
if (type == DimensionNameType.COLUMN || type == DimensionNameType.SAMPLE) {
abbreviation = "x";
direction = AxisDirection.COLUMN_POSITIVE;
} else if (type == DimensionNameType.ROW || type == DimensionNameType.LINE) {
abbreviation = "y";
direction = AxisDirection.ROW_POSITIVE;
} else if (type == DimensionNameType.VERTICAL) {
abbreviation = "z";
direction = AxisDirection.UP;
hasVertical = true;
} else if (type == DimensionNameType.TIME) {
abbreviation = "t";
direction = AxisDirection.FUTURE;
hasTime = true;
} else {
abbreviation = abbreviation(target);
direction = AxisDirection.OTHER;
hasOther = true;
}
/*
* Verify that no other axis has the same direction and abbreviation. If duplicated
* values are found, keep only the first occurrence in grid axis order (may not be
* the CRS axis order).
*/
for (int k = tgtDim; --k >= 0; ) {
final CoordinateSystemAxis previous = axes[k];
if (previous != null) {
if (direction.equals(AxisDirections.absolute(previous.getDirection()))) {
direction = AxisDirection.OTHER;
hasOther = true;
}
if (abbreviation.equals(previous.getAbbreviation())) {
abbreviation = abbreviation(target);
}
}
}
if (scale < 0) {
direction = AxisDirections.opposite(direction);
}
final String name = Types.toString(Types.getCodeTitle(type), locale);
axes[target] = axis(csFactory, name, abbreviation, direction);
}
}
/*
* Search for axes that have not been created in above loop.
* It happens when some axes have no associated `DimensionNameType` code.
*/
for (int j = 0; j < tgtDim; j++) {
if (axes[j] == null) {
final String name = Vocabulary.getResources(locale).getString(Vocabulary.Keys.Dimension_1, j);
final String abbreviation = abbreviation(j);
axes[j] = axis(csFactory, name, abbreviation, AxisDirection.OTHER);
}
}
/*
* Create a coordinate system of affine type if all axes seem spatial.
* If no specialized type seems to fit, use an unspecified ("abstract")
* coordinate system type in last resort.
*/
final Map<String, ?> properties = properties("Grid extent");
final CoordinateSystem cs;
if (hasOther || (tgtDim > (hasTime ? 1 : 3))) {
cs = new AbstractCS(properties, axes);
} else
switch(tgtDim) {
case 1:
{
final CoordinateSystemAxis axis = axes[0];
if (hasVertical) {
cs = csFactory.createVerticalCS(properties, axis);
} else if (hasTime) {
cs = csFactory.createTimeCS(properties, axis);
} else {
cs = csFactory.createLinearCS(properties, axis);
}
break;
}
case 2:
cs = csFactory.createAffineCS(properties, axes[0], axes[1]);
break;
case 3:
cs = csFactory.createAffineCS(properties, axes[0], axes[1], axes[2]);
break;
default:
return null;
}
return DefaultFactories.forBuildin(CRSFactory.class).createEngineeringCRS(properties(cs.getName()), CommonCRS.Engineering.GRID.datum(), cs);
}
use of org.opengis.metadata.spatial.DimensionNameType in project sis by apache.
the class GridGeometryBuilder method build.
/**
* Creates the grid geometry and collect related metadata.
* This method shall be invoked exactly once after {@link #validateMandatoryTags()}.
* After this method call (if successful), the returned value is guaranteed non-null
* and can be used as a flag for determining that the build has been completed.
*
* @param width the image width in pixels.
* @param height the image height in pixels.
* @return the grid geometry, guaranteed non-null.
* @throws FactoryException if an error occurred while creating a CRS or a transform.
*/
@SuppressWarnings("fallthrough")
public GridGeometry build(final Reader reader, final long width, final long height) throws FactoryException {
CoordinateReferenceSystem crs = null;
if (keyDirectory != null) {
final CRSBuilder helper = new CRSBuilder(reader);
try {
crs = helper.build(this);
description = helper.description;
cellGeometry = helper.cellGeometry;
} catch (NoSuchIdentifierException | ParameterNotFoundException e) {
short key = Resources.Keys.UnsupportedProjectionMethod_1;
if (e instanceof NoSuchAuthorityCodeException) {
key = Resources.Keys.UnknownCRS_1;
}
reader.store.warning(reader.resources().getString(key, reader.store.getDisplayName()), e);
} catch (IllegalArgumentException | NoSuchElementException | ClassCastException e) {
if (!helper.alreadyReported) {
canNotCreate(reader, e);
}
}
}
/*
* If the CRS is non-null, then it is either two- or three-dimensional.
* The `affine` matrix may be for a greater number of dimensions, so it
* may need to be reduced.
*/
int n = (crs != null) ? crs.getCoordinateSystem().getDimension() : 2;
final DimensionNameType[] axisTypes = new DimensionNameType[n];
final long[] high = new long[n];
switch(n) {
// Fallthrough everywhere.
default:
axisTypes[2] = DimensionNameType.VERTICAL;
case 2:
axisTypes[1] = DimensionNameType.ROW;
high[1] = height - 1;
case 1:
axisTypes[0] = DimensionNameType.COLUMN;
high[0] = width - 1;
case 0:
break;
}
final GridExtent extent = new GridExtent(axisTypes, null, high, true);
boolean pixelIsPoint = CellGeometry.POINT.equals(cellGeometry);
final MathTransformFactory factory = DefaultFactories.forBuildin(MathTransformFactory.class);
GridGeometry gridGeometry;
try {
MathTransform gridToCRS;
if (affine != null) {
gridToCRS = factory.createAffineTransform(Matrices.resizeAffine(affine, ++n, n));
} else {
pixelIsPoint = true;
gridToCRS = Localization.nonLinear(modelTiePoints);
gridToCRS = factory.createPassThroughTransform(0, gridToCRS, n - 2);
}
gridGeometry = new GridGeometry(extent, pixelIsPoint ? PixelInCell.CELL_CENTER : PixelInCell.CELL_CORNER, gridToCRS, crs);
} catch (TransformException e) {
GeneralEnvelope envelope = null;
if (crs != null) {
envelope = new GeneralEnvelope(crs);
envelope.setToNaN();
}
gridGeometry = new GridGeometry(extent, envelope, GridOrientation.HOMOTHETY);
canNotCreate(reader, e);
/*
* Note: we catch TransformExceptions because they may be caused by erroneous data in the GeoTIFF file,
* but let FactoryExceptions propagate because they are more likely to be a SIS configuration problem.
*/
}
// Not needed anymore, so let GC do its work.
keyDirectory = null;
numericParameters = null;
asciiParameters = null;
modelTiePoints = null;
affine = null;
return gridGeometry;
}
use of org.opengis.metadata.spatial.DimensionNameType in project sis by apache.
the class Grid method getExtent.
/**
* Builds the grid extent if the shape is available. The shape may not be available
* if a dimension has unlimited length. The dimension names are informative only.
*
* @param axes value of {@link #getAxes(Decoder)}. Element order does not matter for this method.
* @return the extent, or {@code null} if not available.
*/
@SuppressWarnings("fallthrough")
private GridExtent getExtent(final Axis[] axes) {
final List<Dimension> dimensions = getDimensions();
final int n = dimensions.size();
final long[] high = new long[n];
for (int i = 0; i < n; i++) {
final long length = dimensions.get(i).length();
if (length <= 0)
return null;
high[(n - 1) - i] = length;
}
final DimensionNameType[] names = new DimensionNameType[n];
switch(n) {
// Fall through
default:
names[1] = DimensionNameType.ROW;
// Fall through
case 1:
names[0] = DimensionNameType.COLUMN;
case 0:
break;
}
for (final Axis axis : axes) {
if (axis.getNumDimensions() == 1) {
final DimensionNameType name;
if (AxisDirections.isVertical(axis.direction)) {
name = DimensionNameType.VERTICAL;
} else if (AxisDirections.isTemporal(axis.direction)) {
name = DimensionNameType.TIME;
} else {
continue;
}
int dim = axis.gridDimensionIndices[0];
// Convert netCDF order to "natural" order.
dim = names.length - 1 - dim;
if (dim >= 0)
names[dim] = name;
}
}
return new GridExtent(names, null, high, false);
}
Aggregations