data-visualizationheatmapautodesk-forgeautodesk-viewerifc

How to make the Forge Data Visualization extension work with IFC files?


I followed the tutorials from the Forge Data Visualization extension documentation: https://forge.autodesk.com/en/docs/dataviz/v1/developers_guide/quickstart/ on a IFC file and everything seems to work except for the coloring of the rooms, which appear like in the image below, instead of being colored.

IFC room

I also tested on Revit files and the rooms are being colored properly, so this issue is specific to IFC files.

The question is what could be the cause for this behavior for the IFC files and how can I solve it?

Edit: The solution is in the comments of the accepted post.


Solution

  • Sorry for the late reply. After some search, I managed to reproduce a similar behavior to yours and found a solution to fix it.

    In my case, the sensorType values I passed to DataVisualization#registerSurfaceShadingColors, DataVisualization#renderSurfaceShading, and devices' sensorType in my levelRoomMap manually created by this tutorial are not using the same character case. For example, Temperature vs temperature. After fixing the character case issue, my heatmap is redered as expected. Here is the snapshot:

    DataViz heapmap on a IFC model

    And here is my code snippet for your reference:

    async function getBoxAsync(dbId) {
        return new Promise((resolve, reject) => {
            const tree = viewer.model.getInstanceTree();
            const frags = viewer.model.getFragmentList();
            tree.enumNodeFragments(dbId, function(fragid) {
                let bounds = new THREE.Box3();
                frags.getWorldBounds(fragid, bounds);
                return resolve(bounds);
            }, true);
        });
    }
    
    function getLevel(box) {
        const floors = viewer.getExtension("Autodesk.AEC.LevelsExtension").floorSelector.floorData;
        const currentElevation = box.min.z;
    
        if (currentElevation < floors[0].zMin) {
            return floors[0];
        } else if (currentElevation > floors[floors.length - 1].zMax) {
            return floors[floors.length - 1];
        } else {
            return floors.find(f => f.zMin <= currentElevation && f.zMax >= currentElevation );
        }
    }
    
    async function getPropAsync(dbId) {
        return new Promise((resolve, reject) => {
            viewer.getProperties(dbId, result => resolve(result));
        });
    }
    
    async function getRoomName(dbId) {
        const result = await getPropAsync(dbId);
        const nameProp = result.properties.find(p => p.attributeName === 'lcldrevit_parameter_Pset_ProductRequirements_tab:lcldrevit_parameter_Name(Pset_ProductRequirements)_PG_IFC');
    
        return nameProp.displayValue;
    }
    
    async function getRoomDbIds() {
        return new Promise((resolve, reject) => {
            viewer.search( 'Rooms', resolve, reject, ['lcldrevit_parameter_Pset_SpaceCommon_tab:lcldrevit_parameter_Category(Pset_SpaceCommon)_PG_IFC'])
        });
    }
    
    async function buildRoomMap() {
        const dbIds = await getRoomDbIds();
        const DataVizCore = Autodesk.DataVisualization.Core;
        let levelRoomsMap = new DataVizCore.LevelRoomsMap();
    
    
        for ( let i = dbIds.length - 1; i >= 0; i-- ) {
            const dbId = dbIds[i];
            const box = await getBoxAsync( dbId );
            const level = getLevel( box );
            const name = await getRoomName( dbId );
    
            let room = new DataVizCore.Room(
                dbId, //Room's DbId
                name,
                box
            );
    
            levelRoomsMap.addRoomToLevel(level.name, room);
        }
    
        return levelRoomsMap;
    }
    
    async function initHeatmap() {
        const DataVizCore = Autodesk.DataVisualization.Core;
        const dataVizExtn = viewer.getExtension('Autodesk.DataVisualization');
        const levelRoomsMap = await buildRoomMap();
        const devices = [];
    
        for(let lvl in levelRoomsMap) {
            const rooms = levelRoomsMap[lvl];
            for (let i = rooms.length - 1; i >= 0; i--) {
                const room = rooms[i];
                const center = room.bounds.center();
                const device = {
                    id: `${room.name} Device`, // An ID to identify this device
                    position: center, // World coordinates of this device
                    sensorTypes: ["temperature"], // The types/properties this device exposes
                }
    
                devices.push(device);
                room.addDevice(device);
            }
        }
    
        const structureInfo = new DataVizCore.ModelStructureInfo(viewer.model);
        let shadingData = await structureInfo.generateSurfaceShadingData(devices, levelRoomsMap);
    
        await dataVizExtn.setupSurfaceShading(viewer.model, shadingData);
    
        // Set heatmap colors for temperature
        dataVizExtn.registerSurfaceShadingColors("temperature", [0x00ff00, 0xff0000]);
    
        function getSensorValue() {
            return Math.random(); // Your random function 🙂
        }
    
        // Generate the heatmap graphics (do this one time, this is heavier)
        dataVizExtn.renderSurfaceShading(Object.keys(levelRoomsMap), "temperature", getSensorValue);
        // Do this as many times as you want (this is lightweight)
        dataVizExtn.updateSurfaceShading(getSensorValue);
    
        viewer.getExtension("Autodesk.AEC.LevelsExtension").floorSelector.selectFloor(0);
    }
    
    await initHeatmap();