From 2fd2451da66e6207d94939fee42da9a219168280 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Fri, 23 Feb 2024 14:52:23 -0700 Subject: [PATCH] geodesic support --- CHANGELOG.md | 1 + .../nga/index/FeatureTableCoreIndex.java | 54 ++++++++ .../rtree/RTreeIndexCoreExtension.java | 116 ++++++++++++++++++ 3 files changed, 171 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 202523d5..e40286c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Adheres to [Semantic Versioning](http://semver.org/). * R-tree update trigger modifications * DAO column range support (including geometry envelopes & bounding boxes) to build where clauses & args for queries * User Column integrated Data Columns Schema support +* RTree Index and Feature Table Index geodesic support * sf-wkb version 2.2.3 * sf-wkt version 1.2.3 * sf-proj version 4.3.2 diff --git a/src/main/java/mil/nga/geopackage/extension/nga/index/FeatureTableCoreIndex.java b/src/main/java/mil/nga/geopackage/extension/nga/index/FeatureTableCoreIndex.java index 50f1872a..0d0494b1 100644 --- a/src/main/java/mil/nga/geopackage/extension/nga/index/FeatureTableCoreIndex.java +++ b/src/main/java/mil/nga/geopackage/extension/nga/index/FeatureTableCoreIndex.java @@ -30,6 +30,7 @@ import mil.nga.proj.Projection; import mil.nga.sf.GeometryEnvelope; import mil.nga.sf.proj.GeometryTransform; +import mil.nga.sf.proj.ProjectionGeometryUtils; /** * Abstract core Feature Table Index NGA Extension implementation. This @@ -85,6 +86,13 @@ public abstract class FeatureTableCoreIndex extends BaseExtension { */ private final String columnName; + /** + * Index geometries using geodesic lines + * + * @since 6.6.7 + */ + protected boolean geodesic = false; + /** * Table Index DAO */ @@ -122,9 +130,28 @@ public abstract class FeatureTableCoreIndex extends BaseExtension { */ protected FeatureTableCoreIndex(GeoPackageCore geoPackage, String tableName, String columnName) { + this(geoPackage, tableName, columnName, false); + } + + /** + * Constructor + * + * @param geoPackage + * GeoPackage + * @param tableName + * table name + * @param columnName + * column name + * @param geodesic + * index using geodesic bounds + * @since 6.6.7 + */ + protected FeatureTableCoreIndex(GeoPackageCore geoPackage, String tableName, + String columnName, boolean geodesic) { super(geoPackage); this.tableName = tableName; this.columnName = columnName; + this.geodesic = geodesic; tableIndexDao = getTableIndexDao(); geometryIndexDao = getGeometryIndexDao(); } @@ -164,6 +191,27 @@ public String getColumnName() { return columnName; } + /** + * Geometries indexed using geodesic lines + * + * @return geodesic flag + * @since 6.6.7 + */ + public boolean isGeodesic() { + return geodesic; + } + + /** + * Set the geodestic flag, true to index geodesic geometries + * + * @param geodesic + * index geodesic geometries flag + * @since 6.6.7 + */ + public void setGeodesic(boolean geodesic) { + this.geodesic = geodesic; + } + /** * Set the progress tracker * @@ -278,6 +326,12 @@ protected boolean index(TableIndex tableIndex, long geomId, // Create the new index row if (envelope != null) { + + if (geodesic) { + envelope = ProjectionGeometryUtils + .geodesicEnvelope(envelope, getProjection()); + } + GeometryIndex geometryIndex = geometryIndexDao .populate(tableIndex, geomId, envelope); try { diff --git a/src/main/java/mil/nga/geopackage/extension/rtree/RTreeIndexCoreExtension.java b/src/main/java/mil/nga/geopackage/extension/rtree/RTreeIndexCoreExtension.java index fe03a3af..b1e87743 100644 --- a/src/main/java/mil/nga/geopackage/extension/rtree/RTreeIndexCoreExtension.java +++ b/src/main/java/mil/nga/geopackage/extension/rtree/RTreeIndexCoreExtension.java @@ -2,7 +2,11 @@ import java.sql.SQLException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; import mil.nga.geopackage.GeoPackageConstants; import mil.nga.geopackage.GeoPackageCore; @@ -17,9 +21,12 @@ import mil.nga.geopackage.geom.GeoPackageGeometryData; import mil.nga.geopackage.property.GeoPackageProperties; import mil.nga.geopackage.property.PropertyConstants; +import mil.nga.geopackage.srs.SpatialReferenceSystem; import mil.nga.geopackage.user.custom.UserCustomColumn; import mil.nga.geopackage.user.custom.UserCustomTable; +import mil.nga.proj.Projection; import mil.nga.sf.GeometryEnvelope; +import mil.nga.sf.proj.ProjectionGeometryUtils; /** * RTree Index abstract core extension @@ -32,6 +39,12 @@ */ public abstract class RTreeIndexCoreExtension extends BaseExtension { + /** + * Logger + */ + private static final Logger log = Logger + .getLogger(RTreeIndexCoreExtension.class.getName()); + /** * Name */ @@ -252,6 +265,20 @@ public abstract class RTreeIndexCoreExtension extends BaseExtension { */ protected GeoPackageCoreConnection connection = null; + /** + * Index geometries using geodesic lines + * + * @since 6.6.7 + */ + protected boolean geodesic = false; + + /** + * Mapping between srs ids and projections + * + * @since 6.6.7 + */ + protected Map projections = new HashMap<>(); + /** * Constructor * @@ -260,8 +287,97 @@ public abstract class RTreeIndexCoreExtension extends BaseExtension { * */ protected RTreeIndexCoreExtension(GeoPackageCore geoPackage) { + this(geoPackage, false); + } + + /** + * Constructor + * + * @param geoPackage + * GeoPackage + * @param geodesic + * index using geodesic bounds + * @since 6.6.7 + * + */ + protected RTreeIndexCoreExtension(GeoPackageCore geoPackage, + boolean geodesic) { super(geoPackage); connection = geoPackage.getDatabase(); + this.geodesic = geodesic; + } + + /** + * Geometries indexed using geodesic lines + * + * @return geodesic flag + * @since 6.6.7 + */ + public boolean isGeodesic() { + return geodesic; + } + + /** + * Set the geodestic flag, true to index geodesic geometries + * + * @param geodesic + * index geodesic geometries flag + * @since 6.6.7 + */ + public void setGeodesic(boolean geodesic) { + this.geodesic = geodesic; + } + + /** + * Expand the vertical bounds of a geometry envelope by geodesic bounds + * + * @param envelope + * geometry envelope + * @param srsId + * spatial reference system id + * @return geometry envelope + * @since 6.6.7 + */ + protected GeometryEnvelope geodesicEnvelope(GeometryEnvelope envelope, + int srsId) { + + GeometryEnvelope result = envelope; + if (geodesic) { + Projection projection = getProjection(srsId); + result = ProjectionGeometryUtils.geodesicEnvelope(envelope, + projection); + } + + return result; + } + + /** + * Get the projection of the spatial reference system id + * + * @param srsId + * spatial reference system id + * @return projection + * @since 6.6.7 + */ + protected Projection getProjection(int srsId) { + Projection projection = projections.get(srsId); + if (projection == null) { + try { + SpatialReferenceSystem srs = geoPackage + .getSpatialReferenceSystemDao() + .queryForId((long) srsId); + if (srs != null) { + projection = srs.getProjection(); + projections.put(srsId, projection); + } + } catch (SQLException e) { + log.log(Level.WARNING, + "Failed to retrieve projection through querying srs id: " + + srsId, + e); + } + } + return projection; } /**