基於 HTML5 WebGL 的樓宇智能化集成系統(一)

前言
      隨着現代通訊技術、計算機技術、控制技術的飛速發展,智能建築已經成爲現代建築發展的主流。智能建築是以建築物爲平臺,兼備信息設施系統、信息化應用系統、建築設備管理系統、公共安全系統等。集結構、系統、服務、管理及其優化組合爲一體,向人們提供一個安全、高效、便攜、節能、環保、健康的建築環境。
 
      IBMS(Intelligent Building Management System),即智能化集成系統,是指在 BAS 的基礎上更進一步的與通訊網絡系統、信息網絡系統實現更高一層的建築集成管理系統。在信息化時代的今天,諸多建築與集成的管理系統融合,生成了一套高效的智慧建築集成解決方案。 IBMS 更多突出的是管理方面的功能,即如何的全面實現優化控制和管理,節能降耗、高效、溫馨、環境安全這樣一個目的,能夠這樣說,判斷一個建築物是否具備智能建築特色,要看它是否具備 IBMS 的系統集成。這是很重要的斷定條件。另外一個重要的前提是,在作好這項工程的同時不要忽視了同步建設的信息化工程。一個成功的 IBMS 系統集成會在諸多的管理方面能發揮其顯著的經濟優點。
 
      傳統的 智慧樓宇/樓宇自動化/樓宇安防/智慧園區 常會採用 BIM(建築信息模型 Building information modeling)軟件,如 Autodesk 的 Revit 或 Bentley 這類建築和工程軟件,但這些 BIM 建模模型的數據每每過於龐大臃腫,絕大部分細節信息對樓宇自控意義不大,反而影響拖累了行業 Web SCADA 或 Web 組態監控的趨勢,因此咱們採用以 Hightopo HT for Web 產品輕量化 HTML5/WebGL 建模的方案,實現快速建模、運行時輕量化到甚至手機終端瀏覽器便可 3D 可視化運維的良好效果。
 
      本系列文章爲了幫助用戶更直觀友好的瀏覽當前的樓宇智控系統,分紅了三個小節來介紹場景以及效果實現的運用:
一、 冷站熱站中央空調末端智慧羣控系統 以及 3D 動畫效果以及切換漫遊;
二、面板組件動畫效果和  樓層監控系統 視頻的引入;
三、 智慧樓宇管理系統電梯監控系統 以及  停車場管理系統
 
界面簡介及效果預覽
界面初始化及漫遊效果
      場景在加載的時候會讀取模型信息,確認模型加載完畢後纔開始執行動畫效果,而後經過場景的漫遊效果,能夠直觀地去巡視整座大樓建築的場景信息。
 
 
冷站場景效果:優化冷水機組效率,按需供給
      在智慧樓宇的中央空調冷熱源系統中,冷站場景分有冷卻水系統、冷水機組以及冷凍水系統所組成。冷卻水系統的做用是爲冷水機組的冷凝器提供冷卻水,吸取製冷劑的冷凝熱量,並將冷凝熱量轉移到大氣中去。冷凍水系統的做用是爲冷水機組的蒸發器提供的冷量經過冷凍水輸送到各種冷水用戶。
 
 
熱站場景效果:優化熱泵機組效率,按需供給
      在智慧樓宇的中央空調冷熱源系統中,熱站場景分有冷卻機組系統和熱水泵系統所組成。經過冷卻機組系統的換熱器不斷加熱了中央空調系統內的空調水,並經過熱水循環中的熱水泵系統進行循環給用戶提供熱量。
 
中央空調末端智慧羣控系統場景效果:靈活對應多樣智能調節空間
      在智慧樓宇的中央空調冷熱源系統中,末端智能節能控制系統,經過室內溫溼度能夠進行模塊內部的調節送風溫度,水閥開度及風機頻率,在保證末端溫馨度的前提下,使供冷量與需求相匹配,最大限度地下降風機能耗。
 
智慧樓宇管理系統優化效果
      主要包括冷站、熱站和中央末端智慧羣控的聯合做用,以及樓層智慧照明,經過清晰的動畫體現出整棟大樓智慧節能運做的流程,能夠經過面板詳情的演示細緻地介紹每一個場景的做用以及串聯的用處。
 
電梯以及樓層監控效果
      可視化地實時監控電梯在樓層間的工做運行狀態,而且可以準確地瀏覽每一個電梯內的實時監控畫面。
 
 
