智慧樓宇和人們的生活息息相關,樓宇智能化程度的提升,會極大程度的改善人們的生活品質,在當前 工業互聯網 大背景下受到很大關注。目前 智慧樓宇可視化監控 的主要優勢包括:html
衣食住行每每是不可或缺,而樓宇建設一直是社會發展進步的一塊基點。以往的管理方式,須要細緻地劃分各個模塊的實施,但各個模塊又相對獨立,在管理成本上和人力投入上都耗費了許多的精力。現現在在科技日益發展的道路上,咱們歷經了 工業互聯網 的浪潮,又順應了 5G 新時代、新基建 的發展,工業4.0 不單勢在必行,而是已經步步落實。經過技術發展的經驗總結,咱們能夠在互聯網實施多樣化行業可視化系統監控管理方案,智慧樓宇可視化系統亦是如此,經過一套完備的子系統串聯,整理出可視化在線管理系統的集合,極大提高了管理能力和節省勞動力的投入。node
傳統的 智慧樓宇/樓宇自動化/樓宇安防/智慧園區 常會採用 BIM(建築信息模型 Building information modeling)軟件,如 Autodesk 的 Revit 或 Bentley 這類建築和工程軟件,但這些 BIM 建模模型的數據每每過於龐大臃腫,絕大部分細節信息對樓宇自控意義不大,反而影響拖累了行業 Web SCADA 或 Web 組態監控的趨勢,因此咱們採用以 Hightopo 的 HT for Web 產品輕量化 HTML5/WebGL 建模的方案,實現快速建模、運行時輕量化到甚至手機終端瀏覽器便可 3D 可視化運維的良好效果。api
本篇文章經過對智能建築的建模,頁面動畫效果的實現,以及頁面主要功能點進行闡述,幫助咱們瞭解如何使用 HT 實現一個簡單的智慧樓宇可視化監控,以及幫助咱們瞭解智慧樓宇,樓宇自動化的優點。數組
預覽地址:基於 HTML5 的 WebGL 樓宇自控 3D 可視化監控 http://www.hightopo.com/demo/ht-smart-building/瀏覽器
界面經過 2d 圖紙疊加在 3d 場景上來實現 2d 界面 與 3d 場景的融合,2d 界面經過自動佈局的機制實現了手機端與電腦端的響應式呈現。網絡
界面初始化過程當中的動畫包括地面路徑的實時渲染,樓層的展開,樓層的輝光掃描,樓層報警點動態水波,樓層監測數據面板的實時變化等等。運維
監控界面包括:dom
該 3d 場景中全部的模型均爲線段和六面體搭建,相比較經過 3d Max 建模而後經過 obj 導入來講場景中的三角面會少不少,更加的輕量化,例如場景中建築的樓層,經過 ht.Shape 類繪製,該類中記錄着樓層 points 點的信息以及 segments 爲 ht.List 類型的線段數組信息,segments 表明着點的鏈接方式,用於告訴 ht.Shape 利用點的信息來繪製二次貝塞爾曲線或者三次貝塞爾曲線或者直線等信息,相關具體說明請參考 HT for Web 的[形狀手冊],如下爲繪製單層的截圖:ide
經過上圖能夠知道構建完一層模型以後其它幾層模型均爲相同的,只是 y 軸的數值不一樣,經過疊加幾層以後即可造成一幢大樓的輪廓。若是用戶須要搭建智慧園區,智慧樓宇等場景,徹底可使用這種基於 HTML5/WebGL 建模的方案,減小考慮使用 BIM 建模模型。場景中的管道以及背景地圖路線都爲點連線以後構成,只是經過修改線的顏色粗細或者進行貼圖來修改線或者面的樣式,場景中的電梯爲一個顏色爲黃色的簡單六面體,電梯線也爲一條線段而已,因此場景中的模型都是輕量化的建模,使 3d 場景運行渲染的更加流暢,提高用戶體驗。函數
經過上述 智能建築建模 的分析咱們能夠知道線路都是爲點與點之間進行連線而生成,因此當咱們繪製完地圖的路徑以後能夠獲得全部點的信息,假如直線 AB 爲地圖中的某一條線段,那麼咱們能夠知道點 A 以及點 B 的點的座標,以後咱們能夠計算 AB 線段上任意一點 C 的點的座標,而後經過鏈接 A 點與 C 點來造成一條與 AB 線段位置方向相同可是大小比 AB 線段短的線,直到 AC 線段的長度等於 AB 線段長度以後再進行下一條路徑動畫的繪製,如下爲關鍵僞代碼展現:
// currentIndex 爲當前路徑繪製到的點的索引 // points 爲當前路徑全部點的信息 currentPoints 爲繪製過程當中點的信息 // segments 爲當前路徑全部點的鏈接方式信息 currentSegments 爲繪製過程當中點的鏈接方式信息 // 即上述此時 A 點信息 let fromPoint = points[currentIndex]; // 即上述此時 B 點信息 let toPoint = points[currentIndex + 1]; // 經過 AB 兩點信息組成一條 AB 方向的向量 let pointVector = new ht.Math.Vector2(toPoint.x - fromPoint.x, toPoint.y - fromPoint.y); // 記錄該向量的長度,用於判斷 AC 是否大於等於 AB let pointVectorLength = pointVector.length(); let currentPoints = [], currentSegments = []; for(let i = 0; i < currentIndex + 1; i++) { currentPoints.push({ x: points[i].x, y: points[i].y }); currentSegments.push(segments[i]); }
經過上述代碼能夠知道咱們獲取到了 currentPoints 以及 currentSegments 的信息了,以後便要計算在 fromPoint(A點) 與 toPoint(B點) 連線上點的座標,即 C 點,如下爲計算 C 點的關鍵僞代碼:
// addLength 爲每次增長的線段長度值,該程序中使用 500 即每次長度增長 500 let nextVectorLength = currentVectorLength + addLength; let tempPoint; roadData.currentVectorLength = nextVectorLength; // 判斷 AC 線段的長度是否大於 AB if(nextVectorLength > pointVectorLength) { nextVectorLength = pointVectorLength; roadData.currentVectorLength = 0; roadData.currentIndex = currentIndex + 1; } pointVector.setLength(nextVectorLength); // 即爲 C 點座標 tempPoint = {x: pointVector.x + fromPoint.x, y: pointVector.y + fromPoint.y}; // 往 currentPoints 添加 C 點座標 currentPoints.push(tempPoint); // 往 currentSegments 添加 C 點鏈接方式,此程序中都爲直線鏈接,因此值都爲 2 currentSegments.push(2); // roadNode 即爲 ht.Shape 類 從新設置 ht.Shape 類點的信息 roadNode.setPoints(currentPoints); // 從新設置 ht.Shape 類點的鏈接信息 roadNode.setSegments(currentSegments);
如下爲動畫代碼執行流程圖
如下爲繪製一條路線動畫的截圖:
程序中經過向量的計算方式來不斷獲取 C 點的座標,固然也能夠用其它方式來計算 C 點的座標。
水波以及掃描動畫都是經過 HT 提供的修改圖標矩形框信息 api 來進行控制,經過調度的方式不斷修改圖標矩形框大小來產生水波以及掃描的動畫效果,調度的具體用法能夠參考 HT for Web 的[調度手冊],如下爲水波動畫的關鍵僞代碼:
// waterWaveNodes 全部水波節點 let waterWaveTask = { interval: 100, // 指每隔 100 ms 調用 action 函數一次 action: function(data){ // 判斷 waterWaveNodes 是包含 data if(waterWaveNodes.indexOf(data) > -1) { // 獲取此時圖標矩形框信息 circleRect 是個長度爲 4 的數組 分別表示 x, y, width, height let circleRect = data.a('circleRect'); if(circleRect) { // 經過修改高度來變大水波大小 let nextHeight = circleRect[3] + 10; // 高度最大值爲 250 if(nextHeight < 250) { // 對應修改 y 的大小,y 的增長大小爲高度的一半 circleRect[1] = circleRect[1] - 5; circleRect[3] = nextHeight; data.a('circleRect', circleRect); data.a('borderColor', 'rgba(255, 133, 133, ' + (1 - circleRect[3] / 250) + ')'); } else { data.a('circleRect', [-0.5,128,257,0]); data.a('borderColor', 'rgba(255, 133, 133)'); } } else { data.a('circleRect', [-0.5,128,257,0]); } } } }; // 新增該調度任務 dm3d.addScheduleTask(waterWaveTask);
下圖爲水波在 2d 中的截圖:
從程序的截圖中能夠看到在 2d 面板以及 3d 場景中都有數字在動態的變化,這部分主要經過數據綁定動態來修改數值的大小,關於數據綁定能夠參考 HT for Web 的[數據綁定手冊],也是經過調度來不斷修改數值的大小,程序中我封裝了產生隨機數的代碼,用於每次產生隨機數以後綁定到對應的節點上,如下爲修改 2d 面板上數字的變化僞代碼:
// numNode(1-7) 爲 2d 面板中對應數字的節點 // data.a('ht.value', number) 即爲動態修改 attr 上的 ht.value 信息,以後圖紙會自動更新新賦予的數值 // getRandomValue 爲本身封裝的產生隨機數的方法 this.change2dNumTask = { interval: 1000, action: (data) => { if(data === numNode1 || data === numNode2) { data.a('ht.value', util.getRandomValue([500, 999], 5)); } if(data === numNode3 || data === numNode4) { data.s('text', util.getRandomValue([0, 30], 2) + '%'); } if(data === numNode5) { data.a('ht.value', util.getRandomValue([0, 99999], 5, 3)); } if(data === numNode6) { data.a('ht.value', util.getRandomValue([0, 100], 2)); } if(data === numNode7) { data.a('ht.value', util.getRandomValue([0, 100], 2)); } } }; // 新增該調度任務 dm2d.addScheduleTask(this.change2dNumTask);
經過以上代碼能夠知道修改數值是經過修改節點的 attr 以及 style 對象的某個屬性值來動態變化數值,固然在程序中 2d 面板可能還會隱藏,此時該調度任務就不須要執行,能夠調用 removeScheduleTask 方法來移除此調度任務。
在 3d 場景中柱狀體也是一個六面體,只是四周用了漸變的貼圖,以及頂面用了一張純色的貼圖構造出來,每一個六面體都有高度的信息,HT 中經過 node.getTall() 來獲取當前六面體的高度值,根據上一節講的數據綁定,咱們能夠在展現柱狀圖的時候循環獲取全部柱狀體節點的高度值大小假如命名爲 tall,以後經過 node.a('tall', tall) 將該值存儲到當前柱狀圖節點的 attr 對象上面,以後在柱狀體初始化的時候能夠不斷修改高度值來動態改變高度,當高度值大於 node.a('tall') 則說明當前柱狀體初始化的高度已經完成。如下爲相關的僞代碼:
charts.forEach((chart) => { // 將高度存儲到 attr 上 !chart.a('tall') && chart.a('tall', chart.getTall()); // 設置初始高度爲 0 chart.setTall(0); }); this.chartAnimteTask = { interval: 25, action: function(data){ if(charts.indexOf(data) > -1) { if(finishNum !== chartLength) { if(data.getTall() !== data.a('tall')) { // deep 爲每次增長的高度 let nextTall = data.getTall() + deep; // 獲取初始化高度 let tall = data.a('tall'); // 判斷下一個高度是否大於初始化高度 if(nextTall < tall) { data.setTall(nextTall); } else { data.setTall(tall); finishNum++; } } } } } }; // 新增該調度任務 dm3d.addScheduleTask(this.chartAnimteTask);
經過上面代碼能夠知道動畫每一步的程序執行也是經過調度來完成的,與前文幾個動畫的實現方式相似。
3d 場景中視野的推動後退都是經過 HT api 提供的修改 eye 以及 center 的數值方法來實現,經過不斷調用 setEye 以及 setCenter 方法來達到修改視角的目的,eye 類比人眼睛所處的位置,center 類比人眼睛聚焦的位置,如下爲實現鏡頭推動關鍵的僞代碼:
let e = ht.Default.clone(g3d.getEye()), // 獲取當前眼睛的位置 c = ht.Default.clone(g3d.getCenter()); // 獲取當前眼睛聚焦的位置 // eye 爲須要修改的對應 eye 值 // center 爲須要修改的對應 center 值 // 如下爲分別獲取 eye 與 center 在 xyz 三個座標軸之間的差值 let edx = eye[0] - e[0], edz = eye[1] - e[1], edy = eye[2] - e[2], cdx = center[0] - c[0], cdz = center[1] - c[1], cdy = center[2] - c[2]; // 開啓不斷修改 eye 與 center 的動畫 ht.Default.startAnim({ duration: time ? time : 3000, easing: function(t){ return t; }, finishFunc: function() { if(typeof cb === 'function') { cb(); } }, action: function (v) { // v 爲從 0-1 變換的值 g3d.setEye([ e[0] + edx * v, e[1] + edz * v, e[2] + edy * v ]); g3d.setCenter([ c[0] + cdx * v, c[1] + cdz * v, c[2] + cdy * v ]); } });
經過以上代碼能夠知道經過修改 eye 與 center 分別對應的 xyz 軸的值與當前 e 與 c 分別對應的 xyz 軸的值之間的距離來達到視角的變化。
如下爲該代碼的一個應用截圖:
物聯網 經過各類信息傳感設備,實時採集任何須要監控、鏈接、互動的物體或過程等各類須要的信息,與互聯網結合造成的一個巨大網絡。實現了物與物、物與人,全部的物品與網絡的鏈接,方便識別、管理和控制。因此物聯網帶給咱們的 智慧樓宇的可視化監控 須要監控的方面可能還有不少,該系統中針對人員出入,設備信息,管道信息等的監控實現了一個簡單的智慧樓宇監控系統,物聯網也將用戶端延伸和擴展到了任何物品與物品之間,讓咱們更加了解搭建智慧園區,智慧校園等場景監控以後設備可視化,資產可視化帶給咱們的直觀性。場景中的反光與景深等效果都是 HT 核心包提供的效果,全部的模型搭建與動畫也都是經過 HT 核心包提供的 api 進行建模與動畫驅動,因此在網頁中展現會十分流暢,大大提升了用戶的體驗,而且在移動端表現也十分友好。
如下爲移動端的程序運行截圖:
HT 經過在行業上不斷地摸索和技術上的鑽研提高,總結出了許多工業互聯網上各個行業的解決方案,不只能夠在 PC 端展現出可視化監控系統,在移動端一樣能夠輕量型地展現出來。如下是另一個智慧樓宇的可視化監控系統的實現效果:
一樣的,2019 咱們也更新了數百個工業互聯網 2D/3D 可視化案例集,在這裏你能發現許多新奇的實例,也能發掘出不同的工業互聯網:https://mp.weixin.qq.com/s/ZbhB6LO2kBRPrRIfHlKGQA
同時,你也能夠查看更多案例及效果:https://www.hightopo.com/demos/index.html