use of org.apache.sis.geometry.Envelopes 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.
*
* <p>If {@code findOpCaller} is non-null, then this method will be executed in optional mode:
* some failures will cause this method to return {@code null} instead of throwing an exception.
* Note that {@link TransformException} may still be thrown but not directly by this method.
* Warning may be logged, but in such case this method presumes that public caller is the named
* method from {@link Envelopes} — typically {@link Envelopes#findOperation(Envelope, Envelope)}.</p>
*
* @param envelope the source envelope.
* @param target the target bounding box, or {@code null} for creating it automatically.
* @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.
* @param findOpCaller non-null for replacing some (not all) exceptions by {@code null} return value.
* @return the bounding box or {@code null} on failure. Never {@code null} if {@code findOpCaller} argument is {@code null}.
* @throws TransformException if the given envelope can not be transformed.
*/
private static DefaultGeographicBoundingBox setGeographicExtent(Envelope envelope, DefaultGeographicBoundingBox target, final CoordinateReferenceSystem crs, final GeographicCRS normalizedCRS, final String findOpCaller) 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) {
if (findOpCaller != null) {
// See javadoc for the assumption that optional mode is used by Envelopes.findOperation(…).
Logging.recoverableException(Logging.getLogger(Modules.REFERENCING), Envelopes.class, findOpCaller, e);
return null;
}
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.
* The envelope may cross the anti-meridian if the envelope implementation is an Apache SIS one.
* For other implementations, the longitude range may be conservatively expanded to [-180 … 180]°.
*/
double westBoundLongitude, eastBoundLongitude;
double southBoundLatitude, northBoundLatitude;
if (envelope instanceof AbstractEnvelope) {
final AbstractEnvelope ae = (AbstractEnvelope) envelope;
westBoundLongitude = ae.getLower(0);
// Cross anti-meridian if eastBoundLongitude < westBoundLongitude.
eastBoundLongitude = ae.getUpper(0);
southBoundLatitude = ae.getLower(1);
northBoundLatitude = ae.getUpper(1);
} else {
westBoundLongitude = envelope.getMinimum(0);
// Expanded to [-180 … 180]° if it was crossing the anti-meridian.
eastBoundLongitude = envelope.getMaximum(0);
southBoundLatitude = envelope.getMinimum(1);
northBoundLatitude = envelope.getMaximum(1);
}
/*
* The envelope transformation at the beginning of this method intentionally avoided to apply datum shift.
* This implies that the prime meridian has not been changed and may be something else than Greenwich.
* We need to take it in account manually.
*
* Note that there is no need to normalize the longitudes back to the [-180 … +180]° range after the rotation, or
* to verify if the longitude span is 360°. Those verifications will be done automatically by target.setBounds(…).
*/
if (normalizedCRS != null) {
final double rotation = CRS.getGreenwichLongitude(normalizedCRS);
westBoundLongitude += rotation;
eastBoundLongitude += rotation;
}
/*
* In the particular case where this method is invoked (indirectly) for Envelopes.findOperation(…) purposes,
* replace NaN values by the whole world. We do that only for Envelopes.findOperation(…) since we know that
* the geographic bounding box will be used for choosing a CRS, and a conservative approach is to select the
* CRS valid in the widest area. If this method is invoked for other usages, then we keep NaN values because
* we don't know the context (union, intersection, something else?).
*/
if (findOpCaller != null) {
if (Double.isNaN(southBoundLatitude))
southBoundLatitude = Latitude.MIN_VALUE;
if (Double.isNaN(northBoundLatitude))
northBoundLatitude = Latitude.MAX_VALUE;
if (Double.isNaN(eastBoundLongitude) || Double.isNaN(westBoundLongitude)) {
// Conservatively set the two bounds because may be crossing the anti-meridian.
eastBoundLongitude = Longitude.MIN_VALUE;
westBoundLongitude = Longitude.MAX_VALUE;
}
}
if (target == null) {
target = new DefaultGeographicBoundingBox();
}
target.setBounds(westBoundLongitude, eastBoundLongitude, southBoundLatitude, northBoundLatitude);
target.setInclusion(Boolean.TRUE);
return target;
}
Aggregations