You can plug properties from external data sources into a TileSet3DLayer
.
This means that you can populate the model in your layer with properties that aren’t available inside the OGC 3D Tiles data.
You can then use those plugged-in properties in expressions for styling.
This leads to the restriction that properties can only be numerical.
For a demonstration of the styling of plugged-in feature properties in a 3D Tiles layer, see the "Selection on OGC 3D Tiles data" sample on the Samples page.
To link the plugged-in properties to features of your model, you need to know the name of a unique numerical feature identifier:
-
For models generated with the Binz converter, this unique identifier is
FeatureID
. -
For models generated via the 3D Tiles Processing Engine, this unique identifier is
ObjectId
.
Typically, you use that same identifier as idProperty
for selection purposes too. See Selecting mesh data for more information.
Defining properties with a PropertiesDescriptor
If you want to add properties to your layer, you must describe them at layer construction time.
Also see the |
const ogc3dTilesLayer = new TileSet3DLayer(model, { selectable: true, idProperty: "ObjectId", properties: { "Temperature": { default: -100, }, "Maintenance": { default: 0, } } });
As you can see in Program: Adding properties to your layer, you must provide a numerical default value for each property you are describing. You can only start pushing real property values to features after you’ve finished creating your layer. The default value serves for all feature properties that you didn’t update with actual values yet.
Because the |
Updating properties with PropertiesUpdate
You can add properties from external sources of both static and dynamic data. Static data typically offers information about materials, floor levels, feature types. Dynamic data typically offers changing information about temperature, pressure, fluid levels, or even about the maintenance status of some parts of the structure. You can handle both types of data in exactly the same way.
Pushing property updates to the layer
To get the correct values in the layer, you can use the updateProperties
function of the layer.
For static data, you may have to do this only once. For dynamic data, you can repeat the update each time your data changes.
For an update, you must give the name of the property you are updating, the IDs for which you are sending an update, and the new values. You add a single value if you want to tell the layer that a part of your structure is in maintenance, for example. You add more than one value, one for each ID, when you are pushing temperature values for parts of the structure fitted with a temperature sensor, for example.
ogc3dTilesLayer.updateProperties({ "Temperature": { ids: [1, 2, 3], //for each id we give a new TemperatureValues, ids that are not updated will remain as is values: [25, 27, 28], }, "Maintenance": { ids: [9, 10, 12], //for each id we provide the same update-value, ids that are not updated are reset to the default value value: 1, } })
Waiting for the layer to request updates
To ensure performance when you are dealing with large models with a lot of features, it’s useful to push data for features in view only. This approach is similar to what LuciadRIA does with the geometry inside the tiles. Whenever your view changes, it loads new tiles, and discards tiles that are going out of view.
Once you have configured a layer with properties, it emits a FeaturesInViewChange
event whenever features come into view or go out of view.
This event comes with two attributes: a list of IDs of features that came into view, and one with IDs of features that went
out of view.
Using that event, you can always track which features are in the view, and thus, for which features you may need to update
the property values.
You can also erase all property values of the features that went out of view.
FeaturesInViewChange
event and taking action
ogc3dTilesLayer.on("FeaturesInViewChange", (idsEnteredView, idsLeftView) => { // Possible things to do: // - subscribe to the idsEnteredView // - remove subscription for idsLeftView // - keep track of all idsInView (for updates without this callback) // - erase values for idsLeftView (note: all values for all properties are erased at once) ogc3dTilesLayer.eraseProperties(idsLeftView); // - update values for idsEnteredView });
Linking the Binz FeatureID to external properties
When you convert Binz data to OGC 3D Tiles, each feature gets a unique numerical FeatureID
, counting up from 0 to the total number of features in the dataset.
Next to generating that unique identifier, the conversion process also integrates the original metadata from the Binz file
in the OGC 3D Tiles.
The original metadata always contains a Linkage
identifier, a unique identifier composed of 4 large numbers. This identifier is generated by Smart Interop Publisher while
it creates the Binz file from other input file types.
It uses this same identifier to populate a *.drv
file with all possible attributes from the original dataset.
This Linkage
identifier is a good entry point to link your features with other, external properties.
To get the Linkage
for each FeatureID
, you must generate a GeoJSON file when you are converting Binz to 3D Tiles. To generate a GeoJSON file, run the Binz converter
script with the -g
command parameter. See Converting Binz data to OGC 3D Tiles for more information.
In this concrete example, we start from a .binz
file and an .rdv
file. They originated from an IFC file.
Original files:
-
someSample.binz
: contains the data geometry -
someSample.drv
: contains the data attributes
3KnTnKB5TBjup7D4Kz$zFO
inside the .drv
file. The generated Linkage
identifier is 19868 16312 -30765 -23112
:
lbl{ 19868 16312 -30765 -23112 text { GlobalId: 3KnTnKB5TBjup7D4Kz$zFO Name: SomeName ObjectType: SomeType Tag: 20504600 Layer Name: A-FLOR-HRAL-OTLN ... other properties } }
After converting the Binz file to OGC 3D Tiles with the GeoJSON file option, you get these files:
-
tileset.json
-
features.geojson
19868 16312 -30765 -23112
. It received FeatureID
1893
during conversion.
"features" : [ { "type" : "Feature", "geometry" : { "type" : "Polygon", "coordinates" : [ ] }, "properties" : { "FeatureID" : 1893, "Linkage" : "19868 16312 -30765 -23112", "aabb" : "{ \"max\": [ -19.166865, -21.212387, 1.074825 ],\"min\": [ -20.572663, -22.189715, 1.032661 ]}", "minZ" : 21.032732863910496, "maxZ" : 21.074896863910496 } } ]
Linking the 3D Tiles Processing Engine ObjectId to external properties
When you convert OBJ data to OGC 3D Tiles with the 3D Tiles Processing Engine, each feature gets a unique numerical ObjectId
, counting up from 0 to the total number of features in the dataset.
Next to generating that unique identifier, the conversion process also integrates some metadata from the OBJ file in the OGC
3D Tiles.
Most of the time, you will find an ObjectName
, also a unique identifier, but a string.
This ObjectName
is a good link to your external properties.
To get the ObjectName
for each generated ObjectId
, you must use a custom ILcd3DTilesProcessorMetadataMapper
in the TLcd3DTilesProcessorBuilder
.
This MetadataMapper
is meant to be used for integrating external properties in the 3D Tiles, but you can also use it to generate a JSON file
linking ObjectId
to ObjectName
.
For more information about the 3D Tiles Processing Engine, see Pre-processing 3D Meshes to OGC 3D Tiles.
In this concrete example, we start from an IFC file.
Original files:
-
someSample.ifc
: containing geometry -
someSample.xml
: containing attributes
0IVRNVgp1F_PzGPAeVm4N_
inside the XML file:
<IfcWallStandardCase id="0IVRNVgp1F_PzGPAeVm4N_" Name="Basic Wall:ANTO_21_WA_iso hard 93:1496853" ObjectType="Basic Wall:ANTO_21_WA_iso hard 93" ObjectPlacement="0.92448 0.381232 0 0 -0.381232 0.92448 0 0 0 0 1 0 34651.9 35501.8 29079 1" Tag="1496853"> <IfcElementQuantity xlink:href="#2BAVFqwMb5hfPB51ojzXo8"/> <IfcPropertySet xlink:href="#1QJS37L09A9OowaWA5$B7n"/> <IfcPropertySet xlink:href="#3RFcCTwWz14xNkgaH0Qn_4"/> <IfcPropertySet xlink:href="#2sbE7MDLT3XgapNq8dhlDn"/> <IfcPropertySet xlink:href="#3VXZJNloP6fQB4mMoi84fT"/> <IfcPropertySet xlink:href="#0IVRNVgp1F_PzGRrSVm4N_"/> <IfcPropertySet xlink:href="#1gdLWQFYHCEQiI6WlFGeHj"/> <IfcWallType xlink:href="#11y0yv0ujCBeC5IKFuwinh"/> <IfcPresentationLayerAssignment xlink:href="#A-WALL-____-OTLN"/> <IfcMaterialLayerSetUsage xlink:href="#IfcMaterialLayerSetUsage_5179"/> </IfcWallStandardCase>
After converting the IFC file to OBJ, using any conversion tool, you get this file:
-
someSample.obj
: containing data geometry and theobjectName
.obj
file:
g 0IVRNVgp1F_PzGPAeVm4N_ s 1 v 51.798 42.5220633920099 29.079 ... a number of vertices, triangles, ...
The custom MetadataMapper
you must use with the 3D Tiles Processing Engine could look like this:
public class CustomMeshup { public static void main(String[] args){ try { CustomMapper mapper = new CustomMapper(); TLcd3DTilesProcessorBuilder.newBuilder() .addInputFiles("someFile.obj") .outputPath("someOutputPath") .metadataMapper(mapper) .process() .get(); mapper.writeJsonFile("somePath", "someSample.json"); } catch (InterruptedException | ExecutionException | IOException aE) { aE.printStackTrace(); } } } private static class CustomMapper implements ILcd3DTilesProcessorMetadataMapper { private static String OBJ_ID = TLcd3DTilesProcessorDataTypes.OBJECT_ID_PROPERTY; private static String OBJ_NAME = TLcd3DTilesProcessorDataTypes.OBJECT_NAME_PROPERTY; private List<FeatureData> fFeatures; CustomMapper(){ fFeatures = new ArrayList<>(); } @Override public TLcdDataType getDataType(TLcdDataType aDataType) { return aDataType; } @Override public ILcdDataObject getDataObject(ILcdDataObject aDataObject) { fFeatures.add(new FeatureData((String) aDataObject.getValue(OBJ_ID), (String) aDataObject.getValue(OBJ_NAME))); return aDataObject; } public void writeJsonFile(String path, String fileName) throws IOException { new ObjectMapper().writeValue(new File(path+fileName), fFeatures); } } private static class FeatureData { private String fObjectId; private String fObjectName; FeatureData(String aObjectId, String aObjectName){ this.fObjectId = aObjectId; this.fObjectName = aObjectName; } public String getObjectId() { return fObjectId; } public void setObjectId(String aObjectId) { this.fObjectId = aObjectId; } public String getObjectName() { return fObjectName; } public void setObjectName(String aObjectName) { this.fObjectName = aObjectName; } } }
The 3D Tiles Processing Engine generates these files with the custom MetadataMapper
:
-
tileset.json
: containing data geometry, generatedobjectId
, andobjectName
-
someSample.json
: a file linkingobjectId
toobjectName
someSample.json
file for the feature under investigation
[{"ObjectId":"1492","ObjectName":"0IVRNVgp1F_PzGPAeVm4N_"}]
You can use this objectId
1492
to add properties for the feature with ID 0IVRNVgp1F_PzGPAeVm4N_
— originating from the someSample.xml
file — to the layer showing this model.
You can add numerical properties only, so you can add a layer property by number, not by name. Afterward, you can link the number back to the original name. |