Geometry module
The Geometry module contains the tables for storing feature geometries, as well as implicit geometries. These implicit geometries can be reused as templates for multiple features, following the CityGML implicit geometry concept.
Figure 1. Geometry module of the 3DCityDB v5
relational schema.
GEOMETRY_DATA
table¶
The GEOMETRY_DATA
table serves as the central location for storing both explicit and implicit geometry data of
the features in the 3DCityDB. It supports various geometry types, including points, lines, surface-based geometries, and
volume geometries.
Feature geometries¶
Explicit feature geometries, which are geometries with real-world coordinates, are stored in the geometry
column. This
column uses a predefined spatial data type from the database system running the 3DCityDB to store the geometry data. All
geometries must be stored with 3D coordinates and must be provided in the Coordinate Reference System (CRS) defined for
the 3DCityDB instance. To enable efficient spatial queries, the geometry
column is indexed by default.
The link between a feature stored in the FEATURE
table and its geometries is
stored as a geometry property in the PROPERTY
table. Additionally, the GEOMETRY_DATA
table contains a feature_id
foreign key, providing a back-link to the
feature. This setup allows you to query features and follow to the geometry, or query geometries and trace back to
the feature.
Implicit geometries¶
Implicit geometries are stored in the implicit_geometry
column of the GEOMETRY_DATA
table. Unlike feature geometries,
implicit geometries use local coordinates, which allows them to serve as templates for multiple city objects in the
database. This is also the reason why they are stored in a separate column, rather than in the geometry
column.
Since implicit geometries are not assigned to specific features directly, the feature_id
column is set to NULL
.
Instead, they are referenced from the IMPLICIT_GEOMETRY
table.
Implicit geometries are typically not involved in spatial queries, so the implicit_geometry
column does not
have a spatial index by default.
JSON-based metadata¶
The use of predefined spatial database types for storing both explicit and implicit geometries presents two main challenges:
-
Geometry types: CityGML features use a wide range of geometry types, including primitives (i.e., points, lines, surfaces, and volume geometries) and composite or aggregate geometries, all based on the ISO 19107 spatial schema standard. However, the predefined spatial database types typically cover only a subset of these, limiting the ability to fully represent all CityGML geometries.
-
Reuse and referencing: CityGML allows geometries to be reused by reference and assigned textures or colors. For this, each geometry and its components requires unique identifiers. However, spatial database types typically store only raw coordinates, lacking the ability to assign unique identifiers, which limits effective referencing and reuse.
Previous versions of 3DCityDB addressed these challenges by decomposing surface geometries into individual polygons, each stored in a separate row with a unique identifier. A hierarchical structure grouped the polygons by their original geometry type. While this enabled efficient referencing, it required recomposing geometries on-the-fly for spatial queries, making them slower and less efficient. Additionally, it increased storage requirements and was only applied to surface-based geometries, not points or lines.
The 3DCityDB v5
solution of using spatial database types to store entire geometries, without decomposition,
greatly improves spatial query performance and reduces storage requirements. To preserve the ability to reuse and
reference geometries and their parts, and to maintain the expressivity of CityGML geometry types, JSON-based metadata is
stored alongside the geometry in the geometry_properties
column.
To illustrate the structure and use of this JSON metadata, consider storing a CityGML solid geometry in
PostgreSQL/PostGIS. The PostGIS-specific data type used is POLYHEDRALSURFACE Z
, which stores a simple array of
polygons. The following snippet demonstrates how a unit cube is represented as a polyhedral surface
consisting of six polygons. The equivalent CityGML Solid
geometry is shown in a second tab.
<gml:Solid gml:id="mySolid">
<gml:exterior>
<gml:Shell gml:id="myOuterShell">
<gml:surfaceMember>
<gml:Polygon gml:id="first">
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 0 1 0 1 1 0 1 0 0 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="second">
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 0 1 0 0 1 1 0 0 1 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="third">
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 1 0 0 1 0 1 0 0 1 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="fourth">
<gml:exterior>
<gml:LinearRing>
<gml:posList>1 1 1 1 0 1 0 0 1 0 1 1 1 1 1</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="fifth">
<gml:exterior>
<gml:LinearRing>
<gml:posList>1 1 1 1 0 1 1 0 0 1 1 0 1 1 1</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="sixth">
<gml:exterior>
<gml:LinearRing>
<gml:posList>1 1 1 1 1 0 0 1 0 0 1 1 1 1 1</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:Shell>
</gml:exterior>
</gml:Solid>
Unlike the PostGIS polyhedral surface, the CityGML Solid
geometry has an additional CompositeSurface
to represent
the outer shell formed by the polygons. Moreover, the solid, the composite surface, and each polygon have an
identifier that allows the reuse of the component and the assignment of textures or colors. The following JSON object
encodes this extra metadata and links it to the POLYHEDRALSURFACE Z
representation:
{
"type": 9, // (1)!
"objectId": "mySolid",
"children": [
{
"type": 6, // (2)!
"objectId": "myOuterShell"
},
{
"type": 5, // (3)!
"objectId": "first",
"parent": 0,
"geometryIndex": 0
},
{
"type": 5,
"objectId": "second",
"parent": 0,
"geometryIndex": 1
},
{
"type": 5,
"objectId": "third",
"parent": 0,
"geometryIndex": 2
},
{
"type": 5,
"objectId": "fourth",
"parent": 0,
"geometryIndex": 3
},
{
"type": 5,
"objectId": "fifth",
"parent": 0,
"geometryIndex": 4
},
{
"type": 5,
"objectId": "sixth",
"parent": 0,
"geometryIndex": 5
}
]
}
- A value of
9
meansSolid
. - A value of
6
meansCompositeSurface
. - A value of
5
meansPolygon
.
The metadata is interpreted as follows: The "type"
property of the JSON object classifies the geometry as a Solid
(type = 9
), with a
unique "objectId"
of "mySolid"
. The "children"
array lists all the components of the Solid
and establishes a
hierarchical relationship between them. The first item in the "children"
array represents the outer shell of the solid
(type = 6
) and is identified as "myOuterShell"
. As defined in ISO 19107, the outer shell acts as a container but does not
directly reference a specific geometry from the polyhedral surface.
The other six items in the "children"
array represent the individual polygons (type = 5
) that form the outer shell. Each
polygon has its own unique "objectId"
. The "parent"
field contains a 0
-based reference into the "children"
array and
defines the parent of the component. In this example, a value of 0
indicates that the polygon belongs to the outer shell.
The "geometryIndex"
is a 0
-based index linking the child to a specific polygon of the polyhedral surface stored
in the geometry
column.
Summary
This simple JSON structure works for mapping any CityGML geometry type onto a spatial database type. In summary, the main idea is that the
primitives in the spatial database type (points, lines, polygons) are referenced by the geometryIndex
, while the
children
and parent
structure enables embedding the primitives into any CityGML geometry hierarchy. The objectId
provides a unique identifier for each component, ensuring that each geometry and its parts can be individually
referenced and distinguished within the database.
The following list shows all supported values for the type
attribute in the JSON metadata, mapping them to their
corresponding CityGML geometry types:
1: Point
2: MultiPoint
3: LineString
4: MultiLineString
5: Polygon
6: CompositeSurface
7: TriangulatedSurface
8: MultiSurface
9: Solid
10: CompositeSolid
11: MultiSolid
In addition to "objectId"
, "type"
, and "children"
mentioned above, the JSON metadata object can also include the
"is2D"
property. When "is2D"
is set to true
, the geometry should be interpreted as 2D. However, it must
still be stored using 3D coordinates in the geometry
column (e.g., with a height value of 0
). Tools processing the
geometry should ignore height values when "is2D"
is set.
Additionally, each component in the "children"
array can have an "isReversed"
property. This flag indicates whether the
coordinates of the component were flipped during import to reverse its orientation. This can occur, for example, when
importing CityGML datasets that contain orientable primitives such as gml:OrientableSurface
with their orientation
attribute set to "-"
. The "isReversed"
property enables tools to export the component as orientable primitive again.
Tip
The 3DCityDB software package includes a JSON Schema specification that defines
the allowed structure of the JSON metadata object. You can find this schema file, named geometry-properties.schema.json
,
in the json-schema
folder of the software package.
IMPLICIT_GEOMETRY
table¶
The IMPLICIT_GEOMETRY
table implements the concept of implicit geometries in CityGML. An implicit geometry is a template
that is stored only once in the 3DCityDB and can be reused by multiple city objects. Examples of implicit geometries
include 3D tree models, where different tree species and heights are represented as template geometries. These tree
models can then be instantiated at various locations for specific tree features according to their species.
Each tree feature can specify a reference point where the template geometry should be placed, along with an individual
3x4 transformation matrix to apply scaling, rotation, and translation to the model. The relationship between a feature
in the FEATURE
table and an implicit geometry in the IMPLICIT_GEOMETRY
table is
established through a corresponding entry in the PROPERTY
table. The
feature-specific reference point and transformation matrix are stored with this relationship in the
PROPERTY
table (see here).
The IMPLICIT_GEOMETRY
table supports three methods for storing template geometries:
- Stored as geometries with local coordinates: These geometries are saved in the
implicit_geometry
column of theGEOMETRY_DATA
table, as explained earlier. The geometry is then referenced through therelative_geometry_id
foreign key. - Stored as binary blobs: The 3D model is stored in a specific data format as a binary object in the
library_object
column. - Stored as references to external 3D models: In this case, the 3D model is referenced through a URI stored in the
reference_to_library
column, pointing to an external file or system.
For both methods 2 and 3, the mime_type
column should specify the MIME type of the binary 3D model or
external file. This ensures that the 3D model can be processed correctly according to its format (e.g.,
model/gltf+json
for a glTF model or application/vnd.collada+xml
for a COLLADA model). Additionally,
the mime_type_codespace
column can store an optional code space for the MIME type, providing further context or
classification.
Finally, the objectid
column provides a unique identifier for the implicit geometry, ideally globally unique.
Tip
The recommended approach for storing implicit geometries is to store them in the GEOMETRY_DATA
table with local
coordinates. Storing arbitrary binary 3D models carries the risk that tools may not be able to process the models
correctly.