FME Version
Files
Introduction
This example creates a simple, textured CityGML model from our Interopolis 3DS model utilized in the previous example. CityGML is an OGC standardized GML application schema for representing 3D cities and landscapes. It is a hierarchical representation with very strict object types, and it can represent many levels of a city model in a single file through levels of detail. For example, you can have building models and building interiors with furniture in a single model on different levels of detail.
In the previous example, Adding Different Textures to a 3D City Model, we took a 3DS model of Interopolis and added different textures to the roof and walls, writing out to a 3D PDF. Now we will take that same completed workspace and modify it to create a textured CityGML model.
Step-by-Step Instructions
1. Download the Workspace Template
Download 3ds-to-3dpdf-textures.fmwt as your beginning workspace from the Files section and open it in FME Workbench. This is the completed workspace of the previous example. We will build upon this to create a textured CityGML model.
2. Replace the Adobe PDF Writer
Replace the Adobe PDF Writer with a CityGML Writer. When adding the CityGML Writer, please set the parameters as follows:
- In the Add Writer dialogue, ensure Feature Type Definition is set to ‘Import from Dataset’ beneath Add Feature Type(s). CityGML has predefined schemas that must be used for data compliance and proper CityGML writing. Select OK.
- In the Import Writer Feature Types dialogue, verify that CityGML 1.0 is selected for the CityGML Version in the Parameters. Using any other version would give us a different CityGML schema setup, and we want to be able to write out to RoofSurface and WallSurface, both of which are found in version 1.0. Leave the Dataset blank. Select OK.
- When prompted to Select Feature Types, select only Building, RoofSurface, and WallSurface.
3. Remove the GeometryCoercer
Next, remove the last GeometryCoercer, as we no longer want to group all the objects together as a single mesh. CityGML’s data model will allow us to keep our roofs and walls separated as children of a building object.
4. Concatenate a New CityGML ID for the ‘Building’ Feature Type
Every CityGML feature needs a unique ID. We are going to use the BuildingID attribute, which keeps track of which features are part of which building, to create IDs for our ‘Building’ feature type. CityGML feature IDs cannot begin with numbers, so we will use the StringConcatenator to prepend the string “GML_” before the building ID. Connect the Aggregator output port to the StringConcatenator.
Type in ‘gml_id’ for ‘New Attribute’. For String Parts, concatenate:
String Parts | String Value |
---|---|
Constant | GML_ |
Attribute Value | BuildingID |
5. Remove Geometries
We don’t actually want to write any geometries to the CityGML Building feature type. Instead, we just want to create an empty high-level class that will become the parent ID attribute for the roof and wall surfaces. This ID will allow us to group roof and wall surfaces of a building together if we wish to. We will remove geometries by connecting a GeometryRemover to the StringConcatenator.
Connect the output port of the GeometryRemover to the Building feature type.
Create a Customer Transformer
In the next few steps, we will create our custom transformer.
6. Aggregate Walls by Building ID
We need to group all of the walls for each building into a single MultiSurface geometry. Attach an Aggregator to the OUTPUT port of the wall texture AppearanceSetter, and make sure you set the ‘Group By’ to BuildingID.
7. Create CityGML Attributes
CityGML features need to have their level of detail and geometry type defined. In FME, this information is stored in Geometry Traits. Before we can add a trait to the geometries, we need to create attributes using the AttributeCreator. Fill out the parameters like the table below.
Attribute Name | Value |
citygml_level_of_detail | 2 |
citygml_lod_name | lod2MultiSurface |
citygml_feature_role | boundedBy |
- Create an attribute, citygml_level_of_detail, and set its value to 2. This means we want our wall features to be in level of detail 2. In this example, we only have a single level of detail, however it is possible to have multiple levels of detail in a single CityGML file.
- Create a second attribute, citygml_lod_name and give it the value lod2MultiSurface. This is the CityGML geometry type. In this case we are using Level of Detail 2 Multi Surface geometries.
- Create a third attribute, citygml_feature_role with the value boundedBy. This attribute defines the relationship between the feature and its parent.
8. Copy the Geometry Type Attribute Into a Geometry Trait
Now that we have stored the geometry type in an attribute, we need to copy it to a geometry trait using the GeometryPropertySetter. Geometry traits are similar to attributes but are stored in the geometry, rather than alongside it. Under Source Attribute, select citygml_lod_name.
9. Create Unique IDs
CityGML requires every feature to have a unique id. The UUIDGenerator will create a unique id and assign it to an attribute, _uuid.
10. Concatenate the Prefix ‘GML_’ With the Attribute ‘_uuid’
The UUIDGenerator creates unique ids that begin with numbers, which are invalid in CityGML. Similar to the building class above, we will use a StringConcatenator to add “GML_” to the beginning of each id. In the Parameters, name the New Attribute: ‘gml_id’, and set the String Parts up like the table below:
String Type | String Value |
Constant | GML_ |
Attribute Value | _uuid |
The Concatenated Result, which is automatically generated when you have filled in the parameters should like like this:
GML_@Value(_uuid)
11. Define the Parent ID Using Another StringConcatenator
We need to define the parent feature’s id, so that FME can properly build the hierarchy in the CityGML model. We need to replicate the gml_id that we created for the building class above. Add another StringConcatenator. Rename the ‘New Attribute’ as ‘gml_parent_id’. Set up the String Parts as follows:
String Type | String Value |
Constant | GML_ |
Attribute Value | BuildingID |
Concatenated Result:
GML_@Value(BuildingID)
12. Create Custom Transformer
Ensure that the Wall AppearanceSetter OUTPUT port is connected to the Aggregator_2. Select all the transformers from Step 6 (Aggregator2) to 11 (StringConcatenator3). Right click and select ‘Create Custom Transformer’. Name it CityGMLBuilder, set Category to 3D and press Ok. You will now see it in the tab at the top ribbon next to the tab Main. Here you will find the transformers that make up the custom transformer.
Open the parameters for the Input, Aggregator_2_Input. Make sure that BuildingID is checked in the ‘External Attributes to Expose’. This step is important because the last StringConcatenator of the CityGMLBuilder depends on this attribute as part of its parameters. Since the attribute was created outside of the custom transformer, the StringConcatenator doesn’t recognize the attribute as a valid parameter until the External Attribute has been exposed.
You may notice that your transformer has no output port. To add an output port, right-click the canvas, and select Insert Transformer Output. Connect the Output to the String_Concatenator_3. Likewise, if you are missing an input, you can add one from here too. Remember to check that BuildingID is exposed in its parameters.
Back in the Main tab, check the parameters for the CityGMLBuilder, and make sure that the attribute BuildingID is also selected as an attribute in the User Parameters. Connect your output to the CityGML feature type WallSurface in your Main workspace.
The custom transformer in the tab, CityGMLBuilder.
13. Duplicate the CityGMLBuilder
Duplicate the custom transformer and connect it to the Output port of the Roof’s AppearanceSetter, and connect the Output port of the custom transformer to the RoofSurface feature type.
14. Write out to CityGML
Clean up the attributes in your feature types before you run your workspace. In the WallSurface feature type parameters, in User Attributes, remove all the attributes except for ‘citygml_feature_role’. Then in Format Attributes, make sure that citygml_lod_name, gml_id, and gml_parent_id are exposed. Do the same for the RoofSurface. For the Building feature type, remove all User Attributes. Make sure that gml_id is exposed in the Format Attributes and uncheck citygml_lod_name and gml_parent_id under Format Attributes.
Run your workspace. After ensuring you are creating valid CityGML, in the Navigator window under the CityGML writer Parameters, please consider changing Validate Output File to No to improve performance.
Remove unnecessary attributes. Keep only the attributes that have connected (green triangle).
Completed Workspace
Results
The resulting CityGML output displayed in the native FZKViewer.
If viewing using the FZKViewer, you will need to add a Reprojector after the source reader feature type, interopolis. Reproject it to LL84. This step is necessary because our data is currently in the Texas State Plane coordinate system. Since this coordinate system is not recognized in the FZKViewer, we need to reproject it into a coordinate system that it does recognize so that we can view it.
If you wish to view the original textures in the FZKViewer, go to Display in the menu bar, then Textures, and select ‘From Entity’.
Congratulations! We have successfully written out our 3DS model to a textured CityGML model. As the model is properly displayed in a native CityGML viewer, we know that we have correctly written out the necessary structures for CityGML.
Data Attribution
Data used in this article originates from open data made available by the City of Austin, Texas. It contains data licensed under the Public Domain Dedication License - City of Austin.
Comments
0 comments
Please sign in to leave a comment.