This is an automated email from the ASF dual-hosted git repository. amanin pushed a commit to branch refactor/sql-store in repository https://gitbox.apache.org/repos/asf/sis.git
commit abffc9c1281a7653d63759abf442a38784a40ac0 Author: Alexis Manin <[email protected]> AuthorDate: Thu Oct 10 11:16:48 2019 +0200 WIP(Feature): start adding CRS resolution strategy for filter operations. --- .../java/org/apache/sis/filter/CRSMatching.java | 100 +++++++++++++++++++++ .../java/org/apache/sis/filter/package-info.java | 45 +++++++++- .../main/java/org/apache/sis/referencing/CRS.java | 80 +++++++++-------- 3 files changed, 184 insertions(+), 41 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/CRSMatching.java b/core/sis-feature/src/main/java/org/apache/sis/filter/CRSMatching.java new file mode 100644 index 0000000..78c4d9f --- /dev/null +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/CRSMatching.java @@ -0,0 +1,100 @@ +package org.apache.sis.filter; + +import java.util.Optional; + +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.operation.CoordinateOperation; +import org.opengis.util.FactoryException; + +import org.apache.sis.referencing.CRS; +import org.apache.sis.util.NullArgumentException; +import org.apache.sis.util.Utilities; + +/** + * TODO: improve CRS conversion/suggestion by infering a geographic region of interest. + */ +public interface CRSMatching { + + static CRSMatching left(final CoordinateReferenceSystem source) { + if (source == null) { + return new CRSMatching() { + @Override + public Match right(CoordinateReferenceSystem other) { + if (other == null) return new NullMatch(); + else throw new IllegalArgumentException("No match can be established with given CRS because source one is null."); + } + }; + } else { + return new CRSMatching() { + @Override + public Match right(CoordinateReferenceSystem other) throws FactoryException { + if (other == null) throw new NullArgumentException("No match can be established with previous CRS because input one is null"); + final CoordinateReferenceSystem commonCrs = CRS.suggestCommonTarget(null, source, other); + return new DefaultMatch(commonCrs, source, other); + } + }; + } + } + Match right(final CoordinateReferenceSystem other) throws FactoryException; + + interface Match { + Optional<CoordinateReferenceSystem> getCommonCRS(); + Optional<CoordinateOperation> fromLeft(); + Optional<CoordinateOperation> fromRight(); + } + + final class NullMatch implements Match { + + @Override + public Optional<CoordinateReferenceSystem> getCommonCRS() { + return Optional.empty(); + } + + @Override + public Optional<CoordinateOperation> fromLeft() { + return Optional.empty(); + } + + @Override + public Optional<CoordinateOperation> fromRight() { + return Optional.empty(); + } + } + + final class DefaultMatch implements Match { + + final CoordinateReferenceSystem commonCRS; + final Optional<CoordinateOperation> fromLeft; + final Optional<CoordinateOperation> fromRight; + + public DefaultMatch(CoordinateReferenceSystem commonCRS, CoordinateReferenceSystem left, CoordinateReferenceSystem right) throws FactoryException { + this.commonCRS = commonCRS; + fromLeft = createOp(left, commonCRS); + fromRight = createOp(right, commonCRS); + } + + @Override + public Optional<CoordinateReferenceSystem> getCommonCRS() { + return Optional.of(commonCRS); + } + + @Override + public Optional<CoordinateOperation> fromLeft() { + return fromLeft; + } + + @Override + public Optional<CoordinateOperation> fromRight() { + return fromRight; + } + } + + static Optional<CoordinateOperation> createOp(final CoordinateReferenceSystem source, final CoordinateReferenceSystem target) throws FactoryException { + if (Utilities.equalsIgnoreMetadata(source, target)) { + return Optional.empty(); + } else { + final CoordinateOperation op = CRS.findOperation(source, target, null); + return Optional.of(op); + } + } +} diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/package-info.java b/core/sis-feature/src/main/java/org/apache/sis/filter/package-info.java index 7291456..cc40a87 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/package-info.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/package-info.java @@ -19,12 +19,53 @@ * Filters features according their properties. * A <cite>filter expression</cite> is a construct used to constraint a feature set to a subset. * + * All operations in this package try to follow rules of both following standards: + * <ul> + * <li><a href="https://www.iso.org/fr/standard/53698.html">ISO/IEC 13249-3:2011 - SQLMM</a></li> + * <li><a href="http://docs.opengeospatial.org/is/09-026r2/09-026r2.html">OGC® Filter Encoding 2.0 Encoding Standard</a></li> + * </ul> + * + * <div class="section">General considerations:</div> + * <div class="section">Coordinate reference system handling:</div> + * As stated by Filter encoding 2.0.2, section 7.8.4, heterogeneous coordinate reference systems must be handled by + * libraries, one way or another. The standard does not define any strategy. As Apache-SIS contains a powerful + * transform system, we'll try to handle differences in the following way: + * <ul> + * <li> + * If all evaluated geometries define a srid, but their not the same, we'll try to project them in a common + * space. The strategy will be guided by {@link org.apache.sis.referencing.CRS#suggestCommonTarget(org.opengis.metadata.extent.GeographicBoundingBox, org.opengis.referencing.crs.CoordinateReferenceSystem...) Referencing utility method}. + * If it cannot provide a common space, we will fail any ongoing operation. + * </li> + * <li> + * Missing information: + * <ul> + * <li>If no geometry contains any srid, consider they're defined in the same space, and proceed</li> + * <li>If one geometry define a CRS but the other do not, consider that an ambiguity resides: fail.</li> + * </ul> + * </li> + * </ul> + * + * <div class="section">Optimisations</div> + * For now, few to no optimisation is done in the operators. Most of important ones would require one of the two + * following things: + * <ul> + * <li> + * Context information: Filters does not know in advance the feature type they're operating upon, which is + * vital to define some calculus parameters, as property value conversion strategy, spatial system changes, etc. + * Such information would allow operators to prepare data at initialisation time. + * </li> + * <li> + * User hints: some operations could be set faster at the cost of precision. To activate such things, it would + * require user consent. Most naïve example is spatial reference system conversion, which could be de-activated + * for systems with nearly equal parameters (see {@link org.apache.sis.util.Utilities#equalsApproximately(java.lang.Object, java.lang.Object)}. + * </li> + * </ul> + * extra-information for + * the operator, as well as hints from the user to allow sac * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) * @version 1.0 * - * @see <a href="http://docs.opengeospatial.org/is/09-026r2/09-026r2.html">OGC® Filter Encoding 2.0 Encoding Standard</a> - * * @since 1.0 * @module */ diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java index 1b9b49d..a8912d4 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java @@ -16,82 +16,84 @@ */ package org.apache.sis.referencing; -import java.util.Map; -import java.util.List; import java.util.ArrayList; import java.util.Collections; +import java.util.List; +import java.util.Map; import java.util.logging.LogRecord; -import org.opengis.util.FactoryException; + import org.opengis.geometry.Envelope; -import org.opengis.referencing.NoSuchAuthorityCodeException; +import org.opengis.geometry.Geometry; +import org.opengis.metadata.citation.Citation; +import org.opengis.metadata.extent.BoundingPolygon; +import org.opengis.metadata.extent.Extent; +import org.opengis.metadata.extent.GeographicBoundingBox; +import org.opengis.metadata.extent.GeographicExtent; import org.opengis.referencing.IdentifiedObject; -import org.opengis.referencing.cs.CartesianCS; -import org.opengis.referencing.cs.EllipsoidalCS; -import org.opengis.referencing.cs.AxisDirection; -import org.opengis.referencing.cs.CoordinateSystem; -import org.opengis.referencing.cs.CoordinateSystemAxis; +import org.opengis.referencing.NoSuchAuthorityCodeException; +import org.opengis.referencing.crs.CRSAuthorityFactory; import org.opengis.referencing.crs.CRSFactory; -import org.opengis.referencing.crs.SingleCRS; import org.opengis.referencing.crs.CompoundCRS; import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.opengis.referencing.crs.CRSAuthorityFactory; +import org.opengis.referencing.crs.EngineeringCRS; +import org.opengis.referencing.crs.GeneralDerivedCRS; import org.opengis.referencing.crs.GeodeticCRS; import org.opengis.referencing.crs.GeographicCRS; -import org.opengis.referencing.crs.GeneralDerivedCRS; import org.opengis.referencing.crs.ProjectedCRS; +import org.opengis.referencing.crs.SingleCRS; import org.opengis.referencing.crs.TemporalCRS; import org.opengis.referencing.crs.VerticalCRS; -import org.opengis.referencing.crs.EngineeringCRS; +import org.opengis.referencing.cs.AxisDirection; +import org.opengis.referencing.cs.CartesianCS; +import org.opengis.referencing.cs.CoordinateSystem; +import org.opengis.referencing.cs.CoordinateSystemAxis; +import org.opengis.referencing.cs.EllipsoidalCS; import org.opengis.referencing.datum.Datum; import org.opengis.referencing.datum.GeodeticDatum; import org.opengis.referencing.operation.Conversion; -import org.opengis.referencing.operation.OperationNotFoundException; -import org.opengis.metadata.citation.Citation; -import org.opengis.metadata.extent.Extent; -import org.opengis.metadata.extent.BoundingPolygon; -import org.opengis.metadata.extent.GeographicBoundingBox; -import org.opengis.metadata.extent.GeographicExtent; import org.opengis.referencing.operation.CoordinateOperation; +import org.opengis.referencing.operation.OperationNotFoundException; import org.opengis.referencing.operation.TransformException; -import org.apache.sis.measure.Units; +import org.opengis.util.FactoryException; + import org.apache.sis.geometry.Envelopes; import org.apache.sis.geometry.GeneralEnvelope; import org.apache.sis.internal.referencing.AxisDirections; +import org.apache.sis.internal.referencing.CoordinateOperations; +import org.apache.sis.internal.referencing.DefinitionVerifier; import org.apache.sis.internal.referencing.EllipsoidalHeightCombiner; import org.apache.sis.internal.referencing.PositionalAccuracyConstant; -import org.apache.sis.internal.referencing.CoordinateOperations; import org.apache.sis.internal.referencing.ReferencingUtilities; -import org.apache.sis.internal.referencing.DefinitionVerifier; import org.apache.sis.internal.referencing.Resources; import org.apache.sis.internal.system.DefaultFactories; -import org.apache.sis.internal.system.Modules; import org.apache.sis.internal.system.Loggers; +import org.apache.sis.internal.system.Modules; import org.apache.sis.internal.util.Numerics; -import org.apache.sis.referencing.cs.AxisFilter; -import org.apache.sis.referencing.cs.CoordinateSystems; -import org.apache.sis.referencing.cs.DefaultVerticalCS; +import org.apache.sis.measure.Units; +import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox; +import org.apache.sis.metadata.iso.extent.Extents; +import org.apache.sis.referencing.crs.DefaultCompoundCRS; +import org.apache.sis.referencing.crs.DefaultEngineeringCRS; import org.apache.sis.referencing.crs.DefaultGeographicCRS; import org.apache.sis.referencing.crs.DefaultProjectedCRS; import org.apache.sis.referencing.crs.DefaultVerticalCRS; -import org.apache.sis.referencing.crs.DefaultCompoundCRS; -import org.apache.sis.referencing.crs.DefaultEngineeringCRS; +import org.apache.sis.referencing.cs.AxisFilter; +import org.apache.sis.referencing.cs.CoordinateSystems; +import org.apache.sis.referencing.cs.DefaultVerticalCS; +import org.apache.sis.referencing.factory.GeodeticObjectFactory; +import org.apache.sis.referencing.factory.UnavailableFactoryException; import org.apache.sis.referencing.operation.AbstractCoordinateOperation; import org.apache.sis.referencing.operation.CoordinateOperationContext; -import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory; import org.apache.sis.referencing.operation.DefaultConversion; -import org.apache.sis.referencing.factory.GeodeticObjectFactory; -import org.apache.sis.referencing.factory.UnavailableFactoryException; -import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox; -import org.apache.sis.metadata.iso.extent.Extents; -import org.apache.sis.util.resources.Errors; -import org.apache.sis.util.logging.Logging; -import org.apache.sis.util.logging.WarningListener; +import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory; import org.apache.sis.util.ArgumentChecks; -import org.apache.sis.util.Utilities; import org.apache.sis.util.Static; +import org.apache.sis.util.Utilities; +import org.apache.sis.util.logging.Logging; +import org.apache.sis.util.logging.WarningListener; +import org.apache.sis.util.resources.Errors; // Branch-dependent imports -import org.opengis.geometry.Geometry; /** @@ -431,7 +433,7 @@ public final class CRS extends Static { * Suggests a coordinate reference system which could be a common target for coordinate operations having the * given sources. This method compares the {@linkplain #getGeographicBoundingBox(CoordinateReferenceSystem) * domain of validity} of all given CRSs. If a CRS has a domain of validity that contains the domain of all other - * CRS, than that CRS is returned. Otherwise this method verifies if a {@linkplain GeneralDerivedCRS#getBaseCRS() + * CRS, then that CRS is returned. Otherwise this method verifies if a {@linkplain GeneralDerivedCRS#getBaseCRS() * base CRS} (usually a {@linkplain org.apache.sis.referencing.crs.DefaultGeographicCRS geographic CRS} instance) * would be suitable. If no suitable CRS is found, then this method returns {@code null}. *
