use of org.opengis.util.FactoryException in project sis by apache.
the class MathTransformContext method getMatrix.
/**
* Returns the normalization or denormalization matrix.
*/
@Override
@SuppressWarnings("fallthrough")
public Matrix getMatrix(final MatrixRole role) throws FactoryException {
final CoordinateSystem cs;
boolean inverse = false;
double rotation;
switch(role) {
default:
throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "role", role));
// Fall through
case INVERSE_NORMALIZATION:
inverse = true;
case NORMALIZATION:
rotation = sourceMeridian;
cs = getSourceCS();
break;
// Fall through
case INVERSE_DENORMALIZATION:
inverse = true;
case DENORMALIZATION:
inverse = !inverse;
rotation = targetMeridian;
cs = getTargetCS();
break;
}
Matrix matrix = super.getMatrix(role);
if (rotation != 0) {
if (inverse)
rotation = -rotation;
MatrixSIS cm = MatrixSIS.castOrCopy(matrix);
if (cs instanceof CartesianCS) {
rotation = Math.toRadians(rotation);
final Matrix4 rot = new Matrix4();
rot.m00 = rot.m11 = Math.cos(rotation);
rot.m01 = -(rot.m10 = Math.sin(rotation));
if (inverse) {
// Apply the rotation after denormalization.
matrix = Matrices.multiply(rot, cm);
} else {
// Apply the rotation before normalization.
matrix = cm.multiply(rot);
}
} else if (cs == null || cs instanceof EllipsoidalCS || cs instanceof SphericalCS) {
final Double value = rotation;
if (inverse) {
// Longitude is the first axis in normalized CS.
cm.convertBefore(0, null, value);
} else {
cm.convertAfter(0, null, value);
}
matrix = cm;
} else {
throw new FactoryException(Errors.format(Errors.Keys.UnsupportedCoordinateSystem_1, cs.getName()));
}
}
return matrix;
}
use of org.opengis.util.FactoryException in project sis by apache.
the class LocalizationGridBuilder method create.
/**
* Creates a transform from the source points to the target points.
* This method assumes that source points are precise and all uncertainty is in the target points.
* If this transform is close enough to an affine transform, then an instance of {@link LinearTransform} is returned.
*
* @param factory the factory to use for creating the transform, or {@code null} for the default factory.
* The {@link MathTransformFactory#createAffineTransform(Matrix)} method of that factory
* shall return {@link LinearTransform} instances.
* @return the transform from source to target points.
* @throws FactoryException if the transform can not be created,
* for example because the target points have not be specified.
*/
@Override
public MathTransform create(final MathTransformFactory factory) throws FactoryException {
final LinearTransform gridToCoord = linear.create(factory);
/*
* Make a first check about whether the result of above LinearTransformBuilder.create() call
* can be considered a good fit. If true, then we may return the linear transform directly.
*/
boolean isExact = true;
boolean isLinear = true;
for (final double c : linear.correlation()) {
isExact &= (c == 1);
if (c < 0.9999) {
// Empirical threshold (may need to be revisited).
isLinear = false;
break;
}
}
if (isExact) {
return MathTransforms.concatenate(sourceToGrid, gridToCoord);
}
final int width = linear.gridSize(0);
final int height = linear.gridSize(1);
final int tgtDim = gridToCoord.getTargetDimensions();
final double[] residual = new double[tgtDim * linear.gridLength];
final double[] point = new double[tgtDim + 1];
double gridPrecision = precision;
try {
/*
* If the user specified a precision, we need to convert it from source units to grid units.
* We convert each dimension separately, then retain the largest magnitude of vector results.
*/
if (gridPrecision > 0 && !sourceToGrid.isIdentity()) {
final double[] vector = new double[sourceToGrid.getSourceDimensions()];
final double[] offset = new double[sourceToGrid.getTargetDimensions()];
double converted = 0;
for (int i = 0; i < vector.length; i++) {
vector[i] = precision;
sourceToGrid.deltaTransform(vector, 0, offset, 0, 1);
final double length = MathFunctions.magnitude(offset);
if (length > converted)
converted = length;
vector[i] = 0;
}
gridPrecision = converted;
}
/*
* Compute the residuals, i.e. the differences between the coordinates that we get by a linear
* transformation and the coordinates that we want to get. If at least one residual is greater
* than the desired precision, then the returned MathTransform will need to apply corrections
* after linear transforms. Those corrections will be done by InterpolatedTransform.
*/
final MatrixSIS coordToGrid = MatrixSIS.castOrCopy(gridToCoord.inverse().getMatrix());
final DirectPosition2D src = new DirectPosition2D();
point[tgtDim] = 1;
for (int k = 0, y = 0; y < height; y++) {
src.y = y;
tmp[1] = y;
for (int x = 0; x < width; x++) {
src.x = x;
tmp[0] = x;
// Expected position.
linear.getControlPoint2D(tmp, point);
// As grid coordinate.
double[] grid = coordToGrid.multiply(point);
isLinear &= (residual[k++] = grid[0] - x) <= gridPrecision;
isLinear &= (residual[k++] = grid[1] - y) <= gridPrecision;
}
}
} catch (TransformException e) {
// Should never happen.
throw new FactoryException(e);
}
if (isLinear) {
return MathTransforms.concatenate(sourceToGrid, gridToCoord);
}
return InterpolatedTransform.createGeodeticTransformation(nonNull(factory), new ResidualGrid(sourceToGrid, gridToCoord, width, height, tgtDim, residual, (gridPrecision > 0) ? gridPrecision : DEFAULT_PRECISION));
}
use of org.opengis.util.FactoryException in project sis by apache.
the class Proj4Factory method createCRS.
/**
* Creates a coordinate reference system from the given {@literal Proj.4} wrapper.
* The given {@code pj} will be stored as the CRS identifier.
*
* @param pj the Proj.4 object to wrap.
* @param withHeight whether to include a height axis.
* @throws IllegalArgumentException if a Proj.4 parameter value can not be parsed or assigned.
* @throws ParserException if a unit symbol can not be parsed.
*/
private CoordinateReferenceSystem createCRS(final PJ pj, final boolean withHeight) throws FactoryException {
final PJ.Type type = pj.getType();
final boolean geographic = PJ.Type.GEOGRAPHIC.equals(type);
final boolean geocentric = PJ.Type.GEOCENTRIC.equals(type);
final Proj4Parser parser = new Proj4Parser(pj.getCode());
final String dir = parser.value("axis", "enu");
final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[geocentric | withHeight ? dir.length() : 2];
for (int i = 0; i < axes.length; i++) {
final char d = Character.toLowerCase(dir.charAt(i));
char abbreviation = Character.toUpperCase(d);
boolean vertical = false;
final AxisDirection c;
final String name;
if (geocentric)
switch(d) {
case 'e':
c = AxisDirection.GEOCENTRIC_X;
name = "Geocentric X";
break;
case 'n':
c = AxisDirection.GEOCENTRIC_Y;
name = "Geocentric Y";
break;
case 'u':
c = AxisDirection.GEOCENTRIC_Z;
name = "Geocentric Z";
break;
default:
c = AxisDirection.OTHER;
name = "Unknown";
break;
}
else
switch(d) {
case 'e':
c = AxisDirection.EAST;
name = geographic ? "Geodetic longitude" : "Easting";
break;
case 'w':
c = AxisDirection.WEST;
name = geographic ? "Geodetic longitude" : "Westing";
break;
case 'n':
c = AxisDirection.NORTH;
name = geographic ? "Geodetic latitude" : "Northing";
break;
case 's':
c = AxisDirection.SOUTH;
name = geographic ? "Geodetic latitude" : "Southing";
break;
case 'u':
c = AxisDirection.UP;
name = "Height";
vertical = true;
abbreviation = 'h';
break;
case 'd':
c = AxisDirection.DOWN;
name = "Depth";
vertical = true;
break;
default:
c = AxisDirection.OTHER;
name = "Unknown";
break;
}
if (geographic && AxisDirections.isCardinal(c)) {
abbreviation = (d == 'e' || d == 'w') ? 'λ' : 'φ';
}
final Unit<?> unit = (vertical || !geographic) ? parser.unit(vertical) : Units.DEGREE;
axes[i] = csFactory.createCoordinateSystemAxis(identifier(name), String.valueOf(abbreviation).intern(), c, unit);
}
/*
* At this point we got the coordinate system axes. Now create the CRS. The given Proj.4 object
* will be stored as the CRS identifier for allowing OperationFactory to get it back before to
* attempt to create a new one for a given CRS.
*/
final Map<String, Object> csName = identifier(UNNAMED);
final Map<String, Object> name = new HashMap<>(identifier(parser.name(type == PJ.Type.PROJECTED)));
name.put(CoordinateReferenceSystem.IDENTIFIERS_KEY, pj);
switch(type) {
case GEOGRAPHIC:
{
return crsFactory.createGeographicCRS(name, createDatum(pj, parser), withHeight ? csFactory.createEllipsoidalCS(csName, axes[0], axes[1], axes[2]) : csFactory.createEllipsoidalCS(csName, axes[0], axes[1]));
}
case GEOCENTRIC:
{
return crsFactory.createGeocentricCRS(name, createDatum(pj, parser), csFactory.createCartesianCS(csName, axes[0], axes[1], axes[2]));
}
case PROJECTED:
{
final PJ base = unique(new PJ(pj));
final CoordinateReferenceSystem baseCRS = createCRS(base, withHeight);
final Transform tr = new Transform(pj, withHeight, base, withHeight);
/*
* Try to convert the Proj.4 parameters into OGC parameters in order to have a less opaque structure.
* Failure to perform this conversion will not cause a failure to create the ProjectedCRS. After all,
* maybe the user invokes this method for using a map projection not yet supported by Apache SIS.
* Instead, fallback on the more opaque Transform.METHOD description. Apache SIS will not be able to
* perform analysis on those parameters, but it will not prevent the Proj.4 transformation to work.
*/
OperationMethod method;
ParameterValueGroup parameters;
try {
method = parser.method(opFactory());
parameters = parser.parameters();
} catch (IllegalArgumentException | FactoryException e) {
Logging.recoverableException(Logging.getLogger(Modules.GDAL), Proj4Factory.class, "createProjectedCRS", e);
method = Transform.METHOD;
// Will let Apache SIS infers the parameters from the Transform instance.
parameters = null;
}
final Conversion fromBase = new DefaultConversion(name, method, tr, parameters);
return crsFactory.createProjectedCRS(name, (GeographicCRS) baseCRS, fromBase, withHeight ? csFactory.createCartesianCS(csName, axes[0], axes[1], axes[2]) : csFactory.createCartesianCS(csName, axes[0], axes[1]));
}
default:
{
throw new FactoryException(Errors.getResources(defaultProperties).getString(Errors.Keys.UnknownEnumValue_2, type, PJ.Type.class));
}
}
}
use of org.opengis.util.FactoryException in project sis by apache.
the class MTFactory method createFromWKT.
/**
* Parses the given Well Known Text (version 1) into a math transform.
*/
@Override
public synchronized MathTransform createFromWKT(final String wkt) throws FactoryException {
ArgumentChecks.ensureNonEmpty("wkt", wkt);
if (parser == null) {
parser = new WKTFormat(null, null);
parser.setFactory(CRSAuthorityFactory.class, this);
parser.setFactory(MathTransformFactory.class, this);
parser.setFactory(CoordinateOperationFactory.class, this);
}
try {
return (MathTransform) parser.parseObject(wkt);
} catch (ParseException | ClassCastException e) {
throw new FactoryException(e);
}
}
use of org.opengis.util.FactoryException in project sis by apache.
the class GeoTiffStore method getMetadata.
/**
* Returns information about the dataset as a whole. The returned metadata object can contain information
* such as the spatiotemporal extent of the dataset, contact information about the creator or distributor,
* data quality, usage constraints and more.
*
* @return information about the dataset.
* @throws DataStoreException if an error occurred while reading the data.
*/
@Override
public synchronized Metadata getMetadata() throws DataStoreException {
if (metadata == null) {
final Reader reader = reader();
final MetadataBuilder builder = reader.metadata;
try {
builder.setFormat(Constants.GEOTIFF);
} catch (MetadataStoreException e) {
warning(null, e);
}
builder.addEncoding(encoding, MetadataBuilder.Scope.METADATA);
builder.addResourceScope(ScopeCode.valueOf("COVERAGE"), null);
final Locale locale = getLocale();
int n = 0;
try {
ImageFileDirectory dir;
while ((dir = reader.getImageFileDirectory(n++)) != null) {
dir.completeMetadata(builder, locale);
}
} catch (IOException e) {
throw new DataStoreException(errors().getString(Errors.Keys.CanNotRead_1, reader.input.filename), e);
} catch (FactoryException | ArithmeticException e) {
throw new DataStoreContentException(getLocale(), Constants.GEOTIFF, reader.input.filename, null).initCause(e);
}
/*
* Add the filename as an identifier only if the input was something convertible to URI (URL, File or Path),
* otherwise reader.input.filename may not be useful; it may be just the InputStream classname. If the TIFF
* file did not specified any ImageDescription tag, then we will had the filename as a title instead than an
* identifier because the title is mandatory in ISO 19115 metadata.
*/
if (location != null) {
builder.addTitleOrIdentifier(IOUtilities.filenameWithoutExtension(reader.input.filename), MetadataBuilder.Scope.ALL);
}
metadata = builder.build(true);
}
return metadata;
}
Aggregations