Triangulated irregular network (TIN) GeoPackage format
Introduction
The TIN GeoPackage format defines the format for a triangulation model stored in a GeoPackage file, that defines a horizontal and/or vertical transformation between two CRS.
That file format may be used by the tinshift operation since PROJ 9.9
Note: this format has similar capabilities than the TIN JSON file format, but can handle arbitrarily large triangulations.
The tin_json_to_gpkg_tin.py Python script can be used to convert a TIN JSON file into a TIN GeoPackage file.
Specification
The file MUST be a GeoPackage v1.2, v1.3 or v1.4 file.
vertices table
The file MUST contain a vertices GeoPackage table, of geometry type POINT,
registered in the gpkg_contents table with data_type set to features.
The x_min, y_min, x_max and y_max columns record in the
record of gpkg_contents MUST contain the bounding box of all vertices.
The CRS referenced by the table MUST be the source CRS of the transformation.
The vertices table MUST have at least the following columns:
fid: the integer primary key column.geom: the GeoPackage POINT geometry column. There are constraints on the format of the GeoPackage BLOB. Both the GeoPackage header and the WKB MUST use Intel byte order. The GeoPackage header MUST NOT have an envelope. The point encodes the coordinates in the source CRS (equivalent of thesource_xandsource_ycolumns in the TIN JSON format. Such columns may also be added to theverticestable, but they are not used by the PROJ implementation)
If the TIN defines a horizontal shift, the following columns MUST be present:
target_x: target X coordinate, in a column of type REAL, if the TIN defines a horizontal shift.target_y: target Y coordinate, in a column of type REAL, if the TIN defines a horizontal shift.
If the TIN defines a vertical shift, the following columns MUST be present:
source_zandtarget_z: source and target Z coordinate, in columns of type REAL(or)
offset_z: value oftarget_z-source_z, in a column of type REAL
Additional columns may be present, but are not used by PROJ.
The vertices table may have a RTree spatial index, but this is not used
by PROJ.
triangles_def table
The file MUST contain a triangles_def GeoPackage table.
Its data_type registered in the gpkg_contents may be attributes,
or features. This is not used by PROJ.
The triangles_def table MUST have at least the following columns:
fid: the integer primary key column.idx_vertex1: foreign key to thefidcolumn ofvertices, for the 1st vertex of the triangle.idx_vertex2: foreign key to thefidcolumn ofvertices, for the 2nd vertex of the triangle.idx_vertex3: foreign key to thefidcolumn ofvertices, for the 3rd vertex of the triangle.
Additional columns may be present, but are not used by PROJ.
gpkg_metadata and gpkg_metadata_reference tables
The file MUST contain the gpkg_metadata and gpkg_metadata_reference tables,
as defined by the GeoPackage metadata
extension.
The gpkg_metadata table MUST contain the following record:
id= 1md_scope=datasetmd_uri=https://proj.orgmime_type=application/jsonmetadata: serialized JSON content of the metadata described below.
The gpkg_metadata_reference table MUST contain the following record:
reference_scope=geopackagetable_name= NULLcolumn_name= NULLtimestamp: any ISO-8601 valid valuerow_id_value= NULLmd_file_id= 1md_parent_id= NULL
JSON content in the gpkg_metadata table
Required members
The content of the record of id 1 in the gpkg_metadata table MUST be a
serialized JSON object, with the following required members:
file_type=triangulation_fileformat_version=1.0or1.1transformed_components: an array which may contain one or two strings:horizontalwhen horizontal components of the coordinates are transformed and/orverticalwhen the vertical component is transformed.
Optional members used by PROJ
fallback_strategyString identifying how to treat points that do not fall into any of the specified triangles. When this item is set,
format_versionmust be set to >= 1.1. Possible values arenone,nearest_sideandnearest_centroid. The default isnoneand signifies, that points that fall outside the specified triangles are not transformed. This is also the behavior forformat_versionbefore 1.1. Iffallback_strategyis set tonearest_side, then points that do not fall into any triangle are transformed according to the triangle closest to them by euclidean distance. Iffallback_strategyis set tonearest_centroid, then points that do not fall into any triangle are transformed according to the triangle with the closest centroid (intersection of its medians).
Conditional members
When transformed_components contains the horizontal string, the JSON
metadata MUST contain the additional members:
min_shift_x: minimum value oftarget_x-source_xover all vertices of theverticestable.max_shift_x: maximum value oftarget_x-source_xover all vertices of theverticestable.min_shift_y: minimum value oftarget_y-source_yover all vertices of theverticestable.max_shift_y: maximum value oftarget_y-source_yover all vertices of theverticestable.
Note: those fields are used when performing inverse transformations
If the above described fallback_strategy field is set to nearest_side or nearest_centroid,
a num_vertices member MUST be set with the number of vertices of the vertices table.
Note: this is used to compute the initial search radius in the inverse transformation for those modes.
Other optional members
All other members defined in the TIN JSON file format (except vertices, vertices_columns,
triangles and triangles_columns which are redundant with the GeoPackage vertices and triangles_def
tables) may be set.
rtree_triangles_geom RTree virtual table
A RTree virtual table MUST be created as following:
CREATE VIRTUAL TABLE rtree_triangles_geom USING rtree(id, minx, maxx, miny, maxy)
It MUST be filled with as many records as there are triangles in the triangles_def
table, with the id column of rtree_triangles_geom containing the
corresponding value of the fid column of triangles_def, and the
minx, maxx, miny, maxy columns containing the bounding box of
each triangle.
Optional triangles spatial view
The file MAY contain an optional triangles spatial view, extending the
triangles_def table with the GeoPackage geometry blob of each triangle.
Such spatial view can be used to display the triangles in a GIS software that supports GeoPackage (and spatial views), such as QGIS.
The tin_json_to_gpkg_tin.py script creates such view with:
srs_id_i32le = as_i32le_hex(srs_id)
wkb_polygon_i32le = as_i32le_hex(3)
number_rings_i32le = as_i32le_hex(1)
number_vertices_i32le = as_i32le_hex(4)
triangle_gpkg_prefix = f"47500001{srs_id_i32le}01{wkb_polygon_i32le}{number_rings_i32le}{number_vertices_i32le}"
# other_fields is typically ",v1.target_x, v1.target_y, v2.target_x, v2.target_y, v3.target_x, v3.target_y" for a horizontal transformation
# 14 = GPKG_header_size_without_envelope (8) + WKB point header (5) + base_one_index (1)
ds.ExecuteSQL(
f"CREATE VIEW triangles AS SELECT triangles_def.fid AS OGC_FID {other_fields}, CAST(X'{triangle_gpkg_prefix}' || substr(v1.geom, 14) || substr(v2.geom, 14) || substr(v3.geom, 14) || substr(v1.geom, 14) AS BLOB) AS geom FROM triangles_def LEFT JOIN vertices v1 ON idx_vertex1 = v1.fid LEFT JOIN vertices v2 ON idx_vertex2 = v2.fid LEFT JOIN vertices v3 ON idx_vertex3 = v3.fid"
)
ds.ExecuteSQL(
f"INSERT INTO gpkg_contents (table_name, identifier, data_type, srs_id, min_x, min_y, max_x, max_y) VALUES ('triangles', 'triangles', 'features', {srs_id}, {min_x}, {min_y}, {max_x}, {max_y})"
)
ds.ExecuteSQL(
f"INSERT INTO gpkg_geometry_columns (table_name, column_name, geometry_type_name, srs_id, z, m) values ('triangles', 'geom', 'POLYGON', {srs_id}, 0, 0)"
)