Skip to content

Commit

Permalink
geodesic support
Browse files Browse the repository at this point in the history
  • Loading branch information
bosborn committed Apr 2, 2024
1 parent 2a08d9f commit 478a24f
Show file tree
Hide file tree
Showing 38 changed files with 587 additions and 56 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Adheres to [Semantic Versioning](http://semver.org/).
* Get abstract User DAO by table name
* Set User Custom DAO contents
* Get Tile Overlays and Bounded Overlays by tile table, feature table, or user DAO
* Feature Tiles geodesic draw support
* Feature Index Manager, RTree Index, Feature Table Index, Feature Indexer, and Manual query geodesic support

## [8.0.4](https://github.com/ngageoint/geopackage-ios/releases/tag/8.0.4) (11-15-2023)

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ GPKGBoundingBox *boundingBox = [GPKGBoundingBox worldWebMercator];
PROJProjection *projection = [PROJProjectionFactory projectionWithEpsgInt:PROJ_EPSG_WEB_MERCATOR];

// Index Features
GPKGFeatureIndexManager *indexer = [[GPKGFeatureIndexManager alloc] initWithGeoPackage:geoPackage andFeatureDao:featureDao];
GPKGFeatureIndexManager *indexer = [[GPKGFeatureIndexManager alloc] initWithGeoPackage:geoPackage andFeatureDao:featureDao andGeodesic:NO];
[indexer setIndexLocation:GPKG_FIT_RTREE];
int indexedCount = [indexer index];

Expand All @@ -185,7 +185,7 @@ GPKGRowPaginatedResults *paginatedResults = [indexer paginate:indexResults];
}

// Feature Tile Overlay (dynamically draw tiles from features)
GPKGFeatureTiles *featureTiles = [[GPKGFeatureTiles alloc] initWithFeatureDao:featureDao];
GPKGFeatureTiles *featureTiles = [[GPKGFeatureTiles alloc] initWithFeatureDao:featureDao andGeodesic:NO];
[featureTiles setMaxFeaturesPerTile:[NSNumber numberWithInt:1000]];
GPKGNumberFeaturesTile *numberFeaturesTile = [[GPKGNumberFeaturesTile alloc] init];
[featureTiles setMaxFeaturesTileDraw:numberFeaturesTile];
Expand Down
25 changes: 25 additions & 0 deletions geopackage-ios/db/GPKGFeatureIndexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@
*/
-(instancetype)initWithFeatureDao:(GPKGFeatureDao *) featureDao;

/**
* Initialize
*
* @param featureDao feature DAO
* @param geodesic index using geodesic bounds
*
* @return new feature indexer
*/
-(instancetype)initWithFeatureDao:(GPKGFeatureDao *) featureDao andGeodesic: (BOOL) geodesic;

/**
* Get the primary key column name
*
Expand All @@ -50,6 +60,21 @@
*/
-(void) close;

/**
* Geometries indexed using geodesic lines
*
* @return geodesic flag
*/
-(BOOL) isGeodesic;

/**
* Set the geodestic flag, true to index geodesic geometries
*
* @param geodesic
* index geodesic geometries flag
*/
-(void) setGeodesic: (BOOL) geodesic;

/**
* Index the feature table if needed
*
Expand Down
14 changes: 13 additions & 1 deletion geopackage-ios/db/GPKGFeatureIndexer.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,16 @@ @interface GPKGFeatureIndexer()
@implementation GPKGFeatureIndexer

-(instancetype)initWithFeatureDao:(GPKGFeatureDao *) featureDao{
return [self initWithFeatureDao:featureDao andGeodesic:NO];
}

-(instancetype)initWithFeatureDao:(GPKGFeatureDao *) featureDao andGeodesic: (BOOL) geodesic{
self = [super init];
if(self){
self.featureDao = featureDao;
self.featureRowSync = [[GPKGUserRowSync alloc] init];
self.db = featureDao.metadataDb;
self.geometryMetadataDataSource = [self.db geometryMetadataDao];
self.geometryMetadataDataSource = [self.db geometryMetadataDaoWithGeodesic:geodesic andProjection:[featureDao projection]];
self.chunkLimit = 1000;
}
return self;
Expand All @@ -42,6 +46,14 @@ -(void) close{

}

-(BOOL) isGeodesic{
return self.geometryMetadataDataSource.geodesic;
}

-(void) setGeodesic: (BOOL) geodesic{
[self.geometryMetadataDataSource setGeodesic:geodesic];
}

-(int) index{
return [self indexWithForce:NO];
}
Expand Down
21 changes: 21 additions & 0 deletions geopackage-ios/db/metadata/GPKGGeometryMetadataDao.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@
*/
@property (nonatomic) double tolerance;

