I was thinking back on last week’s post regarding the work needed to integrate Hyperion’s volumetric heatmaps into Dasher, and realised that – despite the relative length of the post – I’d really glossed over the process for integrating heatmaps and using them to display sensor data. So I’ve retroactively gone back and marked that post as “Part 1”, with this post being “Part 2”.
That’s not to say the process is especially complicated, but I felt it was a bit of a cop out to say “just follow the documentation”, as there was a little more to it (for us, anyway).
Here’s the basic process we now follow in Dasher to generate surface shading heatmaps using the Data Visualization Extension (i.e. Hyperion):
- Create a ModelStructureInfo for our model
- This doesn’t result in the proper data being populated for us, however – as we’re using Navisworks data – hence the need for step 2
- Build a LevelRoomsMap based on our levels, rooms and devices
- We saw the code for this in Part 1 of the series
- Call generateSurfaceShadingData(), passing in our devices and map
- In Dasher – as we’re using a Navisworks-based workflow – we currently have a separate step where we go through and create fragIds for each of our room’s dbIds: this shouldn’t be needed for Revit-based workflows, and will in any case happen automatically in an upcoming update to the Forge viewer
- Decide whether to create volumetric or planar heatmaps
- We’ll cover the latter option in an upcoming post
- Call setupSurfaceShading() with our model, shading data and configuration options
- Call registerSurfaceShadingColors() for our various sensor types and their colour schemes
- Call renderSurfaceShading() for the room or level and sensor type to be displayed, specifying the “sensor value” callback function
- On regular intervals (such as time-change events fired by the timeline), call updateSurfaceShading() with the callback function
- When done, call removeSurfaceShading()
I’ve expressed a few times, now, that I was concerned about our ability to leverage Hyperion heatmaps, mainly because we have our own internally developed, back-end, time-series database. The good news is that the callback function you pass to renderSurfaceShading() and then updateSurfaceShading() (the function they use in the docs is called getSensorValue()) actually allows you to get your sensor value from anywhere: in Dasher we have a local, browser-resident data cache that is populated with sensor readings based on the time selection in the timeline – this allows us to avoid redundant network calls when the timeline’s playing loops or restarts – but you could theoretically get this data from anywhere (even a CSV file). This makes Hyperion a much more flexible and useful component.
Here’s how we’ve implemented our getSensorValue() callback function, bearing in mind that its implementation details only make sense for Dasher. Which means this code is really just for me to show that the mechanism works (honest!), rather than being of any real value for anyone implementing their own. (We did have to implement our own clamp() function, by the way, but that’s something that’s found easily on the interwebs, in case you don’t already have an equivalent utility function.)
The fidelity of the volumetric heatmap rendering has been very good – admittedly not a huge surprise, as Hyperion’s implementation was based on Dasher’s. Having the 2D heatmaps – which are rendered using the original shader that’s (for now) still usable inside Dasher – provide a side-by-side view helps a great deal with this comparison:
This side-by-side verification has helped identify an area where the planar shading differs from the volumetric approach – something the Hyperion team is working on fixing right now. I’ll hopefully share more on planar heatmaps next week, once this fidelity issue has been addressed in an internal build.