I’ve been spending quite a bit of time exploring how Project Dasher might make use of the platform capabilities of Autodesk Tandem. This is just one effort connecting the two projects, and the one I tend to think of as “Tandem inside Dasher”: the Tandem team is looking what makes sense in terms of “Dasher inside Tandem” (i.e. which Dasher features it makes sense to surface in Tandem for their customers).
As I’ve hopefully said before, Autodesk Tandem fills a really important gap in the process to build out a model-centric digital twin: Project Dasher project was never intended to solve the broader problem of digital handover, and was based on the premise that you’d start with a high-quality, as-built model of your facility. Which would – by the way – be out-of-date the moment it was integrated, as the model was considered a static resource.
Tandem flips this around and focuses on building out features that make it easier for its users to keep the digital representation of their facility in sync with reality. This makes Tandem hugely complementary to the vision behind Dasher, and has allowed us to focus on visualization of data coming from connected assets that will hopefully one day be managed within Tandem.
(In case you’re interested in some specifics of how Tandem helps your model become more dynamic – and more of a digital twin – one aspect of this is the Revit plugin that helps bring data defined in Tandem back into the modelling environment. So you can see metadata changes made inside Tandem appear inside Revit, and even make changes in Revit that go straight back to Tandem without having to go through the translation step.)
Anyway, all this means that I’ve been working to test out what it means to build a connected digital twin using the Tandem platform. This platform is not currently available publicly, and I have no knowledge of or insights into when this situation might change. I’m not going to share specific details of the platform itself, but I did want to describe some areas that Forge developers can already work on in anticipation of one day leveraging the Tandem platform themselves.
It’s a fairly short list of things you need to think about, thankfully. Today the Tandem viewer is very similar in nature to the Forge viewer; it just reads its model data from a database rather than a series of files. There are some really important differences in the way it deals with models, however, at least with respect to the assumption we originally made in the Forge-based version of Dasher.
My use of the above image was inspired by this Tweet. It’s just so perfect.
To simplify the management of projects in Dasher, some time ago we made the decision to use exporting to NWC (a compressed Navisworks file) as a key part of the workflow: it just made it easier to have everything model-related in a single file. So however many Revit models were part of a project, we’d ask for everything to munged together into a .NWC before loading into Dasher (via the Forge translation and model derivative services, of course). Aside from the simplicity of dealing with a single file – and a much smaller one, too – this approach gave us room information, which Dasher very much needs to function (unless your model doesn’t have or need rooms – such as the MX3D bridge – of course). So throughout Dasher’s codebase we have the baked-in assumption that Dasher would be dealing with a single model inside the viewer.
This assumption is completely false for Tandem, which leverages the ability of the viewer to deal with multiple models to the max. This makes perfect sense, as a complex facility could clearly be an aggregation of many, many Revit (or other) projects, and the user may want to choose to work in one or more sub-projects, without the full project loaded. This will have significant implications for Forge developers using Tandem as a data-source for their digital twins, though.
In Dasher we have lots of lists such as “the dbIds of rooms on each level” and “the dbIds of sensors per room”. One problem that arises when dealing with multiple models – and maintaining dbIds that refer to objects in these models – is that dbIds are only unique within the context of a particular model. And when you’re dealing with a multi-model environment, you need to make sure you know which model a particular dbId belongs to, if you want to do things such as access an object’s properties or compute its bounding box.
So all of these data structures containing lists of dbIds – or using dbIds as object keys – need to be rethought to include the model in some way.
Before talking about that, it’s worth being clear about something: the Forge viewer has supported the loading of multiple models for some years – it was possible at least as far back as v6, but it seems the mechanism to load models changed with the introduction of v7. Many applications using the viewer – such as the BIM360 model coordination environment – have already grappled with the need to deal with multiple models. I’m guessing that many Forge developers have – like the Dasher team – not had to deal with this additional step, however. I hope that this post sets at least some people on the path to supporting multiple models and therefore – at some point, once it’s available – more easily leveraging the Tandem platform.
What specific steps have we taken inside Dasher, then?
- Whenever we’ve stored a list of dbIds in memory, we’ve also stored the indices of their models (you can then look up the model in viewer.impl.modelQueue().getModels(), or the equivalent Tandem API once it’s available).
- This could be stored as a list of tuples or as separate lists with the same indexing, whichever your prefer (I tend towards the latter, personally).
- It should be noted that dbIds should not be assumed to be unique across sessions: if you do choose to persist them then it should be for a specific version, and so they should not be relied on not changing at all for Tandem.
- I expect there to be a way to persist references to Tandem objects between sessions, but that’s a topic for a future post (once the platform is available).
- When you have an object that uses a dbId as its key, you need to combine the model index or ID with the dbId.
- We’ve mostly used “model.id + ‘-‘ + dbId”, but as in the previous step an index should work just as well.
- Scan through for any use of viewer.model (or viewer.impl.model) to make sure you’re not just assuming a single model.
- Look for functions that use an optional model parameter, and make sure the parameter is being used (and not just with viewer.model).
- Examples include hide(), show(), isolate() and fitToView().
- Get the instanceTree for the correct model when needing to query data (such as the bounding box) for a particular dbId.
- We had this come up a lot.
- There are set of ‘aggregate’ methods and events that make it much easier to select/isolate geometry (and find out when selection/isolation happens) with multiple models.
- From the aggregate events you can access the model from the event object passed in, which is really handy.
This process was quite a big deal for Dasher, but we’ve managed to get most things working properly. Hopefully it’s less painful for others. If you do go through this process (or have gone through it, in the past) and have suggestions of additions, please do post a comment.
Thanks to Michael Beale, Traian Stanev and James Awe, who graciously took the time to review and provide input for this post. Any mistakes are still very much mine, however.