/**
* Index geometries using geodesic lines
*/
@property (nonatomic) BOOL geodesic;

/**
* Features projection
*/
@property (nonatomic, strong) PROJProjection *projection;

/**
* Initialize
*
Expand All @@ -28,6 +38,17 @@
*/
-(instancetype) initWithDatabase: (GPKGConnection *) database;

/**
* Initialize
*
* @param database database connection
* @param geodesic index geodesic geometries flag
* @param projection feature projection
*
* @return new Geometry Metadata DAO
*/
-(instancetype) initWithDatabase: (GPKGConnection *) database andGeodesic: (BOOL) geodesic andProjection: (PROJProjection *) projection;

/**
* Create geometry metadata
*
Expand Down
11 changes: 11 additions & 0 deletions geopackage-ios/db/metadata/GPKGGeometryMetadataDao.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@
#import "GPKGGeoPackageMetadataDao.h"
#import "GPKGUtils.h"
#import "GPKGSqlUtils.h"
#import "SFPProjectionGeometryUtils.h"

@implementation GPKGGeometryMetadataDao

-(instancetype) initWithDatabase: (GPKGConnection *) database{
return [self initWithDatabase:database andGeodesic:NO andProjection:nil];
}

-(instancetype) initWithDatabase: (GPKGConnection *) database andGeodesic: (BOOL) geodesic andProjection: (PROJProjection *) projection{
self = [super initWithDatabase:database];
if(self != nil){
self. geodesic = geodesic;
self.projection = projection;
self.tableName = GPKG_GPGM_TABLE_NAME;
self.idColumns = @[GPKG_GPGM_COLUMN_PK1, GPKG_GPGM_COLUMN_PK2, GPKG_GPGM_COLUMN_PK3];
self.columnNames = @[GPKG_GPGM_COLUMN_GEOPACKAGE_ID, GPKG_GPGM_COLUMN_TABLE_NAME, GPKG_GPGM_COLUMN_ID, GPKG_GPGM_COLUMN_MIN_X, GPKG_GPGM_COLUMN_MAX_X, GPKG_GPGM_COLUMN_MIN_Y, GPKG_GPGM_COLUMN_MAX_Y, GPKG_GPGM_COLUMN_MIN_Z, GPKG_GPGM_COLUMN_MAX_Z, GPKG_GPGM_COLUMN_MIN_M, GPKG_GPGM_COLUMN_MAX_M];
Expand Down Expand Up @@ -465,6 +472,10 @@ -(NSArray *) querySQLArgsWithEnvelope: (SFGeometryEnvelope *) envelope andGeoPac

BOOL minXLessThanMaxX = [envelope.minX compare:envelope.maxX] != NSOrderedDescending;

if(_geodesic){
envelope = [SFPProjectionGeometryUtils geodesicEnvelope:envelope inProjection:_projection];
}

NSDecimalNumber *minX = [[NSDecimalNumber alloc] initWithDouble:[envelope.minX doubleValue] - self.tolerance];
NSDecimalNumber *maxX = [[NSDecimalNumber alloc] initWithDouble:[envelope.maxX doubleValue] + self.tolerance];
NSDecimalNumber *minY = [[NSDecimalNumber alloc] initWithDouble:[envelope.minY doubleValue] - self.tolerance];
Expand Down
10 changes: 10 additions & 0 deletions geopackage-ios/db/metadata/GPKGMetadataDb.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@
*/
-(GPKGGeometryMetadataDao *) geometryMetadataDao;

/**
* Get a Geometry Metadata DAO
*
* @param geodesic index geodesic geometries flag
* @param projection feature projection
*
* @return Geometry Metadata DAO
*/
-(GPKGGeometryMetadataDao *) geometryMetadataDaoWithGeodesic: (BOOL) geodesic andProjection: (PROJProjection *) projection;

/**
* Delete the metadata database file
*
Expand Down
4 changes: 4 additions & 0 deletions geopackage-ios/db/metadata/GPKGMetadataDb.m
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ -(GPKGGeometryMetadataDao *) geometryMetadataDao{
return [[GPKGGeometryMetadataDao alloc] initWithDatabase:self.connection];
}

-(GPKGGeometryMetadataDao *) geometryMetadataDaoWithGeodesic: (BOOL) geodesic andProjection: (PROJProjection *) projection{
return [[GPKGGeometryMetadataDao alloc] initWithDatabase:self.connection andGeodesic:geodesic andProjection:projection];
}

+(BOOL) deleteMetadataFile{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
Expand Down
16 changes: 16 additions & 0 deletions geopackage-ios/extension/nga/index/GPKGFeatureTableIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ extern NSString * const GPKG_PROP_EXTENSION_GEOMETRY_INDEX_DEFINITION;
*/
@property (nonatomic) double tolerance;

