use of org.opengis.util.FactoryException in project sis by apache.
the class GridGeometry method localizationGrid.
/**
* Builds a localization grid from the given GeoTIFF tie points.
* This method may invoke itself recursively.
*
* @param modelTiePoints the model tie points read from GeoTIFF file.
* @param addTo if non-null, add the transform result to this map.
*/
private static MathTransform localizationGrid(final Vector modelTiePoints, final Map<Envelope, MathTransform> addTo) throws FactoryException, TransformException {
final int size = modelTiePoints.size();
final int n = size / RECORD_LENGTH;
if (n == 0)
return null;
final Vector x = modelTiePoints.subSampling(0, RECORD_LENGTH, n);
final Vector y = modelTiePoints.subSampling(1, RECORD_LENGTH, n);
try {
final LocalizationGridBuilder grid = new LocalizationGridBuilder(x, y);
final LinearTransform sourceToGrid = grid.getSourceToGrid();
final double[] ordinates = new double[2];
for (int i = 0; i < size; i += RECORD_LENGTH) {
ordinates[0] = modelTiePoints.doubleValue(i);
ordinates[1] = modelTiePoints.doubleValue(i + 1);
sourceToGrid.transform(ordinates, 0, ordinates, 0, 1);
grid.setControlPoint(Math.toIntExact(Math.round(ordinates[0])), Math.toIntExact(Math.round(ordinates[1])), modelTiePoints.doubleValue(i + 3), modelTiePoints.doubleValue(i + 4));
}
grid.setDesiredPrecision(PRECISION);
final MathTransform tr = grid.create(null);
if (addTo != null && addTo.put(grid.getSourceEnvelope(), tr) != null) {
// Should never happen. If it does, we have a bug in our algorithm.
throw new FactoryException();
}
return tr;
} catch (ArithmeticException | FactoryException e) {
/*
* May happen when the model tie points are not distributed on a regular grid.
* For example Sentinel 1 images may have tie points spaced by 1320 pixels on the X axis,
* except the very last point which is only 1302 pixels after the previous one. We try to
* handle such grids by splitting them in two parts: one grid for the columns where points
* are spaced by 1320 pixels and one grid for the last column. Such splitting needs to be
* done horizontally and vertically, which result in four grids:
*
* ┌──────────────────┬───┐
* │ │ │
* │ 0 │ 1 │
* │ │ │
* ├──────────────────┼───┤ splitY
* │ 2 │ 3 │
* └──────────────────┴───┘
* splitX
*/
final Set<Double> uniques = new HashSet<>(100);
final double splitX = threshold(x, uniques);
final double splitY = threshold(y, uniques);
if (Double.isNaN(splitX) && Double.isNaN(splitY)) {
// Can not do better. Report the failure.
throw e;
}
final int[][] indices = new int[4][size];
final int[] lengths = new int[4];
for (int i = 0; i < size; ) {
final double px = modelTiePoints.doubleValue(i);
final double py = modelTiePoints.doubleValue(i + 1);
// Number of the part where to add current point.
int part = 0;
// Point will be added to part #1 or #3.
if (px > splitX)
part = 1;
// Point will be added to part #2 or #3.
if (py > splitY)
part |= 2;
// Bitmask of the parts where to add the point.
int parts = 1 << part;
// Add also the point to part #1 or #3.
if (px == splitX)
parts |= 1 << (part | 1);
// Add also the point to part #2 or #3.
if (py == splitY)
parts |= 1 << (part | 2);
if (parts == 0b0111) {
// Add also the point to part #3.
parts = 0b1111;
assert px == splitX && py == splitY;
}
final int upper = i + RECORD_LENGTH;
do {
part = Integer.numberOfTrailingZeros(parts);
@SuppressWarnings("MismatchedReadAndWriteOfArray") final int[] tileIndices = indices[part];
int k = lengths[part];
for (int j = i; j < upper; j++) {
tileIndices[k++] = j;
}
lengths[part] = k;
} while (// Clear the bit of the part we processed.
(parts &= ~(1 << part)) != 0);
i = upper;
}
/*
* At this point, we finished to collect indices of the points to use for parts #0, 1, 2 and 3.
* Verify that each part has less points than the initial vector (otherwise it would be a bug),
* and identify which part is the biggest one. This is usually part #0.
*/
int maxLength = 0;
int largestPart = 0;
for (int i = 0; i < indices.length; i++) {
final int length = lengths[i];
// Safety against infinite recursivity.
if (length >= size)
throw e;
indices[i] = Arrays.copyOf(indices[i], length);
if (length > maxLength) {
maxLength = length;
largestPart = i;
}
}
/*
* The biggest part will define the global transform. All other parts will define a specialization
* valid only in a sub-area. Put those information in a map for MathTransforms.specialize(…).
*/
MathTransform global = null;
final Map<Envelope, MathTransform> specialization = new LinkedHashMap<>(4);
for (int i = 0; i < indices.length; i++) {
final Vector sub = modelTiePoints.pick(indices[i]);
if (i == largestPart) {
global = localizationGrid(sub, null);
} else {
localizationGrid(sub, specialization);
}
}
return MathTransforms.specialize(global, specialization);
}
}
use of org.opengis.util.FactoryException in project sis by apache.
the class TransformCommand method run.
/**
* Transforms coordinates from the files given in argument or from the standard input stream.
*
* @return 0 on success, or an exit code if the command failed for a reason other than an uncaught Java exception.
*/
@Override
public int run() throws Exception {
final CoordinateReferenceSystem sourceCRS = fetchCRS(Option.SOURCE_CRS);
final CoordinateReferenceSystem targetCRS = fetchCRS(Option.TARGET_CRS);
/*
* Read all coordinates, so we can compute the area of interest.
* This will be used when searching for a coordinate operation.
*/
GeographicBoundingBox areaOfInterest = null;
List<double[]> points = Collections.emptyList();
final boolean useStandardInput = useStandardInput();
if (useStandardInput || !files.isEmpty()) {
if (useStandardInput) {
try (LineNumberReader in = new LineNumberReader(new InputStreamReader(System.in, encoding))) {
points = readCoordinates(in, "stdin");
}
} else {
for (final String file : files) {
try (LineNumberReader in = new LineNumberReader(new InputStreamReader(new FileInputStream(file), encoding))) {
points = readCoordinates(in, file);
}
}
}
try {
final GeographicCRS domainOfValidityCRS = ReferencingUtilities.toNormalizedGeographicCRS(sourceCRS);
if (domainOfValidityCRS != null) {
toDomainOfValidity = CRS.findOperation(sourceCRS, domainOfValidityCRS, null).getMathTransform();
areaOfInterest = computeAreaOfInterest(points);
}
} catch (FactoryException e) {
warning(e);
}
}
operation = CRS.findOperation(sourceCRS, targetCRS, areaOfInterest);
/*
* Prints the header: source CRS, target CRS, operation steps and positional accuracy.
*/
outHeader = new TableAppender(new LineAppender(out), " ");
outHeader.setMultiLinesCells(true);
printHeader(Vocabulary.Keys.Source);
printNameAndIdentifier(operation.getSourceCRS(), false);
printHeader(Vocabulary.Keys.Destination);
printNameAndIdentifier(operation.getTargetCRS(), false);
printHeader(Vocabulary.Keys.Operations);
printOperations(operation, false);
outHeader.nextLine();
printDomainOfValidity(operation.getDomainOfValidity());
printAccuracy(CRS.getLinearAccuracy(operation));
if (options.containsKey(Option.VERBOSE)) {
printDetails();
}
outHeader.flush();
outHeader = null;
/*
* At this point we finished to write the header. If there is at least one input file,
* compute the number of digits to format and perform the actual coordinate operations.
*/
if (!points.isEmpty()) {
// Must be set before computeNumFractionDigits(…).
ordinateWidth = 15;
coordinateFormat = NumberFormat.getInstance(Locale.US);
coordinateFormat.setGroupingUsed(false);
computeNumFractionDigits(operation.getTargetCRS().getCoordinateSystem());
out.println();
printAxes(operation.getTargetCRS().getCoordinateSystem());
out.println();
transform(points);
if (errorMessage != null) {
error(errorMessage, errorCause);
}
}
return 0;
}
use of org.opengis.util.FactoryException in project sis by apache.
the class CRS method findOperations.
/**
* Finds mathematical operations that transform or convert coordinates from the given source to the
* given target coordinate reference system. If at least one operation exists, they are returned in
* preference order: the operation having the widest intersection between its
* {@linkplain AbstractCoordinateOperation#getDomainOfValidity() domain of validity}
* and the given area of interest are returned first.
*
* @param sourceCRS the CRS of source coordinates.
* @param targetCRS the CRS of target coordinates.
* @param areaOfInterest the area of interest, or {@code null} if none.
* @return mathematical operations from {@code sourceCRS} to {@code targetCRS}.
* @throws OperationNotFoundException if no operation was found between the given pair of CRS.
* @throws FactoryException if the operation can not be created for another reason.
*
* @see DefaultCoordinateOperationFactory#createOperations(CoordinateReferenceSystem, CoordinateReferenceSystem, CoordinateOperationContext)
*
* @since 1.0
*/
public static List<CoordinateOperation> findOperations(final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS, final GeographicBoundingBox areaOfInterest) throws FactoryException {
ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
final CoordinateOperationContext context = CoordinateOperationContext.fromBoundingBox(areaOfInterest);
final DefaultCoordinateOperationFactory factory = CoordinateOperations.factory();
try {
return factory.createOperations(sourceCRS, targetCRS, context);
} catch (UnavailableFactoryException e) {
if (AuthorityFactories.failure(e)) {
throw e;
} else
try {
return Collections.singletonList(factory.createOperation(sourceCRS, targetCRS, context));
} catch (FactoryException ex) {
ex.addSuppressed(e);
throw ex;
}
}
}
use of org.opengis.util.FactoryException in project sis by apache.
the class CRS method findOperation.
/**
* Finds a mathematical operation that transforms or converts coordinates from the given source to the
* given target coordinate reference system. If an estimation of the geographic area containing the points
* to transform is known, it can be specified for helping this method to find a better suited operation.
* If no area of interest is specified, then the current default is the widest
* {@linkplain AbstractCoordinateOperation#getDomainOfValidity() domain of validity}.
* A future Apache SIS version may also take the country of current locale in account.
*
* <div class="note"><b>Note:</b>
* the area of interest is just one aspect that may affect the coordinate operation.
* Other aspects are the time of interest (because some coordinate operations take in account the
* plate tectonics movement) or the desired accuracy. For more control on the coordinate operation
* to create, see {@link CoordinateOperationContext}.</div>
*
* After the caller received a {@code CoordinateOperation} instance, the following methods can be invoked
* for checking if the operation suits the caller's needs:
*
* <ul>
* <li>{@link #getGeographicBoundingBox(CoordinateOperation)}
* for checking if the operation is valid in the caller's area of interest.</li>
* <li>{@link #getLinearAccuracy(CoordinateOperation)}
* for checking if the operation has sufficient accuracy for caller's purpose.</li>
* </ul>
*
* If the source and target CRS are equivalent, then this method returns an operation backed by an
* {@linkplain org.apache.sis.referencing.operation.transform.AbstractMathTransform#isIdentity() identity}
* transform. If there is no known operation between the given pair of CRS, then this method throws an
* {@link OperationNotFoundException}.
*
* @param sourceCRS the CRS of source coordinates.
* @param targetCRS the CRS of target coordinates.
* @param areaOfInterest the area of interest, or {@code null} if none.
* @return the mathematical operation from {@code sourceCRS} to {@code targetCRS}.
* @throws OperationNotFoundException if no operation was found between the given pair of CRS.
* @throws FactoryException if the operation can not be created for another reason.
*
* @see DefaultCoordinateOperationFactory#createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem, CoordinateOperationContext)
*
* @since 0.7
*/
public static CoordinateOperation findOperation(final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS, final GeographicBoundingBox areaOfInterest) throws FactoryException {
ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
final CoordinateOperationContext context = CoordinateOperationContext.fromBoundingBox(areaOfInterest);
/*
* In principle we should just delegate to factory.createOperation(…). However this operation may fail
* if a connection to the EPSG database has been found, but the EPSG tables do not yet exist in that
* database and
*/
final DefaultCoordinateOperationFactory factory = CoordinateOperations.factory();
try {
return factory.createOperation(sourceCRS, targetCRS, context);
} catch (UnavailableFactoryException e) {
if (AuthorityFactories.failure(e)) {
throw e;
} else
try {
// Above method call replaced the EPSG factory by a fallback. Try again.
return factory.createOperation(sourceCRS, targetCRS, context);
} catch (FactoryException ex) {
ex.addSuppressed(e);
throw ex;
}
}
}
use of org.opengis.util.FactoryException in project jena by apache.
the class GenericCardinalGeomPropertyFunction method checkSecondFilter.
@Override
protected boolean checkSecondFilter(SpatialArguments spatialArguments, GeometryWrapper targetGeometryWrapper) {
// Test Geometry against the Geometry from Object to see if it is a success.
// Used when checking against bound Subjects.
// Cardinal functions only check against the search envelope.
SearchEnvelope searchEnvelope = spatialArguments.getSearchEnvelope();
try {
GeometryWrapper srs = targetGeometryWrapper.convertSRS(searchEnvelope.getSrsURI());
Envelope targetEnvelope = srs.getEnvelope();
boolean result = searchEnvelope.check(targetEnvelope);
return result;
} catch (FactoryException | MismatchedDimensionException | TransformException ex) {
throw new ExprEvalException(ex.getMessage() + ": " + targetGeometryWrapper.asLiteral(), ex);
}
}
Aggregations