use of org.opengis.metadata.extent.GeographicBoundingBox in project sis by apache.
the class CoordinateOperationFinder method createOperations.
/**
* Infers operations for conversions or transformations between two coordinate reference systems.
* If a non-null authority factory – the <cite>registry</cite> – has been specified at construction time,
* then this method will first query that factory (<cite>late-binding</cite> approach – see class javadoc).
* If no operation has been found in the registry or if no registry has been specified to the constructor,
* this method inspects the given CRS and delegates the work to one or many {@code createOperationStep(…)}
* methods (<cite>early-binding</cite> approach).
*
* <p>At first, this method is invoked with the {@code sourceCRS} and {@code targetCRS} arguments given to the
* {@link DefaultCoordinateOperationFactory#createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem,
* CoordinateOperationContext) CoordinateOperationFactory.createOperation(…)} method. But then, this method may
* be invoked recursively by some {@code createOperationStep(…)} methods with different source or target CRS,
* for example in order to process the {@linkplain org.apache.sis.referencing.crs.DefaultProjectedCRS#getBaseCRS()
* base geographic CRS} of a projected CRS.</p>
*
* <p>Coordinate operations are returned in preference order: best operations for the area of interest should be first.
* The returned list is modifiable: callers can add, remove or set elements without impact on this
* {@code CoordinateOperationFinder} instance.</p>
*
* @param sourceCRS input coordinate reference system.
* @param targetCRS output coordinate reference system.
* @return coordinate operations from {@code sourceCRS} to {@code targetCRS}.
* @throws OperationNotFoundException if no operation path was found from {@code sourceCRS} to {@code targetCRS}.
* @throws FactoryException if the operation creation failed for some other reason.
*
* @since 1.0
*/
@Override
public List<CoordinateOperation> createOperations(final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS) throws FactoryException {
ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
if (equalsIgnoreMetadata(sourceCRS, targetCRS))
try {
return asList(createFromAffineTransform(AXIS_CHANGES, sourceCRS, targetCRS, CoordinateSystems.swapAndScaleAxes(sourceCRS.getCoordinateSystem(), targetCRS.getCoordinateSystem())));
} catch (IllegalArgumentException | IncommensurableException e) {
throw new FactoryException(Resources.format(Resources.Keys.CanNotInstantiateGeodeticObject_1, new CRSPair(sourceCRS, targetCRS)), e);
}
/*
* If this method is invoked recursively, verify if the requested operation is already in the cache.
* We do not perform this verification on the first invocation because it was already verified by
* DefaultCoordinateOperationFactory.createOperation(…). We do not block if the operation is in
* process of being computed in another thread because of the risk of deadlock. If the operation
* is not in the cache, store the key in our internal map for preventing infinite recursivity.
*/
final CRSPair key = new CRSPair(sourceCRS, targetCRS);
if (useCache && stopAtFirst && !previousSearches.isEmpty()) {
final CoordinateOperation op = factorySIS.cache.peek(key);
// Must be a modifiable list as per this method contract.
if (op != null)
return asList(op);
}
if (previousSearches.put(key, Boolean.TRUE) != null) {
throw new FactoryException(Resources.format(Resources.Keys.RecursiveCreateCallForCode_2, CoordinateOperation.class, key));
}
/*
* If the user did not specified an area of interest, use the domain of validity of the CRS.
*/
GeographicBoundingBox bbox = Extents.getGeographicBoundingBox(areaOfInterest);
if (bbox == null) {
bbox = Extents.intersection(CRS.getGeographicBoundingBox(sourceCRS), CRS.getGeographicBoundingBox(targetCRS));
areaOfInterest = CoordinateOperationContext.setGeographicBoundingBox(areaOfInterest, bbox);
}
/*
* Verify if some extension module handles this pair of CRS in a special way. For example it may
* be the "sis-gdal" module checking if the given CRS are wrappers around Proj.4 data structure.
*/
{
// For keeping 'operations' list locale.
final List<CoordinateOperation> operations = new ArrayList<>();
for (final SpecializedOperationFactory sp : factorySIS.getSpecializedFactories()) {
for (final CoordinateOperation op : sp.findOperations(sourceCRS, targetCRS)) {
if (filter(op)) {
operations.add(op);
}
}
}
if (!operations.isEmpty()) {
CoordinateOperationSorter.sort(operations, bbox);
return operations;
}
}
/*
* Verify in the EPSG dataset if the operation is explicitely defined by an authority.
*/
if (registry != null) {
final List<CoordinateOperation> authoritatives = super.createOperations(sourceCRS, targetCRS);
if (!authoritatives.isEmpty())
return authoritatives;
}
// //////////////////////////////////////////////////////////////////////////////
if (sourceCRS instanceof GeneralDerivedCRS) {
final GeneralDerivedCRS source = (GeneralDerivedCRS) sourceCRS;
if (targetCRS instanceof GeneralDerivedCRS) {
return createOperationStep(source, (GeneralDerivedCRS) targetCRS);
}
if (targetCRS instanceof SingleCRS) {
return createOperationStep(source, (SingleCRS) targetCRS);
}
}
// //////////////////////////////////////////////////////////////////////////////
if (targetCRS instanceof GeneralDerivedCRS) {
final GeneralDerivedCRS target = (GeneralDerivedCRS) targetCRS;
if (sourceCRS instanceof SingleCRS) {
return createOperationStep((SingleCRS) sourceCRS, target);
}
}
// //////////////////////////////////////////////////////////////////////////////
if (sourceCRS instanceof GeodeticCRS) {
final GeodeticCRS source = (GeodeticCRS) sourceCRS;
if (targetCRS instanceof GeodeticCRS) {
return createOperationStep(source, (GeodeticCRS) targetCRS);
}
if (targetCRS instanceof VerticalCRS) {
return createOperationStep(source, (VerticalCRS) targetCRS);
}
}
// //////////////////////////////////////////////////////////////////////////////
if (sourceCRS instanceof VerticalCRS) {
final VerticalCRS source = (VerticalCRS) sourceCRS;
if (targetCRS instanceof VerticalCRS) {
return createOperationStep(source, (VerticalCRS) targetCRS);
}
}
// //////////////////////////////////////////////////////////////////////////////
if (sourceCRS instanceof TemporalCRS) {
final TemporalCRS source = (TemporalCRS) sourceCRS;
if (targetCRS instanceof TemporalCRS) {
return createOperationStep(source, (TemporalCRS) targetCRS);
}
}
// //////////////////////////////////////////////////////////////////////////////
if (sourceCRS instanceof CompoundCRS || targetCRS instanceof CompoundCRS) {
return createOperationStep(sourceCRS, CRS.getSingleComponents(sourceCRS), targetCRS, CRS.getSingleComponents(targetCRS));
}
throw new OperationNotFoundException(notFoundMessage(sourceCRS, targetCRS));
}
use of org.opengis.metadata.extent.GeographicBoundingBox in project sis by apache.
the class StoreTest method testGetMetadata.
/**
* Tests {@link Store#getMetadata()}.
*
* @throws DataStoreException if an error occurred while parsing the data.
*/
@Test
public void testGetMetadata() throws DataStoreException {
final Metadata metadata;
try (Store store = open()) {
metadata = store.getMetadata();
}
final Extent extent = getSingleton(((AbstractIdentification) getSingleton(metadata.getIdentificationInfo())).getExtents());
final GeographicBoundingBox bbox = (GeographicBoundingBox) getSingleton(extent.getGeographicElements());
assertEquals("westBoundLongitude", 50.23, bbox.getWestBoundLongitude(), STRICT);
assertEquals("eastBoundLongitude", 50.31, bbox.getEastBoundLongitude(), STRICT);
assertEquals("southBoundLatitude", 9.23, bbox.getSouthBoundLatitude(), STRICT);
assertEquals("northBoundLatitude", 9.27, bbox.getNorthBoundLatitude(), STRICT);
assertTrue("Should not have a vertical extent.", extent.getVerticalElements().isEmpty());
}
use of org.opengis.metadata.extent.GeographicBoundingBox in project sis by apache.
the class SingleOperationMarshallingTest method testConversionUnmarshalling.
/**
* Tests unmarshalling of a defining conversion.
*
* @throws JAXBException if an error occurred during marshalling or unmarshalling.
*/
@Test
@DependsOnMethod("testOperationMethod")
public void testConversionUnmarshalling() throws JAXBException {
final DefaultConversion c = unmarshalFile(DefaultConversion.class, "Conversion.xml");
assertEquals("name", "World Mercator", c.getName().getCode());
assertEquals("identifier", "3395", getSingleton(c.getIdentifiers()).getCode());
assertEquals("scope", "Very small scale mapping.", String.valueOf(c.getScope()));
assertNull("operationVersion", c.getOperationVersion());
final GeographicBoundingBox e = (GeographicBoundingBox) getSingleton(c.getDomainOfValidity().getGeographicElements());
assertEquals("eastBoundLongitude", +180, e.getEastBoundLongitude(), STRICT);
assertEquals("westBoundLongitude", -180, e.getWestBoundLongitude(), STRICT);
assertEquals("northBoundLatitude", 84, e.getNorthBoundLatitude(), STRICT);
assertEquals("southBoundLatitude", -80, e.getSouthBoundLatitude(), STRICT);
// This is a defining conversion, so we do not expect CRS.
assertNull("sourceCRS", c.getSourceCRS());
assertNull("targetCRS", c.getTargetCRS());
assertNull("interpolationCRS", c.getInterpolationCRS());
assertNull("mathTransform", c.getMathTransform());
// The most difficult part.
final OperationMethod method = c.getMethod();
assertNotNull("method", method);
verifyMethod(method);
final ParameterValueGroup parameters = c.getParameterValues();
assertNotNull("parameters", parameters);
final Iterator<GeneralParameterValue> it = parameters.values().iterator();
verifyParameter(method, parameters, -0.0, (ParameterValue<?>) it.next());
verifyParameter(method, parameters, -90.0, (ParameterValue<?>) it.next());
assertFalse("Unexpected parameter.", it.hasNext());
Validators.validate(c);
}
use of org.opengis.metadata.extent.GeographicBoundingBox in project sis by apache.
the class Extents method getGeographicBoundingBox.
/**
* Returns a single geographic bounding box from the specified extent.
* This method tries to find the bounding box in the cheapest way
* before to fallback on more expansive computations:
*
* <ol>
* <li>First, this method searches geographic elements that are instance of {@link GeographicBoundingBox}.<ul>
* <li>If exactly one such instance is found, then this method returns that instance directly (no copy).</li>
* <li>If more than one instance is found, then this method computes and returns the
* {@linkplain DefaultGeographicBoundingBox#add union} of all bounding boxes.</li>
* </ul></li>
* <li>If above step found no {@code GeographicBoundingBox}, then this method inspects geographic elements
* that are instance of {@link BoundingPolygon}, taking in account only the envelopes associated to a
* coordinate reference system of kind {@link GeographicCRS}. If such envelopes are found, then this
* method computes and returns their union.</li>
* <li>If above step found no polygon's envelope associated to a geographic CRS, then in last resort this
* method uses all polygon's envelopes regardless their coordinate reference system (provided that the
* CRS is not null), applying coordinate transformations if needed.</li>
* <li>If above step found no polygon's envelope, then this method returns {@code null}.</li>
* </ol>
*
* @param extent the extent to convert to a geographic bounding box, or {@code null}.
* @return a geographic bounding box extracted from the given extent, or {@code null} if none.
*
* @see org.apache.sis.referencing.CRS#getDomainOfValidity(CoordinateReferenceSystem)
*/
public static GeographicBoundingBox getGeographicBoundingBox(final Extent extent) {
GeographicBoundingBox bounds = null;
if (extent != null) {
DefaultGeographicBoundingBox modifiable = null;
final List<Envelope> fallbacks = new ArrayList<>();
for (final GeographicExtent element : extent.getGeographicElements()) {
/*
* If a geographic bounding box can be obtained, add it to the previous boxes (if any).
* All exclusion boxes before the first inclusion box are ignored.
*/
if (element instanceof GeographicBoundingBox) {
final GeographicBoundingBox item = (GeographicBoundingBox) element;
if (bounds == null) {
/*
* We use DefaultGeographicBoundingBox.getInclusion(Boolean) below because
* add(…) method that we use cares about the case where inclusion is false.
*/
if (DefaultGeographicBoundingBox.getInclusion(item.getInclusion())) {
bounds = item;
}
} else {
if (modifiable == null) {
bounds = modifiable = new DefaultGeographicBoundingBox(bounds);
}
modifiable.add(item);
}
}
}
/*
* If we found not explicit GeographicBoundingBox element, use the information that we
* collected in BoundingPolygon elements. This may involve coordinate transformations.
*/
if (bounds == null)
try {
for (final Envelope envelope : fallbacks) {
final DefaultGeographicBoundingBox item = new DefaultGeographicBoundingBox();
item.setBounds(envelope);
if (bounds == null) {
bounds = item;
} else {
if (modifiable == null) {
bounds = modifiable = new DefaultGeographicBoundingBox(bounds);
}
modifiable.add(item);
}
}
} catch (TransformException e) {
throw new InvalidMetadataException(Errors.format(Errors.Keys.CanNotTransformEnvelope), e);
}
}
return bounds;
}
Aggregations