/**
* Index geometries using geodesic lines
*/
@property (nonatomic) BOOL geodesic;

/**
* Initialize
*
Expand All @@ -51,6 +56,17 @@ extern NSString * const GPKG_PROP_EXTENSION_GEOMETRY_INDEX_DEFINITION;
*/
-(instancetype) initWithGeoPackage: (GPKGGeoPackage *) geoPackage andFeatureDao: (GPKGFeatureDao *) featureDao;

/**
* Initialize
*
* @param geoPackage GeoPackage
* @param featureDao feature data access object
* @param geodesic index using geodesic bounds
*
* @return new feature table index
*/
-(instancetype) initWithGeoPackage: (GPKGGeoPackage *) geoPackage andFeatureDao: (GPKGFeatureDao *) featureDao andGeodesic: (BOOL) geodesic;

/**
* Get the Feature DAO
*
Expand Down
11 changes: 11 additions & 0 deletions geopackage-ios/extension/nga/index/GPKGFeatureTableIndex.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#import "GPKGSqlLiteQueryBuilder.h"
#import "GPKGGeometryIndexTableCreator.h"
#import "GPKGNGAExtensions.h"
#import "SFPProjectionGeometryUtils.h"

NSString * const GPKG_EXTENSION_GEOMETRY_INDEX_NAME_NO_AUTHOR = @"geometry_index";
NSString * const GPKG_PROP_EXTENSION_GEOMETRY_INDEX_DEFINITION = @"geopackage.extensions.geometry_index";
Expand All @@ -32,6 +33,10 @@ @interface GPKGFeatureTableIndex ()
@implementation GPKGFeatureTableIndex

-(instancetype) initWithGeoPackage: (GPKGGeoPackage *) geoPackage andFeatureDao: (GPKGFeatureDao *) featureDao{
return [self initWithGeoPackage:geoPackage andFeatureDao:featureDao andGeodesic:NO];
}

-(instancetype) initWithGeoPackage: (GPKGGeoPackage *) geoPackage andFeatureDao: (GPKGFeatureDao *) featureDao andGeodesic: (BOOL) geodesic{
self = [super initWithGeoPackage:geoPackage];
if(self != nil){
self.featureDao = featureDao;
Expand All @@ -40,6 +45,7 @@ -(instancetype) initWithGeoPackage: (GPKGGeoPackage *) geoPackage andFeatureDao:
self.extensionDefinition = [GPKGProperties valueOfProperty:GPKG_PROP_EXTENSION_GEOMETRY_INDEX_DEFINITION];
self.tableName = featureDao.tableName;
self.columnName = [featureDao geometryColumnName];
self.geodesic = geodesic;
self.tableIndexDao = [self tableIndexDao];
self.geometryIndexDao = [self geometryIndexDao];
self.chunkLimit = 1000;
Expand Down Expand Up @@ -172,6 +178,11 @@ -(BOOL) indexTableIndex: (GPKGTableIndex *) tableIndex withGeomId: (int) geomId

// Create the new index row
if(envelope != nil){

if(_geodesic){
envelope = [SFPProjectionGeometryUtils geodesicEnvelope:envelope inProjection:[self projection]];
}

GPKGGeometryIndex *geometryIndex = [self.geometryIndexDao populateWithTableIndex:tableIndex andGeomId:geomId andEnvelope:envelope];
[self.geometryIndexDao createOrUpdate:geometryIndex];
indexed = YES;
Expand Down
15 changes: 15 additions & 0 deletions geopackage-ios/extension/rtree/GPKGRTreeIndexExtension.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ extern NSString * const GPKG_RTREE_INDEX_EXTENSION_COLUMN_MAX_Y;
*/
@property (nonatomic, strong) NSString *definition;

/**
* Index geometries using geodesic lines
*/
@property (nonatomic) BOOL geodesic;

/**
* Initialize
*
Expand All @@ -45,6 +50,16 @@ extern NSString * const GPKG_RTREE_INDEX_EXTENSION_COLUMN_MAX_Y;
*/
-(instancetype) initWithGeoPackage: (GPKGGeoPackage *) geoPackage;

/**
* Initialize
*
* @param geoPackage GeoPackage
* @param geodesic index using geodesic bounds
*
* @return new instance
*/
-(instancetype) initWithGeoPackage: (GPKGGeoPackage *) geoPackage andGeodesic: (BOOL) geodesic;