停車場管理系統監控效果
      停車場做爲如今樓宇監控不可缺失的一環,這裏主要能夠體現出實時的車位監控,經過簡單的動畫演示來表現出整個停車場車輛的運行狀態,方便管理。
 
代碼實現
1、場景搭建
      界面經過 2D 圖紙疊加在3D 場景上來實現 2D 界面 與 3D 場景的融合,2D 界面經過自動佈局的機制實現了手機端與電腦端的響應式呈現。
      經過 2D 視圖的組件 ht.graph. GraphView 和 3D 視圖的組件 ht.graph3d. Graph3dView 建立出呈現 2D 視圖的組件類 g2d 以及呈現 3D 視圖的組件類 g3d,在分別獲取各自的數據模型 DataModel,來對圖紙場景作一些數據可視化的操做,這裏值得一提的是,我對於 2D 界面和 3D 場景的融合,是經過把 getView() 獲取到 g3d 拓撲組件的根層 div,而後 addToDOM() 將 g2d 組件加入到指定的 DOM 元素底下。
      能夠經過<HT的入門手冊>瞭解到更多視圖與數據模型之間的內容。
// 建立二維拓撲視圖
this.g2d = new ht.graph.GraphView();
this.g2dDm = this.g2d.dm();

// 建立三維拓撲視圖
this.g3d = new ht.graph3d.Graph3dView();
this.g3dDm = this.g3d.dm();

// 將二維圖紙嵌入到三維場景中
this.g2d.addToDOM(this.g3d.getView());

// 修改左右鍵交互方式
let mapInteractor = new ht.graph3d.MapInteractor(this.g3d);
this.g3d.setInteractors([mapInteractor]);

// 修改最大仰角爲 PI / 2
mapInteractor.maxPhi = Math.PI / 2;

const G = {};
window.G = G;
// 事件派發
G.event = new ht.Notifier();

 

3D 場景加載主視圖爲:html

 

      首先我搭建了一個 3D 的場景用來放置咱們的 json 場景數據,利用 ht.Default.xhrLoad 函數解析 json 場景數據,並經過 deserialize 將反序列化的對象加入DataModel來顯示加載 3D 場景,有興趣的能夠經過<HT的序列化手冊>來了解這一機制的實現。json

ht.Default.xhrLoad('scenes/demo.json', (json) => {
    if (!json) return;
    g3dDm.deserialize(json);

    // 設置三維視圖的中心點和相機位置
    g3d.setCenter([-342, -64, 389]);
    g3d.setEye([-355, 10833, 2642]);

    // 設置最遠距離
    g3d.setFar(1000000);
    // 獲取球圖標,設置爲天空球
    let skybox = g3dDm.getDataByTag('skyBox');
    g3d.setSkyBox(skybox);

    // 模型加載完後執行動畫
    const modelList = [];
    g3dDm.each(d => {
        const shape3d = d.s('shape3d');
        if (!shape3d || !shape3d.endsWith('.json')) return;
        if (ht.Default.getShape3dModel(shape3d)) return;
        modelList.push(shape3d);
    });
    ht.Default.handleModelLoaded = (name, model) => {
        const index = modelList.indexOf(name);
        if (index < 0) return;
        modelList.splice(index, 1);
        if (modelList.length > 91) return;
        ht.Default.handleModelLoaded = () => {
        };

        // 模型加載完侯,默認執行場景切換動畫
        g3d.moveCamera([257, 713, 1485], [7, 40, 144], {
            duration: 2000,
            finishFunc: () => {
                this.load2D();
            }
        });
    };
});

 

2D 面板加載視圖爲:數組

 

      一樣,我搭建了一個 2D 的場景用來放置咱們的 json 矢量圖,利用 ht.Default.xhrLoad 函數將 json 矢量背景圖反序列化顯示在 2D 面板數據。瀏覽器

ht.Default.xhrLoad('displays/demo.json', (json) => {
    if (!json) return;
    g2dDm.deserialize(json);

    // 面板動畫入口
    this.tittleAnim();
    this.panelTime();

    // 2D圖紙加載完後執行事件處理
    this.loaded2DHandler();
});

 

