UNPKG

@loaders.gl/geopackage

Version:

GeoPackage data loaders

311 lines (307 loc) 9.69 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // dist/index.js var dist_exports = {}; __export(dist_exports, { GeoPackageLoader: () => GeoPackageLoader }); module.exports = __toCommonJS(dist_exports); // dist/lib/parse-geopackage.js var import_loader_utils = require("@loaders.gl/loader-utils"); var import_wkt = require("@loaders.gl/wkt"); var import_gis = require("@loaders.gl/gis"); var import_proj4 = require("@math.gl/proj4"); var import_sql = __toESM(require("sql.js"), 1); var SQL_JS_VERSION = "1.8.0"; var DEFAULT_SQLJS_CDN = import_loader_utils.isBrowser ? `https://cdnjs.cloudflare.com/ajax/libs/sql.js/${SQL_JS_VERSION}/` : null; var ENVELOPE_BYTE_LENGTHS = { 0: 0, 1: 32, 2: 48, 3: 48, 4: 64, // values 5-7 are invalid and _should_ never show up 5: 0, 6: 0, 7: 0 }; var SQL_TYPE_MAPPING = { BOOLEAN: "bool", TINYINT: "int8", SMALLINT: "int16", MEDIUMINT: "int32", INT: "int32", INTEGER: "int32", FLOAT: "float32", DOUBLE: "float64", REAL: "float64", TEXT: "utf8", BLOB: "binary", DATE: "utf8", DATETIME: "utf8", GEOMETRY: "binary", POINT: "binary", LINESTRING: "binary", POLYGON: "binary", MULTIPOINT: "binary", MULTILINESTRING: "binary", MULTIPOLYGON: "binary", GEOMETRYCOLLECTION: "binary" }; async function parseGeoPackage(arrayBuffer, options) { var _a; const { sqlJsCDN = DEFAULT_SQLJS_CDN } = (options == null ? void 0 : options.geopackage) || {}; const { reproject = false, _targetCrs = "WGS84" } = (options == null ? void 0 : options.gis) || {}; const db = await loadDatabase(arrayBuffer, sqlJsCDN); const tables = listVectorTables(db); const projections = getProjections(db); const selectedTable = tables.find((table) => { var _a2; return table.table_name === ((_a2 = options == null ? void 0 : options.geopackage) == null ? void 0 : _a2.table); }); const tableName = selectedTable ? selectedTable.table_name : tables[0].table_name; const shape = (_a = options == null ? void 0 : options.geopackage) == null ? void 0 : _a.shape; switch (shape) { case "geojson-table": return getVectorTable(db, tableName, projections, { reproject, _targetCrs }); case "tables": const outputTables = { shape: "tables", tables: [] }; for (const table of tables) { const { table_name: tableName2 } = table; outputTables.tables.push({ name: tableName2, table: getVectorTable(db, tableName2, projections, { reproject, _targetCrs }) }); } return outputTables; default: throw new Error(shape); } } async function loadDatabase(arrayBuffer, sqlJsCDN) { let SQL; if (sqlJsCDN) { SQL = await (0, import_sql.default)({ locateFile: (file) => `${sqlJsCDN}${file}` }); } else { SQL = await (0, import_sql.default)(); } return new SQL.Database(new Uint8Array(arrayBuffer)); } function listVectorTables(db) { const stmt = db.prepare("SELECT * FROM gpkg_contents WHERE data_type='features';"); const vectorTablesInfo = []; while (stmt.step()) { const vectorTableInfo = stmt.getAsObject(); vectorTablesInfo.push(vectorTableInfo); } return vectorTablesInfo; } function getVectorTable(db, tableName, projections, { reproject, _targetCrs }) { const dataColumns = getDataColumns(db, tableName); const geomColumn = getGeometryColumn(db, tableName); const featureIdColumn = getFeatureIdName(db, tableName); const { columns, values } = db.exec(`SELECT * FROM \`${tableName}\`;`)[0]; let projection; if (reproject) { const geomColumnProjStr = projections[geomColumn.srs_id]; projection = new import_proj4.Proj4Projection({ from: geomColumnProjStr, to: _targetCrs }); } const geojsonFeatures = []; for (const row of values) { const geojsonFeature = constructGeoJsonFeature( columns, row, geomColumn, // @ts-ignore dataColumns, featureIdColumn ); geojsonFeatures.push(geojsonFeature); } const schema = getSchema(db, tableName); if (projection) { return { shape: "geojson-table", type: "FeatureCollection", // @ts-expect-error TODO - null geometries causing problems... features: (0, import_gis.transformGeoJsonCoords)(geojsonFeatures, projection.project), schema }; } return { shape: "geojson-table", schema, type: "FeatureCollection", // @ts-expect-error TODO - null features features: geojsonFeatures }; } function getProjections(db) { const stmt = db.prepare("SELECT * FROM gpkg_spatial_ref_sys;"); const projectionMapping = {}; while (stmt.step()) { const srsInfo = stmt.getAsObject(); const { srs_id, definition } = srsInfo; projectionMapping[srs_id] = definition; } return projectionMapping; } function constructGeoJsonFeature(columns, row, geomColumn, dataColumns, featureIdColumn) { const idIdx = columns.indexOf(featureIdColumn); const id = row[idIdx]; const geomColumnIdx = columns.indexOf(geomColumn.column_name); const geometry = parseGeometry(row[geomColumnIdx].buffer); const properties = {}; if (dataColumns) { for (const [key, value] of Object.entries(dataColumns)) { const idx = columns.indexOf(key); properties[value] = row[idx]; } } else { for (let i = 0; i < columns.length; i++) { if (i === idIdx || i === geomColumnIdx) { continue; } const columnName = columns[i]; properties[columnName] = row[i]; } } return { id, type: "Feature", geometry, properties }; } function getFeatureIdName(db, tableName) { const stmt = db.prepare(`PRAGMA table_info(\`${tableName}\`)`); while (stmt.step()) { const pragmaTableInfo = stmt.getAsObject(); const { name, pk } = pragmaTableInfo; if (pk) { return name; } } return null; } function parseGeometry(arrayBuffer) { var _a, _b; const view = new DataView(arrayBuffer); const { envelopeLength, emptyGeometry } = parseGeometryBitFlags(view.getUint8(3)); if (emptyGeometry) { return null; } const wkbOffset = 8 + envelopeLength; const binaryGeometry = (_b = (_a = import_wkt.WKBLoader).parseSync) == null ? void 0 : _b.call(_a, arrayBuffer.slice(wkbOffset)); return (0, import_gis.binaryToGeometry)(binaryGeometry); } function parseGeometryBitFlags(byte) { const envelopeValue = (byte & 14) / 2; const envelopeLength = ENVELOPE_BYTE_LENGTHS[envelopeValue]; return { littleEndian: Boolean(byte & 1), envelopeLength, emptyGeometry: Boolean(byte & 16), extendedGeometryType: Boolean(byte & 32) }; } function getGeometryColumn(db, tableName) { const stmt = db.prepare("SELECT * FROM gpkg_geometry_columns WHERE table_name=:tableName;"); stmt.bind({ ":tableName": tableName }); stmt.step(); const geometryColumn = stmt.getAsObject(); return geometryColumn; } function getDataColumns(db, tableName) { let stmt; try { stmt = db.prepare("SELECT * FROM gpkg_data_columns WHERE table_name=:tableName;"); } catch (error) { if (error.message.includes("no such table")) { return null; } throw error; } stmt.bind({ ":tableName": tableName }); const result = {}; while (stmt.step()) { const column = stmt.getAsObject(); const { column_name, name } = column; result[column_name] = name || null; } return result; } function getSchema(db, tableName) { const stmt = db.prepare(`PRAGMA table_info(\`${tableName}\`)`); const fields = []; while (stmt.step()) { const pragmaTableInfo = stmt.getAsObject(); const { name, type: sqlType, notnull } = pragmaTableInfo; const type = SQL_TYPE_MAPPING[sqlType]; const field = { name, type, nullable: !notnull }; fields.push(field); } return { fields, metadata: {} }; } // dist/geopackage-loader.js var VERSION = "latest"; var GeoPackageLoader = { dataType: null, batchType: null, id: "geopackage", name: "GeoPackage", module: "geopackage", version: VERSION, extensions: ["gpkg"], mimeTypes: ["application/geopackage+sqlite3"], category: "geometry", parse: parseGeoPackage, options: { geopackage: { sqlJsCDN: DEFAULT_SQLJS_CDN, shape: "tables" }, gis: {} } }; //# sourceMappingURL=index.cjs.map