/**
* Get a RTree Index Table DAO for the feature table
*
Expand Down
54 changes: 54 additions & 0 deletions geopackage-ios/extension/rtree/GPKGRTreeIndexExtension.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import "GPKGRTreeIndexExtension.h"
#import "GPKGProperties.h"
#import "GPKGIOUtils.h"
#import "SFPProjectionGeometryUtils.h"

NSString * const GPKG_RTREE_INDEX_EXTENSION_NAME = @"rtree_index";
NSString * const GPKG_RTREE_INDEX_PREFIX = @"rtree_";
Expand Down Expand Up @@ -57,15 +58,22 @@ @interface GPKGRTreeIndexExtension()
@property (nonatomic, strong) NSString *geometryColumnSubstitute;
@property (nonatomic, strong) NSString *pkColumnSubstitute;
@property (nonatomic, strong) NSString *triggerSubstitute;
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, PROJProjection *> *projections;

@end

@implementation GPKGRTreeIndexExtension

-(instancetype) initWithGeoPackage: (GPKGGeoPackage *) geoPackage{
return [self initWithGeoPackage:geoPackage andGeodesic:NO];
}

-(instancetype) initWithGeoPackage: (GPKGGeoPackage *) geoPackage andGeodesic: (BOOL) geodesic{
self = [super initWithGeoPackage:geoPackage];
if(self != nil){
self.connection = geoPackage.database;
self.geodesic = geodesic;
self.projections = [NSMutableDictionary dictionary];
self.extensionName = [GPKGExtensions buildDefaultAuthorExtensionName:GPKG_RTREE_INDEX_EXTENSION_NAME];
self.definition = [GPKGProperties valueOfProperty:GPKG_PROP_RTREE_INDEX_EXTENSION_DEFINITION];

Expand Down Expand Up @@ -258,6 +266,50 @@ -(GPKGUserCustomTable *) rTreeTableWithFeatureTable: (GPKGFeatureTable *) featur
return userCustomTable;
}

/**
* Expand the vertical bounds of a geometry envelope by geodesic bounds
*
* @param envelope
* geometry envelope
* @param srsId
* spatial reference system id
* @return geometry envelope
*/
-(SFGeometryEnvelope *) geodesicEnvelope: (SFGeometryEnvelope *) envelope withSrsId: (int) srsId{

SFGeometryEnvelope *result = envelope;
if(_geodesic){
PROJProjection *projection = [self projectionWithSrsId:srsId];
result = [SFPProjectionGeometryUtils geodesicEnvelope:envelope inProjection:projection];
}

return result;
}

/**
* Get the projection of the spatial reference system id
*
* @param srsId
* spatial reference system id
* @return projection
*/
-(PROJProjection *) projectionWithSrsId: (int) srsId{
NSNumber *srsIdNumber = [NSNumber numberWithInt:srsId];
PROJProjection *projection = [_projections objectForKey:srsIdNumber];
if(projection == nil){
@try {
GPKGSpatialReferenceSystem *srs = (GPKGSpatialReferenceSystem *)[[self.geoPackage spatialReferenceSystemDao] queryForIdObject:srsIdNumber];
if(srs != nil){
projection = [srs projection];
[_projections setObject:projection forKey:srsIdNumber];
}
} @catch (NSException *exception) {
NSLog(@"Failed to retrieve projection through querying srs id: %d, error: %@", srsId, exception);
}
}
return projection;
}

/**
* Min X SQL function
*/
Expand All @@ -272,6 +324,7 @@ void minXFunction (sqlite3_context *context, int argc, sqlite3_value **argv) {
*/
void minYFunction (sqlite3_context *context, int argc, sqlite3_value **argv) {
GPKGGeometryData *data = [GPKGRTreeIndexExtension geometryDataFunctionWithCount:argc andArguments:argv];
// TODO Support geodesic indexing by calling geodesicEnvelope with an instance reference to this GPGKRTreeIndexExtension?
NSDecimalNumber *minY = [GPKGRTreeIndexExtension envelopeOfGeometryData:data].minY;
sqlite3_result_double(context, [minY doubleValue]);
}
Expand All @@ -290,6 +343,7 @@ void maxXFunction (sqlite3_context *context, int argc, sqlite3_value **argv) {
*/
void maxYFunction (sqlite3_context *context, int argc, sqlite3_value **argv) {
GPKGGeometryData *data = [GPKGRTreeIndexExtension geometryDataFunctionWithCount:argc andArguments:argv];
// TODO Support geodesic indexing by calling geodesicEnvelope with an instance reference to this GPGKRTreeIndexExtension?
NSDecimalNumber *maxY = [GPKGRTreeIndexExtension envelopeOfGeometryData:data].maxY;
sqlite3_result_double(context, [maxY doubleValue]);
}
Expand Down

0 comments on commit 478a24f

Please sign in to comment.