GeoPackage Support
简介
本文档解释了 GeoTools 对 GeoPackage 标准的实现,这是一种开放、基于标准、平台独立、可移植、自包含的地理空间信息数据格式。GeoPackage 是一个 SQLite 容器,允许您存储矢量要素和栅格数据图块,使其成为地理空间应用的多功能格式。
GeoTools 提供对读取和写入 GeoPackage 文件的全面支持,包括处理要素(矢量数据)、图块(栅格数据)、元数据和各种 GeoPackage 扩展。
- modules/plugin/geopkg/src/main/java/org/geotools/geopkg/GeoPackage.java
- modules/plugin/geopkg/src/main/java/org/geotools/geopkg/GeoPkgDialect.java
GeoTools 中的 GeoPackage 架构
GeoTools 中的 GeoPackage 支持主要通过 geopkg 模块实现,该模块通过 GeoPackage 特定的处理扩展了 JDBC 框架。
架构概述
核心组件
- GeoPkgDataStoreFactory: 创建 GeoPackage 数据存储实例
- GeoPackage: 直接与 GeoPackage 文件交互的主类
- GeoPkgDialect: 处理 SQL 转换、几何编码/解码和其他 SQLite 特定操作
- FeatureEntry/TileEntry: 要素和图块数据集的元数据
- Extensions: 支持标准 GeoPackage 扩展
- modules/plugin/geopkg/src/main/java/org/geotools/geopkg/GeoPkgDataStoreFactory.java
- modules/plugin/geopkg/src/main/java/org/geotools/geopkg/GeoPackage.java
- modules/plugin/geopkg/src/main/java/org/geotools/geopkg/GeoPkgDialect.java
GeoPackage 数据模型
标准表
GeoPackage 格式定义了几个标准表:
| 表 | 用途 |
|---|---|
gpkg_contents | 列出 GeoPackage 中的所有要素和图块数据集 |
gpkg_spatial_ref_sys | 定义空间参考系统 |
gpkg_geometry_columns | 描述要素表中的几何列 |
gpkg_tile_matrix_set | 定义图块矩阵集范围 |
gpkg_tile_matrix | 定义每个缩放级别的参数 |
gpkg_extensions | 注册 GeoPackage 中使用的扩展 |
用户数据表
要素表: 存储具有属性和几何图形的矢量要素
图块表: 存储具有缩放级别、行和列的平铺栅格数据
modules/plugin/geopkg/src/main/java/org/geotools/geopkg/GeoPackage.java107-129
modules/plugin/geopkg/src/test/java/org/geotools/geopkg/GeoPackageTest.java143-148
要素支持
要素读取和写入
要素数据类型
GeoTools 为 GeoPackage 中的各种数据类型提供特定处理:
- 几何图形: 全面支持所有 OGC 几何类型,包括 3D 几何图形
- 基本类型: Integer、Double、String、Boolean 等
- 日期/时间: 支持 Date、Time 和 Timestamp 数据类型
- 枚举: 支持存储和检索枚举值
- 数组: 支持以 JSON 字符串形式存储的数组类型
空间索引
GeoTools 实现了 GeoPackage R-Tree 空间索引扩展,以提高空间查询性能:
在 SQLite 中创建 R-Tree 虚拟表
设置触发器以在数据更改时维护索引
使用索引进行空间查询,如 bbox 和相交
modules/library/jdbc/src/main/java/org/geotools/jdbc/JDBCFeatureReader.java
modules/plugin/geopkg/src/main/java/org/geotools/geopkg/GeoPkgDialect.java
modules/plugin/geopkg/src/main/resources/org/geotools/geopkg/gpkg_spatial_index.sql
图块支持
GeoTools 通过 GeoPackageReader 和相关类支持读取和写入 GeoPackage 中的平铺栅格数据。
图块读取管道
缩放级别和分辨率
GeoPackage 在具有不同分辨率的缩放级别中组织图块。GeoTools 提供以下方法:
根据请求的分辨率选择适当的缩放级别
将多个缩放级别作为内部概览处理
在同一数据集中支持不同的图块格式(PNG、JPEG)
modules/plugin/geopkg/src/main/java/org/geotools/geopkg/mosaic/GeoPackageReader.java
modules/plugin/geopkg/src/main/java/org/geotools/geopkg/TileMatrix.java
modules/plugin/geopkg/src/test/java/org/geotools/geopkg/mosaic/GeoPackageReaderTest.java
扩展支持
GeoTools 支持几个 GeoPackage 扩展:
空间索引扩展
实现 R-Tree 空间索引扩展,用于对要素数据进行更快的空间查询。使用以下方法创建空间索引:
geoPackage.createSpatialIndex(featureEntry);模式扩展
模式扩展提供有关列和约束的附加元数据,通过 GeoPkgSchemaExtension 类实现:
- 列描述: 为列添加标题、描述和 MIME 类型
- 约束: 为列定义枚举值、范围或模式
- 枚举支持: 在存储代码和可读值之间映射
DataColumn dc = new DataColumn();
dc.setColumnName("enumProperty");
dc.setConstraint(new DataColumnConstraint.Enum("constraint_name", enumValues));
geopkg.getExtension(GeoPkgSchemaExtension.class).addDataColumn(tableName, dc, connection);- modules/plugin/geopkg/src/main/java/org/geotools/geopkg/GeoPkgSchemaExtension.java
- modules/plugin/geopkg/src/test/java/org/geotools/geopkg/GeoPkgEnumTest.java
特殊数据类型处理
日期和时间
GeoPackage 将日期和时间值以 ISO-8601 格式的文本字符串存储。GeoTools 为以下内容提供特殊处理:
java.sql.Date用于 DATE 列java.sql.Timestamp用于 DATETIME 列java.sql.Time用于 TIME 列
GeoPkgDialect 确保在 SQLite 字符串和 Java 日期对象之间进行正确的时区处理。
枚举
GeoTools 通过以下方式支持枚举值:
- 要素类型选项:
builder.options("one", "two", "three") - 通过模式扩展的显式枚举约束
- 存储代码和可读值之间的自动转换
数组
GeoPackage 本身不支持数组类型,但 GeoTools 通过以下方式实现数组支持:
- 将数组作为 JSON 字符串存储在数据库中
- 在模式扩展中将 MIME 类型设置为 "application/json"
- 在 JSON 和 Java 数组之间自动转换
- modules/plugin/geopkg/src/main/java/org/geotools/geopkg/GeoPkgDialect.java663-721
- modules/plugin/geopkg/src/test/java/org/geotools/geopkg/GeoPkgDatetimeTest.java
- modules/plugin/geopkg/src/test/java/org/geotools/geopkg/GeoPkgEnumTest.java
- modules/plugin/geopkg/src/main/java/org/geotools/geopkg/JSONArrayIO.java
筛选和查询
GeoPackage 通过 GeoPkgFilterToSQL 类支持标准 GeoTools 筛选功能,该类将 Filter 对象转换为 SQL:
空间筛选器
BBOX 和 Intersects 等空间筛选器优化为使用:
- 可用时使用空间索引
- 使用空间函数(ST_MinX、ST_MaxX 等)作为后备
属性筛选器
全面支持:
- 比较筛选器(=、<、>、BETWEEN、LIKE)
- 逻辑筛选器(AND、OR、NOT)
- 日期/时间比较的特殊处理
查询性能
GeoTools 为 GeoPackage 查询实现了几个优化:
空间索引利用
预准备语句
连接池
查询限制和偏移
modules/plugin/geopkg/src/main/java/org/geotools/geopkg/GeoPkgFilterToSQL.java
modules/plugin/geopkg/src/main/java/org/geotools/geopkg/GeoPkgDialect.java796-854
使用示例
从 GeoPackage 读取要素
// 打开 GeoPackage 文件
File file = new File("example.gpkg");
Map<String, Object> params = new HashMap<>();
params.put(GeoPkgDataStoreFactory.DBTYPE.key, "geopkg");
params.put(GeoPkgDataStoreFactory.DATABASE.key, file);
// 创建数据存储
DataStore dataStore = DataStoreFinder.getDataStore(params);
// 获取要素源
String typeName = dataStore.getTypeNames()[0];
SimpleFeatureSource featureSource = dataStore.getFeatureSource(typeName);
// 读取要素
SimpleFeatureCollection features = featureSource.getFeatures();向 GeoPackage 写入要素
// 创建新的 GeoPackage 文件
File file = new File("new.gpkg");
GeoPackage geopkg = new GeoPackage(file);
geopkg.init();
// 创建要素条目
FeatureEntry entry = new FeatureEntry();
entry.setTableName("features");
entry.setSrid(4326);
entry.setBounds(new ReferencedEnvelope(-180, 180, -90, 90, CRS.decode("EPSG:4326")));
// 将要素添加到 GeoPackage
geopkg.add(entry, featureCollection);
// 创建空间索引
geopkg.createSpatialIndex(entry);
geopkg.close();读取图块
// 打开带有图块的 GeoPackage
GeoPackageReader reader = new GeoPackageReader(file, null);
// 设置读取参数
GridGeometry2D gg = new GridGeometry2D(
new GridEnvelope2D(new Rectangle(1000, 500)),
new ReferencedEnvelope(-180, 180, -90, 90, CRS.decode("EPSG:4326"))
);
ParameterValue<GridGeometry2D> param = AbstractGridFormat.READ_GRIDGEOMETRY2D.createValue();
param.setValue(gg);
// 将图块作为 GridCoverage2D 读取
GridCoverage2D coverage = reader.read("tile_layer", new GeneralParameterValue[] { param });- modules/plugin/geopkg/src/test/java/org/geotools/geopkg/GeoPackageTest.java
- modules/plugin/geopkg/src/test/java/org/geotools/geopkg/mosaic/GeoPackageReaderTest.java
限制和考虑
- 版本兼容性: GeoTools 实现 GeoPackage 1.2 规范
- 性能: 对于非常大的数据集,请考虑使用空间索引
- 内存使用: 对于大区域,图块读取可能会占用大量内存
- SQLite 限制: 记住 SQLite 的并发访问限制