Is there a way to create a SurfaceShadingNode without passing a dbId of existing Room created in Revit?
According to API documentation, I understand that I can create a LevelRoomMap using custom bounds and then use it to generate SurfaceShadingData. For that, I have to restructure my code.
So, I would be grateful if someone could help me with way to define a SurfaceShadingNode with custom bounds.
Thanks! Bandu
Unfortunately, it is impossible to create SurfaceShadingNode
without passing dbIds
due to its implementation, but we can use Scene Builder to add custom geometries with the dbId
support.
/////////////////////////////////////////////////////////////////////
// Copyright (c) Autodesk, Inc. All rights reserved
// Written by Forge Partner Development
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM 'AS IS' AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
/////////////////////////////////////////////////////////////////////
(function () {
/**
* Helper of converting THREE.Box3 to THREE.Mesh
* @class
*/
class BoxMeshHelper extends THREE.Mesh {
constructor(box) {
const geometry = new THREE.BufferGeometry();
const positionNumComponents = 3;
const normalNumComponents = 3;
const uvNumComponents = 2;
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(36 * positionNumComponents), positionNumComponents));
geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(36 * positionNumComponents), normalNumComponents));
geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(36 * uvNumComponents), uvNumComponents));
super(geometry, new THREE.MeshPhongMaterial({ color: 0xffff00, side: THREE.DoubleSide, opacity: 0.4, transparent: true }));
this.type = 'BoxMeshHelper';
this.box = box;
this.positionNumComponents = 3;
this.normalNumComponents = 3;
this.uvNumComponents = 2;
this.update();
}
update() {
const box = this.box;
if (box.isEmpty()) return;
const min = box.min;
const max = box.max;
/*
5____4
1/___0/|
| 6__|_7
2/___3/
0: max.x, max.y, max.z
1: min.x, max.y, max.z
2: min.x, min.y, max.z
3: max.x, min.y, max.z
4: max.x, max.y, min.z
5: min.x, max.y, min.z
6: min.x, min.y, min.z
7: max.x, min.y, min.z
*/
const vertices = [
// front
{ pos: [min.x, min.y, max.z], norm: [0, 0, 1], uv: [0, 1], },
{ pos: [max.x, min.y, max.z], norm: [0, 0, 1], uv: [1, 1], },
{ pos: [min.x, max.y, max.z], norm: [0, 0, 1], uv: [0, 0], },
{ pos: [min.x, max.y, max.z], norm: [0, 0, 1], uv: [0, 0], },
{ pos: [max.x, min.y, max.z], norm: [0, 0, 1], uv: [1, 1], },
{ pos: [max.x, max.y, max.z], norm: [0, 0, 1], uv: [1, 0], },
// right
{ pos: [max.x, min.y, max.z], norm: [1, 0, 0], uv: [0, 1], },
{ pos: [max.x, min.y, min.z], norm: [1, 0, 0], uv: [1, 1], },
{ pos: [max.x, max.y, max.z], norm: [1, 0, 0], uv: [0, 0], },
{ pos: [max.x, max.y, max.z], norm: [1, 0, 0], uv: [0, 0], },
{ pos: [max.x, min.y, min.z], norm: [1, 0, 0], uv: [1, 1], },
{ pos: [max.x, max.y, min.z], norm: [1, 0, 0], uv: [1, 0], },
// back
{ pos: [max.x, min.y, min.z], norm: [0, 0, -1], uv: [0, 1], },
{ pos: [min.x, min.y, min.z], norm: [0, 0, -1], uv: [1, 1], },
{ pos: [max.x, max.y, min.z], norm: [0, 0, -1], uv: [0, 0], },
{ pos: [max.x, max.y, min.z], norm: [0, 0, -1], uv: [0, 0], },
{ pos: [min.x, min.y, min.z], norm: [0, 0, -1], uv: [1, 1], },
{ pos: [min.x, max.y, min.z], norm: [0, 0, -1], uv: [1, 0], },
// left
{ pos: [min.x, min.y, min.z], norm: [-1, 0, 0], uv: [0, 1], },
{ pos: [min.x, min.y, max.z], norm: [-1, 0, 0], uv: [1, 1], },
{ pos: [min.x, max.y, min.z], norm: [-1, 0, 0], uv: [0, 0], },
{ pos: [min.x, max.y, min.z], norm: [-1, 0, 0], uv: [0, 0], },
{ pos: [min.x, min.y, max.z], norm: [-1, 0, 0], uv: [1, 1], },
{ pos: [min.x, max.y, max.z], norm: [-1, 0, 0], uv: [1, 0], },
// top
{ pos: [max.x, max.y, min.z], norm: [0, 1, 0], uv: [0, 1], },
{ pos: [min.x, max.y, min.z], norm: [0, 1, 0], uv: [1, 1], },
{ pos: [max.x, max.y, max.z], norm: [0, 1, 0], uv: [0, 0], },
{ pos: [max.x, max.y, max.z], norm: [0, 1, 0], uv: [0, 0], },
{ pos: [min.x, max.y, min.z], norm: [0, 1, 0], uv: [1, 1], },
{ pos: [min.x, max.y, max.z], norm: [0, 1, 0], uv: [1, 0], },
// bottom
{ pos: [max.x, min.y, max.z], norm: [0, -1, 0], uv: [0, 1], },
{ pos: [min.x, min.y, max.z], norm: [0, -1, 0], uv: [1, 1], },
{ pos: [max.x, min.y, min.z], norm: [0, -1, 0], uv: [0, 0], },
{ pos: [max.x, min.y, min.z], norm: [0, -1, 0], uv: [0, 0], },
{ pos: [min.x, min.y, max.z], norm: [0, -1, 0], uv: [1, 1], },
{ pos: [min.x, min.y, min.z], norm: [0, -1, 0], uv: [1, 0], },
];
const positions = [];
const normals = [];
const uvs = [];
for (const vertex of vertices) {
positions.push(...vertex.pos);
normals.push(...vertex.norm);
uvs.push(...vertex.uv);
}
this.geometry.attributes.position = new THREE.BufferAttribute(new Float32Array(positions), this.positionNumComponents);
this.geometry.attributes.normal = new THREE.BufferAttribute(new Float32Array(normals), this.normalNumComponents);
this.geometry.attributes.uv = new THREE.BufferAttribute(new Float32Array(uvs), this.uvNumComponents);
this.geometry.attributes.position.needsUpdate = true;
this.geometry.attributes.normal.needsUpdate = true;
this.geometry.attributes.uv.needsUpdate = true;
this.geometry.computeBoundingSphere();
}
}
class DataVizCustomBoundsExt extends Autodesk.Viewing.Extension {
constructor(viewer, options) {
super(viewer, options);
this.dbIdPrefix = 1000;
}
get dataVizExt() {
return this.viewer.getExtension('Autodesk.DataVisualization');
}
get sceneBuilderExt() {
return this.viewer.getExtension('Autodesk.Viewing.SceneBuilder');
}
async renderBounds(bounds) {
if (!(bounds instanceof THREE.Box3)) return;
let mesh = new BoxMeshHelper(bounds);
let boundMesh = new THREE.Mesh(
mesh.geometry.clone(),
this.boundsMaterial
);
boundMesh.dbId = ++this.dbIdPrefix;
this.modelBuilder.addMesh(
boundMesh
);
const shadingGroup = new Autodesk.DataVisualization.Core.SurfaceShadingGroup('Bounds');
const boundNode = new Autodesk.DataVisualization.Core.SurfaceShadingNode(`Bound ${boundMesh.dbId}`, boundMesh.dbId);
boundNode.addPoint(
new Autodesk.DataVisualization.Core.SurfaceShadingPoint('Bound sensor', bounds.center(), ['Temperature'])
);
shadingGroup.addChild(boundNode);
const heatmapData = new Autodesk.DataVisualization.Core.SurfaceShadingData();
heatmapData.addChild(shadingGroup);
// Initialize with model loaded from forge
let model = this.modelBuilder.model;
heatmapData.initialize(model);
await this.dataVizExt.setupSurfaceShading(model, heatmapData);
this.dataVizExt.renderSurfaceShading('Bounds', 'Temperature', this.getSensorValue);
}
getSensorValue() {
return Math.random();
}
async load() {
await Promise.all([
this.viewer.loadExtension('Autodesk.Viewing.SceneBuilder'),
this.viewer.loadExtension('Autodesk.DataVisualization'),
]);
await this.viewer.waitForLoadDone();
this.modelBuilder = await this.sceneBuilderExt.addNewModel({
conserveMemory: false,
modelNameOverride: 'Custom Bounds',
loadAsHidden: true
});
const matName = 'bounds-mat';
const boundsMat = new THREE.MeshPhongMaterial({ color: 0xffff00, side: THREE.DoubleSide, opacity: 0.4, transparent: true });
this.modelBuilder.addMaterial(matName, boundsMat);
this.boundsMaterial = this.modelBuilder.findMaterial(matName);
return true;
}
unload() {
this.dataVizExt.removeSurfaceShading(this.modelBuilder.model);
this.viewer.unloadModel(this.modelBuilder.model);
return true;
}
}
Autodesk.Viewing.theExtensionManager.registerExtension('Autodesk.ADN.DataVizCustomBoundsExt', DataVizCustomBoundsExt);
})();
const dataVizCustomBoundsExt = await viewer.loadExtension('Autodesk.ADN.DataVizCustomBoundsExt');
// Custom bounds
let bounds = new THREE.Box3(new THREE.Vector3(-87.49999999999999, -123.7500076293945, -29.434711456298828), new THREE.Vector3(0, -0.0000018146972706745137, 0));
dataVizCustomBoundsExt.renderBounds(bounds);