A very basic and experimental converter from CityGML to Cesium 3D Tiles.
Note that this tool is generating 3D Tiles v1.0, while the current format is v1.1.
The purpose of this JavaScript code is to read CityGML files, extract objects (like buildings), and write the corresponding meshes as a batched 3D model in the 3D Tiles spec. Each building will become a feature, and its attributes will be stored in the 3D Tiles batch table. For more information see docs/background.md.
The code for writing 3D Tiles files is based on the 3D Tiles Samples Generator.
The functionality is very basic, and many limitations exist:
Building
are converted.Buffer
.The library provides an executable to convert files on the command line.
node --version
npm install -g citygml-to-3dtiles
citygml-to-3dtiles "my-citygml.xml" "my-output-folder/"
When converting large files, it can be necessary to increase NodeJS' memory limit. For example run the conversion with a 10GB memory limit:
NODE_OPTIONS=--max-old-space-size=10000 citygml-to-3dtiles "my-citygml.xml" "my-output-folder/"
Instead of a single input file the script also accepts a path to a folder containing multiple CityGML files. The contents of all files will get concatenated and written to a single 3D Tileset.
The library exposes an easy to use API to convert from CityGML to 3D Tiles. Using the library programmatically allows us to calculate custom properties and store them in the resulting tileset.
import Converter from "citygml-to-3dtiles";
let converter = new Converter();
await converter.convertFiles('./input.xml', './output/');
propertiesGetter
By default any CityGML attributes and external references are stored in the 3D Tiles batch table.
Additional properties can be stored per feature by passing propertiesGetter
.
The function propertiesGetter
is executed once for each city object and the key/value pairs of the return value will become the model's properties.
The function receives two arguments:
CityObject
. Can be used to retrieve the object's geometry and to access the corresponding XML node from the CityGML.Example: Get the value of an element <measuredHeight>
in the XML namespace "bldg2" (http://www.opengis.net/citygml/building/2.0)
and store it as "measuredHeight" in the batch table:
let converter = new Converter({
propertiesGetter: (cityObject, properties) => {
let measuredHeightNode = cityObject.cityNode.selectNode('./bldg2:measuredHeight');
let measuredHeight = parseFloat(measuredHeightNode.textContent);
return {
measuredHeight: measuredHeight
}
}
});
await converter.convertFiles('./input.xml', './output/');
Example: Store the convex surface area of each building (calculated from the geometry) in the property "surfaceArea":
let converter = new Converter({
propertiesGetter: (cityObject, properties) => {
let mesh = cityObject.getTriangleMesh();
return {
surfaceArea: mesh.getSurfaceArea()
}
}
});
await converter.convertFiles('./input.xml', './output/');
objectFilter
Allows to remove city objects (buildings) based on a callback function.
The function specified receives the city object (CityObject
) as its only argument and should return true
or false
to decide
whether to include it in the 3DTiles output.
Example: Only include objects with a maximum distance of 600m of a given point.
let center = Cesium.Cartesian3.fromDegrees(8.5177282, 47.3756023);
let converter = new Converter({
objectFilter: (cityObject) => {
let distance = Cesium.Cartesian3.distance(center, cityObject.getAnyPoint());
return distance < 600;
}
});
await converter.convertFiles('./input.xml', './output/');
srsProjections
The coordinates in CityGML are defined in a certain spatial reference system (SRS). This script assumes that all coordinates in a document are using the same SRS. Height component of coordinates is not transformed according to the SRS, because the library used (proj4js) doesn't support it.
Only a few SRS are defined by default. Additional SRS can be passed to the converter:
let converter = new Converter({
srsProjections: {
'CH1903': '+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 +x_0=600000 +y_0=200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs',
}
});
await converter.convertFiles('./input.xml', './output/');
The definition should be in the "PROJ.4" format. Definitions in that format can be found at http://epsg.io/.
For Delft an area is available in CityGML2 LOD1 from TU Delft.
For Zürich a small area of LOD2 CityGML is available from Stadt Zürich, Geomatik Vermessung.
Here the buildings' hull volume is color coded in Cesium:
Install dependencies:
npm install
Run tests:
npm test
Release a new version:
git checkout master && git pull --ff-only
package.json
, run npm install
and commit the change.git tag "vX.Y.Z"
git push && git push --tags