use of org.opengis.util.FactoryException in project sis by apache.
the class GeodeticObjectFactory method createFromWKT.
/**
* Creates a Coordinate Reference System object from a <cite>Well Known Text</cite> (WKT).
* This method understands both version 1 (a.k.a. OGC 01-009) and version 2 (a.k.a. ISO 19162)
* of the WKT format.
*
* <div class="note"><b>Example:</b> below is a slightly simplified WKT 2 string for a Mercator projection.
* For making this example smaller, some optional {@code UNIT[…]} and {@code ORDER[…]} elements have been omitted.
*
* {@preformat wkt
* ProjectedCRS["SIRGAS 2000 / Brazil Mercator",
* BaseGeodCRS["SIRGAS 2000",
* Datum["Sistema de Referencia Geocentrico para las Americas 2000",
* Ellipsoid["GRS 1980", 6378137, 298.257222101]]],
* Conversion["Petrobras Mercator",
* Method["Mercator (variant B)", Id["EPSG",9805]],
* Parameter["Latitude of 1st standard parallel", -2],
* Parameter["Longitude of natural origin", -43],
* Parameter["False easting", 5000000],
* Parameter["False northing", 10000000]],
* CS[cartesian,2],
* Axis["easting (E)", east],
* Axis["northing (N)", north],
* LengthUnit["metre", 1],
* Id["EPSG",5641]]
* }
* </div>
*
* If the given text contains non-fatal anomalies
* (unknown or unsupported WKT elements, inconsistent unit definitions, unparsable axis abbreviations, <i>etc.</i>),
* warnings may be reported in a {@linkplain java.util.logging.Logger logger} named {@code "org.apache.sis.io.wkt"}.
* However this parser does not verify if the overall parsed object matches the EPSG (or other authority) definition,
* since this geodetic object factory is not an {@linkplain GeodeticAuthorityFactory authority factory}.
* For such verification, see the {@link org.apache.sis.referencing.CRS#fromWKT(String)} convenience method.
*
* <div class="section">Usage and performance considerations</div>
* The default implementation uses a shared instance of {@link org.apache.sis.io.wkt.WKTFormat}
* with the addition of thread-safety. This is okay for occasional use,
* but is sub-optimal if this method is extensively used in a multi-thread environment.
* Furthermore this method offers no control on the WKT {@linkplain org.apache.sis.io.wkt.Convention conventions}
* in use and on the handling of {@linkplain org.apache.sis.io.wkt.Warnings warnings}.
* Applications which need to parse a large amount of WKT strings should consider to use
* the {@link org.apache.sis.io.wkt.WKTFormat} class instead than this method.
*
* @param text coordinate system encoded in Well-Known Text format (version 1 or 2).
* @throws FactoryException if the object creation failed.
*
* @see org.apache.sis.io.wkt
* @see org.apache.sis.referencing.CRS#fromWKT(String)
* @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT 2 specification</a>
* @see <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy WKT 1</a>
*/
@Override
public CoordinateReferenceSystem createFromWKT(final String text) throws FactoryException {
Parser p = parser.getAndSet(null);
if (p == null)
try {
Constructor<? extends Parser> c = parserConstructor;
if (c == null) {
c = Class.forName("org.apache.sis.io.wkt.GeodeticObjectParser").asSubclass(Parser.class).getConstructor(Map.class, ObjectFactory.class, MathTransformFactory.class);
// For allowing use in inner class or lambda expression.
final Constructor<?> cp = c;
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
cp.setAccessible(true);
return null;
});
parserConstructor = c;
}
p = c.newInstance(defaultProperties, this, getMathTransformFactory());
} catch (ReflectiveOperationException e) {
throw new FactoryException(e);
}
final Object object;
try {
object = p.createFromWKT(text);
} catch (FactoryException e) {
/*
* In the case of map projection, the parsing may fail because a projection parameter is not known to SIS.
* If this happen, replace the generic exception thrown be the parser (which is FactoryException) by a
* more specific one. Note that InvalidGeodeticParameterException is defined only in this sis-referencing
* module, so we could not throw it from the sis-metadata module that contain the parser.
*/
Throwable cause = e.getCause();
while (cause != null) {
if (cause instanceof ParameterNotFoundException) {
throw new InvalidGeodeticParameterException(e.getLocalizedMessage(), cause);
}
cause = cause.getCause();
}
throw e;
}
parser.set(p);
if (object instanceof CoordinateReferenceSystem) {
return (CoordinateReferenceSystem) object;
} else {
throw new FactoryException(Errors.getResources(defaultProperties).getString(Errors.Keys.IllegalClass_2, CoordinateReferenceSystem.class, object.getClass()));
}
}
use of org.opengis.util.FactoryException in project sis by apache.
the class LinearTransformBuilder method create.
/**
* Creates a linear transform approximation from the source positions to the target positions.
* This method assumes that source positions are precise and that all uncertainty is in the target positions.
*
* @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 fitted linear transform.
* @throws FactoryException if the transform can not be created,
* for example because the source or target points have not be specified.
*
* @since 0.8
*/
@Override
@SuppressWarnings("serial")
public LinearTransform create(final MathTransformFactory factory) throws FactoryException {
if (transform == null) {
// Protect from changes.
final double[][] sources = this.sources;
final double[][] targets = this.targets;
if (targets == null) {
throw new InvalidGeodeticParameterException(noData());
}
final int sourceDim = (sources != null) ? sources.length : gridSize.length;
final int targetDim = targets.length;
correlation = new double[targetDim];
final MatrixSIS matrix = Matrices.create(targetDim + 1, sourceDim + 1, ExtendedPrecisionMatrix.ZERO);
matrix.setElement(targetDim, sourceDim, 1);
for (int j = 0; j < targetDim; j++) {
final double c;
switch(sourceDim) {
case 1:
{
final int row = j;
final Line line = new Line() {
@Override
public void setEquation(final Number slope, final Number y0) {
super.setEquation(slope, y0);
// Preserve the extended precision (double-double).
matrix.setNumber(row, 0, slope);
matrix.setNumber(row, 1, y0);
}
};
if (sources != null) {
c = line.fit(vector(sources[0]), vector(targets[j]));
} else {
c = line.fit(Vector.createSequence(0, 1, gridSize[0]), Vector.create(targets[j], false));
}
break;
}
case 2:
{
final int row = j;
final Plane plan = new Plane() {
@Override
public void setEquation(final Number sx, final Number sy, final Number z0) {
super.setEquation(sx, sy, z0);
// Preserve the extended precision (double-double).
matrix.setNumber(row, 0, sx);
matrix.setNumber(row, 1, sy);
matrix.setNumber(row, 2, z0);
}
};
if (sources != null) {
c = plan.fit(vector(sources[0]), vector(sources[1]), vector(targets[j]));
} else
try {
c = plan.fit(gridSize[0], gridSize[1], Vector.create(targets[j], false));
} catch (IllegalArgumentException e) {
// This may happen if the z vector still contain some "NaN" values.
throw new InvalidGeodeticParameterException(noData(), e);
}
break;
}
default:
{
throw new FactoryException(Errors.format(Errors.Keys.ExcessiveNumberOfDimensions_1, sourceDim));
}
}
correlation[j] = c;
}
transform = (LinearTransform) nonNull(factory).createAffineTransform(matrix);
}
return transform;
}
use of org.opengis.util.FactoryException in project sis by apache.
the class ServicesForMetadata method setGeographicExtent.
/**
* Implementation of the public {@code setBounds(…, DefaultGeographicBoundingBox, …)} methods for
* the horizontal extent. If the {@code crs} argument is null, then it is caller's responsibility
* to ensure that the given envelope is two-dimensional.
*
* @param envelope the source envelope.
* @param target the target bounding box.
* @param crs the envelope CRS, or {@code null} if unknown.
* @param normalizedCRS the horizontal component of the given CRS, or null if the {@code crs} argument is null.
* @throws TransformException if the given envelope can not be transformed.
*/
private void setGeographicExtent(Envelope envelope, final DefaultGeographicBoundingBox target, final CoordinateReferenceSystem crs, final GeographicCRS normalizedCRS) throws TransformException {
if (normalizedCRS != null) {
// No need to check for dimension, since GeodeticCRS can not have less than 2.
final CoordinateSystem cs1 = crs.getCoordinateSystem();
final CoordinateSystem cs2 = normalizedCRS.getCoordinateSystem();
if (!Utilities.equalsIgnoreMetadata(cs2.getAxis(0), cs1.getAxis(0)) || !Utilities.equalsIgnoreMetadata(cs2.getAxis(1), cs1.getAxis(1))) {
final CoordinateOperation operation;
final CoordinateOperationFactory factory = CoordinateOperations.factory();
try {
operation = factory.createOperation(crs, normalizedCRS);
} catch (FactoryException e) {
throw new TransformException(Resources.format(Resources.Keys.CanNotTransformEnvelopeToGeodetic), e);
}
envelope = Envelopes.transform(operation, envelope);
}
}
/*
* At this point, the envelope should use (longitude, latitude) coordinates in degrees.
* However the prime meridian is not necessarily Greenwich.
*/
double westBoundLongitude = envelope.getMinimum(0);
double eastBoundLongitude = envelope.getMaximum(0);
double southBoundLatitude = envelope.getMinimum(1);
double northBoundLatitude = envelope.getMaximum(1);
if (normalizedCRS != null) {
final double rotation = CRS.getGreenwichLongitude(normalizedCRS);
westBoundLongitude += rotation;
eastBoundLongitude += rotation;
}
target.setBounds(westBoundLongitude, eastBoundLongitude, southBoundLatitude, northBoundLatitude);
target.setInclusion(Boolean.TRUE);
}
use of org.opengis.util.FactoryException in project sis by apache.
the class FranceGeocentricInterpolation method load.
/**
* Unconditionally loads the grid for the given file without in-memory compression.
*
* @param in reader of the RGF93 datum shift file.
* @param file path to the file being read, used only for error reporting.
* @throws IOException if an I/O error occurred.
* @throws NumberFormatException if a number can not be parsed.
* @throws NoSuchElementException if a data line is missing a value.
* @throws FactoryException if an problem is found with the file content.
* @throws ArithmeticException if the width or the height exceed the integer capacity.
*/
static DatumShiftGridFile.Float<Angle, Length> load(final BufferedReader in, final Path file) throws IOException, FactoryException, NoninvertibleTransformException {
DatumShiftGridFile.Float<Angle, Length> grid = null;
double x0 = 0;
double xf = 0;
double y0 = 0;
double yf = 0;
double Δx = 0;
double Δy = 0;
int nx = 0;
int ny = 0;
/*
* The header should be like below, but the only essential line for this class is the one
* starting with "GR3D1". We also check that "GR3D2" declares the expected interpolation.
*
* GR3D 002024 024 20370201
* GR3D1 -5.5000 10.0000 41.0000 52.0000 .1000 .1000
* GR3D2 INTERPOLATION BILINEAIRE
* GR3D3 PREC CM 01:5 02:10 03:20 04:50 99>100
*/
String line;
while (true) {
line = in.readLine();
if (line == null) {
throw new EOFException(Errors.format(Errors.Keys.UnexpectedEndOfFile_1, file));
}
final int length = CharSequences.skipTrailingWhitespaces(line, 0, line.length());
if (length <= 0) {
// Skip empty lines.
continue;
}
int p = CharSequences.skipLeadingWhitespaces(line, 0, length);
if (line.charAt(p) == '#') {
// Skip comment lines (not officially part of the format).
continue;
}
if (!line.regionMatches(true, p, HEADER, 0, HEADER.length())) {
// End of header.
break;
}
if ((p += HEADER.length()) < length) {
final char c = line.charAt(p);
p = CharSequences.skipLeadingWhitespaces(line, p + 1, length);
switch(c) {
case '1':
{
if (grid != null) {
throw new FactoryException(Errors.format(Errors.Keys.DuplicatedElement_1, HEADER));
}
final double[] gridGeometry = CharSequences.parseDoubles(line.substring(p, length), ' ');
if (gridGeometry.length == 6) {
x0 = gridGeometry[0];
xf = gridGeometry[1];
y0 = gridGeometry[2];
yf = gridGeometry[3];
Δx = gridGeometry[4];
Δy = gridGeometry[5];
nx = Math.toIntExact(Math.round((xf - x0) / Δx + 1));
ny = Math.toIntExact(Math.round((yf - y0) / Δy + 1));
grid = new DatumShiftGridFile.Float<>(3, Units.DEGREE, Units.METRE, false, x0, y0, Δx, Δy, nx, ny, PARAMETERS, file);
}
break;
}
case '2':
{
final String interp = line.substring(p, length);
if (!interp.matches("(?i)INTERPOLATION[^A-Z]+BILINEAIRE")) {
final LogRecord record = Errors.getResources((Locale) null).getLogRecord(Level.WARNING, Errors.Keys.UnsupportedInterpolation_1, interp);
record.setLoggerName(Loggers.COORDINATE_OPERATION);
Logging.log(FranceGeocentricInterpolation.class, "createMathTransform", record);
// We declare 'createMathTransform' method because it is closer to public API.
}
break;
}
}
}
}
if (grid == null) {
throw new FactoryException(Errors.format(Errors.Keys.CanNotParseFile_2, HEADER, file));
}
/*
* Loads the data with the sign of all offsets reversed. Data columns are
*
* (unknown), longitude, latitude, tX, tY, tZ, accuracy code, data sheet (ignored)
*
* where the longitude and latitude values are in RGF93 system.
* Example:
*
* 00002 -5.500000000 41.000000000 -165.027 -67.100 315.813 99 -0158
* 00002 -5.500000000 41.100000000 -165.169 -66.948 316.007 99 -0157
* 00002 -5.500000000 41.200000000 -165.312 -66.796 316.200 99 -0157
*
* Translation values in the IGN file are from NTF to RGF93, but Apache SIS implementation needs
* the opposite direction (from RGF93 to NTF). The reason is that SIS expect the source datum to
* be the datum in which longitude and latitude values are expressed.
*/
final float[] tX = grid.offsets[0];
final float[] tY = grid.offsets[1];
final float[] tZ = grid.offsets[2];
do {
final StringTokenizer t = new StringTokenizer(line.trim());
// Ignored
t.nextToken();
// Longitude in degrees
final double x = Double.parseDouble(t.nextToken());
// Latitude in degrees
final double y = Double.parseDouble(t.nextToken());
// Column index
final int i = Math.toIntExact(Math.round((x - x0) / Δx));
// Row index
final int j = Math.toIntExact(Math.round((y - y0) / Δy));
if (i < 0 || i >= nx) {
throw new FactoryException(Errors.format(Errors.Keys.ValueOutOfRange_4, "x", x, x0, xf));
}
if (j < 0 || j >= ny) {
throw new FactoryException(Errors.format(Errors.Keys.ValueOutOfRange_4, "y", y, y0, yf));
}
final int p = j * nx + i;
if (!Double.isNaN(tX[p]) || !Double.isNaN(tY[p]) || !Double.isNaN(tZ[p])) {
throw new FactoryException(Errors.format(Errors.Keys.ValueAlreadyDefined_1, x + ", " + y));
}
// See javadoc for the reason why we reverse the sign.
tX[p] = -parseFloat(t.nextToken());
tY[p] = -parseFloat(t.nextToken());
tZ[p] = -parseFloat(t.nextToken());
final double accuracy = ACCURACY[Math.min(ACCURACY.length - 1, Math.max(0, Integer.parseInt(t.nextToken()) - 1))];
if (!(accuracy >= grid.accuracy)) {
// Use '!' for replacing the initial NaN.
grid.accuracy = accuracy;
}
} while ((line = in.readLine()) != null);
return grid;
}
use of org.opengis.util.FactoryException in project sis by apache.
the class CC_OperationMethod method group.
/**
* Wraps the given descriptors in a descriptor group of the given name. If the given name can be matched
* to the name of one of the predefined operation method, then the predefined parameters will be used.
*
* <p>We try to use predefined parameters if possible because they contain information, especially the
* {@link org.opengis.parameter.ParameterDescriptor#getValueClass()} property, which are not available
* in the GML document.</p>
*
* <div class="note"><b>Note:</b>
* this code is defined in this {@code CC_OperationMethod} class instead than in the
* {@link DefaultOperationMethod} class in the hope to reduce the amount of code processed
* by the JVM in the common case where JAXB (un)marshalling is not needed.</div>
*
* @param name the operation method name, to be also given to the descriptor group.
* @param descriptors the parameter descriptors to wrap in a group. This array will be modified in-place.
* @return a parameter group containing at least the given descriptors, or equivalent descriptors.
*/
public static ParameterDescriptorGroup group(final Identifier name, final GeneralParameterDescriptor[] descriptors) {
OperationMethod method;
try {
method = CoordinateOperations.factory().getOperationMethod(name.getCode());
} catch (FactoryException e) {
// Use DefaultOperationMethod as the source class because it is the first public class in callers.
Context.warningOccured(Context.current(), DefaultOperationMethod.class, "setDescriptors", e, true);
method = null;
}
final Map<String, ?> properties = Collections.singletonMap(ParameterDescriptorGroup.NAME_KEY, name);
if (method != null) {
/*
* Verify that the pre-defined operation method contains at least all the parameters specified by
* the 'descriptors' array. If this is the case, then the pre-defined parameters will be used in
* replacement of the given ones.
*/
final ParameterDescriptorGroup parameters = method.getParameters();
return CC_GeneralOperationParameter.merge(DefaultOperationMethod.class, properties, IdentifiedObjects.getProperties(parameters), 1, 1, descriptors, parameters, true);
}
return new DefaultParameterDescriptorGroup(properties, 1, 1, descriptors);
}
Aggregations