Model Tree

Overview

Engineering Data usually consists of a lot more than just its visible 2D or 3D geometry. The structure and hierarchy of a model often referred to as its “Product Structure” or “Model Tree” is equally important. In the Web Viewer, this information is represented alongside the geometry in multiple ways. In this chapter, we will mainly focus on the Node hierarchy usually representing the structural parent/child relationship between entities in a model and some of its related attributes. Other topics specific to MCAD and BIM will be discussed in separate sections.

Nodes

A node is the basic building block of the model tree in the Web Viewer. All visible or non-visible geometry and attributes are always associated with a node. A node may contain many child nodes, or it can just encapsulate a single entity.

NodeIDs

Each node has a NodeId which is a unique identifier that is generated when the model is authored meaning that it will stay persistent when loading the same model multiple times. Functions that operate on nodes will either return a NodeId or will use it as input.

    var nodename = hwv.model.getNodeName(myNodeId);

While nodeIds are persistent between model loads when loading multiple models into the same scene, the Web Viewer applies an offset value to prevent multiple nodes sharing the same nodeIDs. You can find out more about this mechanism here.

Node hierarchy

The node hierarchy in the Web Viewer forms a tree like structure with a single root node at its top. The nodeid of that root node can be queried with a call to model.getAbsoluteRootNode(). When loading SC models into the Web Viewer the root node will always have one child node per model loaded with the hierarchy of the loaded model underneath it.

To navigate the model tree you can use the functions below.

    var parent = hwv.model.getNodeParent(myNodeId);
    var children = hwv.model.getNodeChildren(myNodeId);

Only the leaf nodes of the model tree can contain mesh geometry and implicitly any nodes returned from a selection will always point to those leaf nodes.

A node can be one of several different types. For models imported via our conversion tools, those types are derived from the PRC entity definitions. We will discuss those definitions later in this programming guide. See below for an example of a model tree consisting of two separately loaded models:

../../../_images/model-tree-two-loaded-models.png

Instancing

The Web Viewer only supports what it is called a “flattened” tree meaning that nodes can only have zero or more children and a single parent. No other relationship exists between nodes. In mechanical assemblies, commonly, subassemblies are sometimes “instanced” and the same subassembly is referred to multiple times by a parent node (e.g. the four tires in a car). In the Web Viewer, this instance hierarchy will be flattened during conversion meaning that the node hierarchy is repeated in the tree for each instance in the original assembly. <br>The Web Viewer does support instancing on the mesh level meaning that in the diagram above the mesh that exists at the leaf of the tree is “instanced” meaning that its geometry is rendered with different attributes and in different locations but it only exists once in the model.

Callbacks

Conceptually the model tree and all mesh geometry and attributes are independent of each other in the Web Viewer meaning that they are loaded in parallel. This is to ensure that quickly visualizing a model is not delayed by interpreting the model tree data. While mesh geometry streams incrementally into the client and can be interacted with right away it is not possible to interact with the model tree until it has been completely loaded and parsed.

To determine if the model tree is ready to interact with you can set the below callbacks:

modelStructureReady

This callback will only be executed on the loading of the initial model and will not be triggered again with any subsequent model loads into the same viewer context. If your application only loads a single model into the scene this is the only callback you need to set to ensure that the model tree is loaded.

modelSwitched

This callback is executed after the model tree has been loaded and parsed after a call to switchToModel():

subtreeLoaded

This callback is executed after loading and parsing of the model tree in response to one of the loadSubtreeFrom functions.

modelStructureHeaderParsed

As it can take a while for large models before the model tree is fully loaded and parsed we provide another callback that is executed as soon as the initial model tree header has been parsed which should happen very quickly. This callback also provides the name of the CAD file that the model has been converted from as well as its file type (assuming it has been imported from a CAD model).

Note

Just to reiterate, without the model tree, no functions operating on nodeIds can be called so it is advisable to disallow most interactions with the model until one of those callbacks has executed.

Node creation

To dynamically create new nodes simply call the model.createNode() function. This function optionally takes a matrix as well as a default visibility state. Deleting a node can be done via the model.deleteNode() function. This function will also delete all descendants of the deleted node but not their associated meshes if they are referenced by other nodes.

In the below example we iterate over all nodes in the model tree and delete the ones with the specified name.

    function generateRecursive(nodeId, node_to_delete) {
        var name = hwv.model.getNodeName(nodeId);
        if (name == node_to_delete) hwv.model.deleteNode(nodeId);
        else {
            var children = hwv.model.getNodeChildren(nodeId);
            for (var i = 0; i < children.length; i++) {
                generateRecursive(children[i], node_to_delete);
            }
        }
    }

    function generate(node_to_delete) {
        var rootid = hwv.model.getAbsoluteRootNode();
        generateRecursive(rootid, node_to_delete);
    }