You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by am...@apache.org on 2019/11/12 16:45:00 UTC
[sis] 33/45: WIP(Feature): start adding CRS resolution strategy for
filter operations.
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 <am...@apache.org>
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}.
*