Source code for reVX.handlers.geopackage
# -*- coding: utf-8 -*-
"""
GeoPackage Handlers
"""
from functools import cached_property
import pyproj
import sqlite3
[docs]class GPKGMeta:
"""Extract meta info about underlying GeoPackage SQL tables."""
def __init__(self, filename):
"""
Parameters
----------
filename : path-like
Path to input GeoPackage.
"""
self.filename = filename
@cached_property
def primary_table(self):
"""str: Name of table containing user data."""
with sqlite3.connect(self.filename) as con:
cursor = con.cursor()
cursor.execute("SELECT table_name FROM gpkg_contents")
return cursor.fetchall()[0][0]
@cached_property
def srs_id(self):
"""int: Spatial reference system ID (4326, 3857, etc.)"""
with sqlite3.connect(self.filename) as con:
cursor = con.cursor()
cursor.execute("SELECT srs_id FROM gpkg_contents")
return cursor.fetchall()[0][0]
@cached_property
def crs(self):
"""pyproj.crs.CRS: Coordinate Reference System for GeoPackage."""
with sqlite3.connect(self.filename) as con:
cursor = con.cursor()
cursor.execute("SELECT definition FROM gpkg_spatial_ref_sys "
"WHERE srs_id={}".format(self.srs_id))
proj = cursor.fetchall()[0][0]
return pyproj.Proj(proj).crs
@cached_property
def bbox(self):
"""tuple: MIN_X, MIN_Y, MAX_X, MAX_Y values for GeoPackage. """
with sqlite3.connect(self.filename) as con:
cursor = con.cursor()
cursor.execute("SELECT min_x, min_y, max_x, max_y "
"FROM gpkg_contents;")
return cursor.fetchall()[0]
@cached_property
def primary_key_column(self):
"""str: Name of the primary key column in the user data table. """
with sqlite3.connect(self.filename) as con:
cursor = con.cursor()
cursor.execute("PRAGMA table_info({})"
.format(self.primary_table))
pragma = cursor.fetchall()
pk_name = [info[1] for info in pragma if info[-1]]
assert len(pk_name) == 1, "Found multiple Primary Key columns"
return pk_name[0]
@cached_property
def geom_table_suffix(self):
"""str: Name of the geometry table suffix."""
with sqlite3.connect(self.filename) as con:
cursor = con.cursor()
cursor.execute("SELECT table_name, column_name FROM "
"gpkg_geometry_columns;")
return "_".join(cursor.fetchall()[0])
@cached_property
def num_feats(self):
"""int: Number of feature rows."""
with sqlite3.connect(self.filename) as con:
cursor = con.cursor()
cursor.execute("SELECT COUNT(distinct id) FROM "
"rtree_{table_suffix};"
.format(table_suffix=self.geom_table_suffix))
return cursor.fetchall()[0][0]
@cached_property
def feat_ids(self):
"""tuple: All the feature ID's in the GeoPackage. """
with sqlite3.connect(self.filename) as con:
cursor = con.cursor()
cursor.execute("PRAGMA temp_store=2")
cursor.execute("SELECT distinct id FROM rtree_{table_suffix} "
"ORDER BY miny, minx"
.format(table_suffix=self.geom_table_suffix))
return tuple(id_[0] for id_ in cursor.fetchall())
[docs] def feat_ids_for_bbox(self, bbox):
"""Find the ID's of the features within the input bounding box.
Parameters
----------
bbox : list | tuple | iterable
Container with four int/float values describing the bounding
box. The values should be in the following order:
``MIN_X, MIN_Y, MAX_X, MAX_Y``
Returns
-------
ids : tuple
Tuple of all the feature IDs within the given input bounding
box.
"""
minx, miny, maxx, maxy = bbox
with sqlite3.connect(self.filename) as con:
cursor = con.cursor()
cursor.execute("SELECT distinct id FROM rtree_{table_suffix} "
"WHERE minx<={maxx} and maxx>={minx} "
"and miny<={maxy} and maxy>={miny} "
"ORDER BY miny, minx"
.format(table_suffix=self.geom_table_suffix,
maxx=maxx, minx=minx, maxy=maxy, miny=miny))
ids = tuple(id_[0] for id_ in cursor.fetchall())
return ids