2、3D 動畫效果以及切換漫遊緩存

      對於 3D 建模下的樓宇建築,加上場景的全方位漫遊,可以使用戶達到一種沉浸式的體驗,更加直觀地去感覺這個樓宇下各個場景的聯繫,依次地介紹了冷站、智慧末端以及熱站的位置以及功能運做的動畫 。主要運用的方法是經過藉助 HT 提供的 ht.Shape 圖元類型,能夠在 GraphView 和 Graph3dView 組件上展現出各類二維和三維的形狀效果,而漫遊的管道路線就是由其擴展子類 ht.Polyline 去繪製實現一條三維的管道,而後用這條繪製的管道加上漫遊的時間去調用這個漫遊的方法,其本質上是圍繞着中心點,而後根據管道去不斷地改變視角下的 eyecenter 的數值,達到環視這個建築的總體視角。安全

      這裏能夠了解一下關於空間軌道的繪製,詳見<HT的形狀手冊>的空間管線章節。網絡

      如下是環視漫遊動畫的僞代碼:運維

polyLineRoam(polyLine, time) {
    const g3d = this.g3d;
    const g3dDm = this.g3dDm;
    this.roamButton.a('active', true);
    this.roamAnim = ht.Default.startAnim({
        duration: time,
        easing: t => t,
        action: (v, t) => {
            let length = this.main.g3d.getLineLength(polyLine),
            offset = this.main.g3d.getLineOffset(polyLine, length * v),
            point = offset.point,
            px = point.x,
            py = point.y,
            pz = point.z;

            g3d.setEye(px, py, pz);
            g3d.setCenter(7, 40, 144);
        },
        finishFunc: () => {
            this.roam1();
        }
    });
}

 

      在總體建築的環視漫遊完後,咱們能夠經過拉近各個場景的視角,來依次巡視各個場景所執行的動畫。在根據管道改變 eye center 環視漫遊方法結束後,用動畫的結束回調 finishFunc 去調用下一個動畫的執行,而巡視漫遊就在這裏去調用,如下咱們以巡視冷站的漫遊動畫爲例去介紹實現的方法。ide

      巡視漫遊的主要實現方法是經過 HT 核心包的相機移動 moveCamera 來實現的, 經過參數 (eye, center, animation) 來調用這個方法:函數

  • eye:新的相機位置,形如[-291, -8, 283],若是爲 null 則使用當前相機的位置;
  • center:新的目標中心點位置(相機看向的位置),形如[148, -400, 171],若是爲 null 則使用當前中心點位置;
  • animation:默認 false,是否啓用動畫,能夠設置爲 true 或者 flase 或者 animation 動畫對象;

      每次執行完一個場景的視角移動後,再經過相機移動動畫的結束回調 finishFunc 調用下一個相機移動的動畫,達到巡視漫遊的效果。

// 切換到冷站視角
roam1() {
    const g3d = this.g3d;
    const g3dDm = this.g3dDm;
    this.roamAnim = g3d.moveCamera([-291, -8, 283], [148, -400, 171], {
        duration: 500,
        easing: t => t * t,
        finishFunc: () => {
            this.roam2();
        }
    });
}

 

      在環視漫遊和巡視漫遊的執行下,咱們也能夠觸發 2D 圖紙右面板下的按鈕面板去觀看咱們想要瀏覽的指定場景,這時候就會關閉當前在執行的環視漫遊或者巡視漫遊,再次點擊改按鈕則返回場景的主視角,或者點擊左上角漫遊按鈕又能夠進入環視漫遊,這樣的交互體驗,能夠方便用戶即便地查看想要瀏覽的場景,而不用依靠等待逐一漫遊下去查看,也不會干擾到漫遊的總體體驗。相應地經過介紹冷站按鈕的點擊觸發介紹一下實現的方法。

      通常的交互方式存在三種事件交互的方法,包括事件通知管理器 ht.Notifier 類,內置的 Interator 在交互過程會派發出事件和數據綁定的監聽來實現,而這裏使用的是第三種交互方式。

      經過數據綁定監聽到 onDown 執行按下的事件後,經過改變按下和再次按下的按鈕狀態 active 來分別執行相機移動去切換視角,主要實現的僞代碼以下:

