Search in sources :

Example 1 with Envelopes

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;
}
Also used : Envelopes(org.apache.sis.geometry.Envelopes) AbstractEnvelope(org.apache.sis.geometry.AbstractEnvelope) DefaultGeographicBoundingBox(org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox) FactoryException(org.opengis.util.FactoryException) CoordinateSystem(org.opengis.referencing.cs.CoordinateSystem) DefaultCoordinateOperationFactory(org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory) CoordinateOperationFactory(org.opengis.referencing.operation.CoordinateOperationFactory) TransformException(org.opengis.referencing.operation.TransformException) CoordinateOperation(org.opengis.referencing.operation.CoordinateOperation)

Aggregations

AbstractEnvelope (org.apache.sis.geometry.AbstractEnvelope)1 Envelopes (org.apache.sis.geometry.Envelopes)1 DefaultGeographicBoundingBox (org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox)1 DefaultCoordinateOperationFactory (org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory)1 CoordinateSystem (org.opengis.referencing.cs.CoordinateSystem)1 CoordinateOperation (org.opengis.referencing.operation.CoordinateOperation)1 CoordinateOperationFactory (org.opengis.referencing.operation.CoordinateOperationFactory)1 TransformException (org.opengis.referencing.operation.TransformException)1 FactoryException (org.opengis.util.FactoryException)1