The Instance Operator
In this chapter, we will walk through building our own custom "instance operator". This will be a custom operator that copies geometry.
- Inserting objects with the mouse
- Gathering node dependencies
- Instancing through mesh creation
A common additive manufacturing use case may be to replicate parts on the plane for printing multiple copies. To do this visually, we can instance selected nodes and allow the user to place them on the plane with the mouse.
The InstanceOperator.js file has been provided with the basic skeleton code for our InstanceOperator class. Our custom operator class will implement the Communicator.Operator interface within HOOPS Communicator to our specific needs. One of those needs is to make sure our viewers are synced with any operations performed, so lets pass the viewSyncSyncHelper object to the constructor. We will also create member variables for where the user clicked, the current nodes we want to instance, and the Z position of the inserted nodes.
We want the user to be able to select a node, click on the plane, and insert the node where the user clicked. For this tutorial, we will use the onMouseDown() and onMouseUp() event callbacks in the Operator class. We use both to ensure that the user is clicking and not dragging the mouse. If the onMouseDown() position is equal to the onMouseUp position, we can continue to insert the node into the scene.
This function will ensure that the user has picked a point on the PrintingPlane surface, and not elsewhere in world space. If the user did select the PrintingPlane, we continue to insert the geometry.
The InstanceOperator class will need another function called _insertGeometry, that uses the mouse click event position on the selection item to dictate where the geometry should be inserted.
To insert the geometry, we will follow the same general steps outlined in the Building A Basic Application tutorial. We will obtain the mesh IDs, then use those mesh IDs to set mesh instance data and create the mesh instance. The inserted mesh instance will return a new node ID, indicating to the viewSync object that we need to update our model nodes.
You notice we create MeshInstanceData for each viewer – this is because once we use our MeshInstanceData, it is unavailable for use again in another viewer, so we duplicate the object and pass it to each viewer.
Lets write our last member function, setNodesToInstance. This function gathers the selection node IDs, then recursively gathers and dependent leaf nodes we may need to instance alongside it.
With this, we are able to instance nodes in the scene.
Now that our InstanceOperator class is complete, we need to update app.js to instantiate and register the operator.
First, we create and register our operator on the main viewer. Update the provided configureOperators() function with the following snippet and verify the starter code invokes the function in the constructor() for main.
Our operator is now registered with the viewer, but the operator still needs to be hooked into the UI element provided. Let’s take a look at the instance-button event callback skeleton we wrote earlier. Once again, the user to make a node selection, click the "Instance Part" button, and then select a point on the plane to insert the geometry. When the user clicks the "Instance Part" button, we want to update the button text (so they can disable to operator), gather the user selection results, and then tell HC we want to instance those nodes. We will write a setNodesToInstance member function on our InstanceOperator class to handle this. Finally, we want to disable further selections, and push (or pop) our operator to/from the stack. We also disable highlighting so no weird highlighting results happen when interacting around the scene.
To use the new InstanceOperator first select a part, click on the "Instance Part" button, and begin clicking around the plane. Each click will create another instance of that node in both the "Main" and "Overhead" viewers. Click "Disable Instancing" to stop.