// 設置圖元可交互
this.coolingCentralStationButton.s('interactive', true);
// 經過數據綁定監聽到onDown執行按下的事件
this.coolingCentralStationButton.s('onDown', () => {
// 切換到冷站時,2d面板所執行的切換動畫
this.switchToColdStation();
// 按鈕初始化
this.buttonTearDown();
// 按鈕按下效果的狀態
    let active = this.coolingCentralStationButton.a('active');
    // button爲按鈕集合數組,當按下電梯按鈕,其餘按鈕默認false
    button.forEach(btn => {
        btn.a('active', false);
    });
    // 冷站按鈕的狀態切換
    this.coolingCentralStationButton.a('active', !active);
    // 根據冷站按鈕的狀態執行切換到冷站或者切換回主視角
    if (active) {
        // 相機移動切換到主視角
        moveCamera(g3d, [257, 713, 1485], [7, 40, 144], {
            duration: 2000,
            easing: t => t * t
        });
    } else {
        // 漫遊動畫對象若是不爲空,則暫停漫遊動畫對象而且設置爲空
        if (this.roamAnim !== null) {
            this.roamAnim.pause();
            this.roamAnim = null;
        }
        // 相機移動切換到冷站視角
        coolingCentralStationAnimation = moveCamera(g3d, [-291, -8, 283], [148, -400, 171], {
            duration: 2000,
            easing: t => t * t
        });
    }
});

 

      固然,在 3D 場景下還有一些頗有趣的動畫效果,好比車流效果、飛光效果和圓環擴散效果。車流效果主要經過採用了貼圖的 uv 的偏移來實現達到車流穿梭的科技感效果;而飛光效果則是採用調度動畫的方法來間隔設置飛光的高度,達到最高點則消失而後從新輪迴動畫展現;圓環擴散效果則是一樣採用調度動畫的方法來間隔設置圓環的縮放值和透明度,來達到擴散消失的效果。

      對於間隔的調度動畫,爲了實現動畫的流暢性,這裏調度使用的 loop 是運用到本身封裝 HT 的動畫 ht.Default.startAnim 的一個方法:

  • frames 動畫幀數,這裏不鎖定幀數,能夠適應自己動畫的幀數;
  • interval 動畫間隔,單位ms,默認設置20ms。
loop(action, interval = 20) {
    return ht.Default.startAnim({
        frames: Infinity,
        interval: interval,
        action: action
    });
}

 

      而後經過調用這個 loop 的間隔動畫方法,咱們來實現車流效果、飛光效果和圓環擴散效果,實現的參考僞代碼以下:

// 車流圖元的初始化
let traffic = g3dDm.getDataByTag('traffic');
// 圓環擴散圖元的初始化
let lightRing = this.lightRing = g3dDm.getDataByTag('lightRing');
// 飛光圖元設置三種透明狀態數組集合flyMap的初始化
[1, 2, 3].forEach(i => {
    const data = flyMap['fly' + i] = g3dDm.getDataByTag('fly' + i);
    data.eachChild(d => {
        d.s({
            // 打開透明度
            'shape3d.transparent': true,
            // 根據不一樣的數組集合設置不一樣的透明度
            'shape3d.opacity': i === 3 ? 0.5 : 0.7,
            // 設置沿着y軸自動旋轉
            'shape3d.autorotate': 'y'
        });
    });
});

if (this.flyAnim) return;
this.flyAnim = loop(() => {
    // 飛光根據間隔設置高度來達到上升的效果
    for (let k in flyMap) {
        const data = flyMap[k];
        let e = data.getElevation() + flyDltMap[k];
        if (e >= 500) e = -400;
        data.setElevation(e);
    }

    // 車流根據設置間隔增加uv偏移量來實現穿梭的效果
    traffic.eachChild(c => {
        c.s('all.uv.offset', [location, 0]);
    });
    location -= 0.03;

    // 旋轉震盪波透明度漸降
    let percent = lightRing.a('percent') || 0,
        scale = 15 * percent + 0.5;
    lightRing.setScale3d([scale + 1, scale, scale + 1]);
    lightRing.s('shape3d.opacity', (1 - percent) * 0.5);
    percent += 0.01;
    if (percent >= 1) {
        percent = 0;
    }
    lightRing.a('percent', percent);
}, 50);

 

3、冷站場景和熱站場景的動畫實現

      場景動畫中機組的風扇、集水器的蓄滿以及水的流動效果:

      動畫的實現主要仍是經過 HT 自帶的 ht.Default.startAnim 動畫函數,支持 Frame-Based 和 Time-Based 兩種方式的動畫。一樣的,咱們這裏使用的是 Frame-Based 來封裝一個 loop 函數來執行每一幀間隔的動畫。

      通常來講,動畫可經過自行配置來達到本身想要實現的方法,這裏能夠了解< HT 的入門手冊>關於動畫函數的介紹。

if (this.stationAnim) return;
this.stationAnim = loop(() => {
    // 冷站水管流動
    coldFlow_blue.eachChild(c => {
        c.s('shape3d.uv.offset', [-location, 0]);
    });
    coldFlow_yellow.eachChild(c => {
        c.s('shape3d.uv.offset', [location, 0]);
    });

    // 熱站水管流動
    heatFlow_blue.eachChild(c => {
        c.s('shape3d.uv.offset', [-location, 0]);
    });
    heatFlow_yellow.eachChild(c => {
        c.s('shape3d.uv.offset', [location, 0]);
    });

    location -= 0.03;

    // 冷站風扇旋轉
    cold_fan.eachChild(c => {
        c.setRotation3d(c.r3()[0], c.r3()[1] + (Math.PI / 10), c.r3()[2]);
    });
    // 熱站風扇旋轉
    heat_fan.eachChild(c => {
        c.setRotation3d(c.r3()[0], c.r3()[1] + (Math.PI / 10), c.r3()[2]);
    });

    // 集水器水位變化
    HotWaterTankTall += 0.25;
    if (HotWaterTankTall > 15) {
        HotWaterTankTall = 0;
    }
    coldWaterTankTall1 += 0.25;
    if (coldWaterTankTall1 > 20) {
        coldWaterTankTall1 = 0;
    }
    coldWaterTankTall2 += 0.25;
    if (coldWaterTankTall2 > 20) {
        coldWaterTankTall2 = 0;
    }
    hotWaterTank.setTall(HotWaterTankTall);
    coldWaterTank1.setTall(coldWaterTankTall1);
    coldWaterTank2.setTall(coldWaterTankTall2);
}, 50);

 

4、中央空調末端智慧羣控系統場景效果

      這裏採用了模擬數據的方式來體現末端智能節能控制的效果。應用於真實項目的時候,能夠採用數據接口的方式來實時對接真實數據,能夠達到實時監控的效果。

      我使用了本身 mock 的末端羣控的數據參數,格式以下:

var boxData =
    [
        [{
            // 設備編號
            id: 'box1',
            // 設備的溫度
            temperature: 23.8,
            // 設備的頻率
            frequency: 45.8
        }, ...]
        ...
    ];

 

      這裏的實現也是經過 loop 循環執行數據的讀取,當數組指標 index 讀取到最後一個數據時,當即關閉循環並清空 loop調度。

boxAnimation = loop(() => {
        for (let i = 0, l = 16; i <= l-1; i++) {
            let roomTag, roomBox, tag;
            tag = i+1;
            roomTag = 'boxPanel' + tag;
            roomBox = 'box' + tag;

            let panel = g3dDm.getDataByTag(roomTag);
            let box = g3dDm.getDataByTag(roomBox);
            if (panel) {
                panel.a('valueT', boxData[index][i].temperature + '℃');
                panel.a('valueK', boxData[index][i].frequency + 'Hz');
                // 手動更新緩存的面板信息
                g3d.invalidateShape3dCachedImage(panel);
                // 根據溫度判斷設備的顏色
                if (box && parseFloat(panel.a('valueT')) < 26) {
                    box.s('shape3d.blend', 'rgb(4,67,176)');
                    box.s('wf.color', 'rgb(4,67,176)');
                } else if (box && parseFloat(panel.a('valueT')) >= 26 && parseFloat(panel.a('valueT')) <= 28) {
                    box.s('shape3d.blend', 'rgb(28,189,87)');
                    box.s('wf.color', 'rgb(28,189,87)');
                } else if (box && parseFloat(panel.a('valueT')) > 28) {
                    box.s('shape3d.blend', 'rgb(181,43,43)');
                    box.s('wf.color', 'rgb(181,43,43)');
                }
            }
        }
        index++;
        if (index >= 10) {
            boxAnimation.pause();
            boxAnimation = null;
        }
    }, 500);

 

總結

      IBMS 智能化集成系統管理對於建築園區管理的重要性日趨上升,在信息時代裏不只能夠很好地體現出信息數據管理的明確性,也體現了智慧管理的便利有效性。經過 3D 場景樓宇園區的動畫加上環視漫遊和巡視漫遊的配合,充分體現了 3D 場景的擬真優勢,可是如何實現場景動畫的觸發實現呢?這裏固然必不可少了 2D 面板上的交互和動畫,在下期咱們會爲你們介紹一些 2D 面板的交互和動畫實現,帶您解讀不同的 2D/3D 融合。
 
      2019 咱們也更新了數百個工業互聯網 2D/3D 可視化案例集,在這裏你能發現許多新奇的實例,也能發掘出不同的工業互聯網: https://mp.weixin.qq.com/s/ZbhB6LO2kBRPrRIfHlKGQA
      同時,你也能夠查看更多案例及效果: https://www.hightopo.com/demos/index.html
相關文章
相關標籤/搜索