工業企業中生產線處於高速運轉,由工業設備所產生、採集和處理的數據量遠大於企業中計算機和人工產生的數據,生產線的高速運轉則對數據的實時性要求也更高。破解這些大數據就是企業在新一輪製造革命中贏得競爭力的鑰匙。所以,工業生產可視化系統是工業製造業的最佳選擇。html
工業生產可視化是將虛擬現實技術有機融入了工業監控系統,系統展示界面以生產廠房的仿真場景爲基礎,對各個工段、重要設備的形態都進行復原,做業流轉狀態能夠在廠房視圖當中直接顯示。在單體設備視圖中,機械設備的運行模式直接以仿真動畫的形式展示,經過圖像、三維動畫以及計算機程控技術與實體模型相融合,實現對設備的可視化表達,使管理者對其所管理的設備有形象具體的概念。同時,對設備運行中產生的全部參數一目瞭然,從而大大減小管理者的勞動強度,提升管理效率和管理水平。node
如下是基於 HT for Web(http://www.hightopo.com/)的裙房監控系統的具體解決方案動圖:json
http://www.hightopo.com/demo/...
基於 HT for Web(http://www.hightopo.com/)的 HTML5 技術除了應用在工業行業外,如今愈來愈多用戶實用 HT 在城市服務、農業、樓宇、管廊、安防、BIM、隧道等等傳統的領域進行實時聯網監控,經過數字孿生雙胞胎的方式將實體設備與具體的數據傳輸過去,方便管理員進行管理,也爲監管省去了很大一筆人力開銷。
最初客戶給出的需求是實現動畫以及開關動畫的功能,控制動畫和燈光的開關佔據屏幕的比例不須要太大,按照人類習慣的操做方式來講,放在右上角是最合適的,剩下的整屏就由 3D 場景來填充,主次分明。數組
要將工業生產可視化,3D 的展示是必不可少,HT 須要建立一個 3D 組件,搭建靠 2 行代碼來實現:app
var g3d = new ht.graph3d.Graph3dView();// Hightopo 的 3D 組件(三維場景地基) g3d.addToDOM();// 將 3D 組將添加到 body 體中
HT 的組件通常都會嵌入 BorderPane(https://hightopo.com/guide/gu...)、SplitView(https://hightopo.com/guide/gu...)和 TabView (https://hightopo.com/guide/gu...)等容器中使用,而最外層的 HT 組件則須要用戶手工將 getView() 返回的底層 div 元素添加到頁面的 DOM 元素中,這裏須要注意的是,當父容器大小變化時,若是父容器是 BorderPane 和 SplitView 等這些HT預約義的容器組件,則 HT 的容器會自動遞歸調用孩子組件 invalidate 函數通知更新。但若是父容器是原生的 html 元素, 則 HT 組件沒法獲知須要更新,所以最外層的 HT 組件通常須要監聽 window 的窗口大小變化事件,調用最外層組件 invalidate 函數進行更新。
爲了最外層組件加載填充滿窗口的方便性,HT 的全部組件都有 addToDOM 函數,其實現邏輯以下,其中 iv 是 invalidate 的簡寫:dom
addToDOM = function(){ var self = this, view = self.getView(),//獲取組件的底層 div style = view.style; document.body.appendChild(view);//將組件底層div添加進body中 style.left = '0';//ht 默認將全部的組件的position都設置爲absolute絕對定位 style.right = '0'; style.top = '0'; style.bottom = '0'; window.addEventListener('resize', function () { self.iv(); }, false);//窗口大小改變事件,調用刷新函數 }
接下來咱們要向場景中添加各類模型,用代碼生成模型是很是痛苦的,咱們將整個場景的模型都放到一個 JSON 文件中,並經過 ht.Default.xhrLoad 方法將這個 JSON 轉換爲 3D 場景顯示在界面上:異步
var dm = g3d.dm();// 獲取 HT 3D 組件的數據容器 ht.Default.xhrLoad('scenes/system.json', function(text) { dm.deserialize(text);// 將函數的 text(json)參數傳給 deserialize 反序列化方法,可將 json 內容中的元素添加到 dataModel 數據容器中進行顯示 }
ht.Default.xhrLoad 方法是一個異步加載 json 文件的方法,第一個參數爲傳入的 json 文件,路徑是相對於 html 文件的,第二個參數是回調函數,在傳入的 json 文件解析完畢以後作的操做。此方法爲異步加載,所以須要對 dm 數據容器中的數據進行獲取或操做的話,須要將獲取/操做的代碼寫在 dm.deserialize(text) 方法以後,由於此時 dm 數據容器中才有節點。
上面將 JSON 文件發序列化到 dm 數據容器中後界面顯示以下:ide
上圖中整個場景的背景是我後期用代碼添加的,經過前面的 addToDOM 函數能夠知道咱們能夠經過 getView 方法獲取 HT 3D 組件的底層 div,所以要在此 div 上添加一張背景圖也就不難了。剩下的 3D 模型部分都是由 JSON 反序列化出來的。函數
工業葉輪的轉動不多是整個模型在轉動,而是中間的「滾輪」在轉動,這要求設計師在建立模型的時候就將這個部分分離出來,而後我給此部分設置 tag 惟一標識爲「yelun」,經過 dm.getDataByTag('yelun') 便可獲取到這個節點,而後給這個節點設置旋轉動畫。
HT 中調度進行的流程是,先經過 DataModel (https://hightopo.com/guide/gu...)添加調度任務,DataModel 會在調度任務指定的時間間隔到達時, 遍歷 DataModel 全部圖元回調調度任務的 action 函數,可在該函數中對傳入的 Data 圖元作相應的屬性修改以達到動畫效果。
根據上面對調度任務的說明,咱們瞭解到向 dm 數據容器中添加調度任務會遍歷整個數據容器,數據容器中內容很少的時候可能感受不到,但當數據容器中內容多且模型重的狀況下,對 dm 數據容器進行過濾就很是有必要了,並且若是添加多個調度任務都遍歷了整個數據容器,那麼對電腦的性能要求可想而知。我一開始使用的時候就是遺漏了對 dm 數據容器的過濾,由於場景不大,因此一開始沒有感受,後來加了燈光後很重,就立馬出現問題了,才發現遺漏了對 data 的過濾判斷。
所以,調度任務傳入的參數對象中 action 方法傳入了一個 data 值,用於設置當前動畫的對象,不是此對象的直接能夠 return 掉,不作任何操做:性能
var task = []; var yelun = dm.getDataByTag('yelun');// 獲取 tag 爲 yelun 的節點 // 建立一個動畫調度任務 task.yelunTask = { interval: 100,// 動畫持續時間 action: function(data) {// 動畫內容 if (data !== yelun) return; // 設置 yelun 節點的 x 軸旋轉爲當前 x 軸旋轉值再加上 Math.PI/12 yelun.setRotationX(yelun.getRotationX() + Math.PI/12); } } dm.addScheduleTask(task.yelunTask);// 將調度任務添加到數據容器中
容器中水位的上升降低也是數字孿生(雙胞胎)的體現,數據同步進行展示給監控人員,監控人員不須要進行數據採集系統也能直接獲取當前數據。
這裏將容器水位的上升降低放到一個動畫調度任務裏了,也就是說經過 dm 數據容器操做這個調度任務就可以同時操做這兩個部分的動畫,將上一小節中的 yelunTask 調度任務的 action 更改一下,由於上面的代碼只對 yelun 節點進行了操做,咱們須要對裝水的容器也進行操做。首先獲取裝水的容器,這裏將這個節點的惟一標識 tag 設置爲「cylinder」:
var cylinder = dm.getDataByTag('cylinder'); 而後更改調度中的 action 部分代碼: action: function(data) { if (!(data === yelun || data === cylinder)) return; // 葉輪轉動 yelun.setRotationX(yelun.getRotationX() + Math.PI/12); // 容器水位變化 if (cylinder.getTall() === 100) cylinder.setTall(0);// 容器水位高度到達 100 的值時,重置爲 0else cylinder.setTall(cylinder.getTall() + 1); }
由於沒有數據的傳輸,因此這邊故障信息我只能本身造假數據了,我建立了一個 10 之內的整數隨機數,判斷這個值是否爲 1,若是爲 1 就將運做正常的圖標變換成告警圖標,同時我還經過這個值來設置 dm 數據容器添加/移除調度任務來控制當前葉輪轉動/中止、容器水位變化與否:
var alarm = dm.getDataByTag('alarm');// 獲取告警圖標節點 setInterval(function() { var random = Math.floor(Math.random()*5); if (random === 1) { alarm.s('shape3d.image', 'symbols/電信/故障 2.json');// 設置告警圖標節點爲「故障」圖標 dm.removeScheduleTask(task.yelunTask);// 將葉輪的動畫加上 } else { alarm.s('shape3d.image', 'symbols/電信/正常 2.json');// 設置告警圖標節點爲「正常」圖標 dm.addScheduleTask(task.yelunTask);// 移除葉輪的動畫 } }, 1000);
上一小節咱們已經提到了開啓/關閉動畫的方式,這邊咱們運用 form 表單,手動操做動畫的開啓和關閉(注:這裏只說明第一行的「水流開關」)。
工業互聯網還有一個好處,就是可以遠程來控制現場的開關,同時也能快速監測到設備是否故障,可以及時反饋給維修人員,減小了時間成本,以及下降了生產停滯的風險。
首先,咱們須要建立一個 formPane (https://hightopo.com/guide/gu...)表單組件,在這個表單組件中添加行數據,這邊操做動畫的開啓和關閉我是用的 checkbox,值變化只有 true 和 false,這個狀況用這個是比較優的選擇。而後經過監聽這個 checkbox 的值的變化事件,設置動畫的開啓(添加)或者關閉(移除)。
function createForm(task) { var form = new ht.widget.FormPane();// 建立 form 表單組件對象 form.setWidth(160);// 設置表單組件的寬度 form.setHeight(90);// 設置表單組件的高度 // 設置表單組件底層 div 的樣式屬性 form.getView().style.right = '10px'; form.getView().style.top = '10px'; form.getView().style.background = 'rgba(255, 255, 255, 0.2)'; form.getView().style.borderRadius = '5px'; document.body.appendChild(form.getView());// 將 form 表單底層 div 添加到 body 體中 // 水閥開啓和關閉 form.addRow([// 給 form 表單添加一行數據 { checkBox: {// 複選框類,HT 將此封裝到 form 中 實際上建立了一個 ht.widget.CheckBox 組件 label: '水流開關',// 設置 checkbox 的文本內容 labelColor: '#fff',// 設置 checkbox 文本顏色 selected: true,// 設置此 checkbox 是否選中 onValueChanged: function() {// 監聽值變化事件 if (this.isSelected()) dm.addScheduleTask(task.arrowTask);// 若是這個 checkBox 選中,則添加動畫(開啓水閥) else dm.removeScheduleTask(task.arrowTask);// 若是這個 checkBox 未被選中,則移除動畫(關閉水閥) } } } ], [0.1]);// 設置這個行數據中列的寬度 return form; }
addRow 方法上面代碼中一言兩語解釋不清楚,參考以下說明:
addRow(items, widths, height, params) 添加一行組件
items爲元素數組,元素可爲字符串、json 格式描述的組件參數信息、html 元素或者爲 null 的空
上面代碼中提到的 arrowTask 是對場景中的「箭頭」流動添加的動畫調度任務,經過控制 form 表單中 checkbox 複選框是否選中可直接操做 dm 是否添加/移除動畫調度任務。
控制燈光的開啓和關閉,這裏也是經過 form 表單上的 checkbox 複選框來進行操做的。通常建議不要使用燈光,渲染太燒性能了,這裏只是爲了效果而添加作一個說明。
首先咱們須要建立一個「燈」節點,而後經過設置樣式屬性 setStyle 來設置燈的類型、顏色、燈照範圍等等屬性:
// 添加燈光 var light = new ht.Light();// 建立一個燈節點(繼承於 ht.Node) (https://hightopo.com/guide/guide/core/lighting/ht-lighting-guide.html) light.p3([15, 120, 50]);// 設置此節點的位置 light.setTag('light');// 設置此節點的惟一標識 dm.add(light);// 將此節點添加到 dm 數據容器中進行顯示 light.s({// 設置此節點的樣式屬性 setStyle 簡寫爲 s 'light.type': 'point',// 設置燈類型 'light.color': 'rgb(252,252,149)',// 設置燈顏色 'light.range': 1400,// 設置燈照範圍 '3d.visible': false// 設置此節點在 3d 上不可見 });
而後在 form 表單上添加一行用來控制燈的開關、燈的顏色燈功能:
// 九、燈光開啓和關閉 以及顏色切換 form.addRow([// form 中添加一行 { id: 'lightDisabled',// 設置此項的 id 值,可經過 form.getItemById 獲取此項 checkBox: {// 複選框組件 label: '開關燈',// 設置複選框文本內容 labelColor: '#fff',// 設置複選框文本顏色 selected: true,// 設置複選框是否選中 onValueChanged: function() {// 監聽值變化事件 dm.getDataByTag('light').s('light.disabled', !this.getValue());// 獲取燈節點並設置是否關閉燈光效果,light.disabled 屬性默認爲false,可設置爲true關閉燈效果 } } }, { colorPicker: {// 顏色選擇器組件 value: 'rgb(252,252,149)',// 設置當前值 instant: true,// 設置是否處於即時狀態,將會實時改變模型值 onValueChanged: function() {// 監聽值變化事件 dm.getDataByTag('light').s('light.color', this.getValue())// 設置燈的顏色爲當前選中的顏色 } } } ], [0.1, 0.1]);
HT 將事件監聽封裝到 mi 事件(https://hightopo.com/guide/gu...)中,mi 方法中有多種事件,這裏咱們須要的是單擊節點的事件監聽 clickData 事件,經過判斷事件類型 e.kind 是否爲 clickData,以後對節點的設置模型便可:
var waterPump6 = dm.getDataByTag('水泵06');// 獲取 tag 爲「水泵06」的節點 waterPump6.s({// 設置該節點的樣式屬性 'note': '點我切換模型',// 設置標註文字內容 'note.transparent': true,// 設置標註在 3D 下是否透明 'note.t3': [0, 0, -50],// 設置標註在 3D 下的偏移 'note.reverse.flip': true//設置標註背面是否顯示正面的內容 }); g3d.mi(function(e) {// 監聽 3D 組件上的事件 if(e.kind === 'clickData') {// 點擊節點事件 // 模型點擊切換 if (e.data === waterPump6 && e.data.s('shape3d') === 'models/裙房系統/水泵.json') e.data.s('shape3d', 'models/fengji.json');// 設置點擊節點的 shape3d 樣式屬性 else if (e.data === waterPump6 && e.data.s('shape3d') === 'models/fengji.json') e.data.s('shape3d', 'models/裙房系統/水泵.json');// 設置點擊節點的 shape3d 樣式屬性 } });
HT 設置模型是經過設置節點的樣式屬性 node.setStyle(簡寫爲 node.s)爲 shape3d 來實現的。
上面說到了事件的監聽,既然同爲點擊事件,咱們就在一個監聽事件裏面進行具體的操做便可,在上面的 if (e.kind === 'clickData') 判斷中添加顯示/隱藏屬性窗口的邏輯:
var waterPump5 = dm.getDataByTag('水泵05'); waterPump6.s({ 'note': '點我切換模型', 'note.transparent': true, 'note.t3': [0, 0, -50], 'note.reverse.flip': true }); g3d.mi(function(e) { if(e.kind === 'clickData') { // 模型點擊切換 if (e.data === waterPump6 && e.data.s('shape3d') === 'models/裙房系統/水泵.json') e.data.s('shape3d', 'models/fengji.json'); else if (e.data === waterPump6 && e.data.s('shape3d') === 'models/fengji.json') e.data.s('shape3d', 'models/裙房系統/水泵.json'); // 模型點擊 隱藏/顯示屬性窗口 if (e.data === waterPump5) {// 判斷點擊的圖元是否爲 waterPump5 if(giveWater.s('3d.visible')) {// 判斷當前屬性窗口是否爲顯示狀態 giveWater.s('3d.visible', false);// 設置屬性窗口不可見 e.data.s('note', '點我顯示屬性窗口');// 更改標註中的顯示內容 } else { giveWater.s('3d.visible', true);// 設置屬性窗口可見 e.data.s('note', '點我隱藏屬性窗口')// 更改標註中的顯示內容 } } } });
工業生產現場數據確定是不斷地變化,數字孿生的特性也在這裏充分地展現出來,根據設備返回的數據不斷地更新顯示數據,清晰地展現了當前設備的動態。
經過 tag 獲取場景中對應的屬性窗口的節點,此節點爲一個面板,至關於六面體有六面,這個節點類型就只有一面,並經過設置屬性 shape3d.image 設置此節點上的圖片爲 tooltips.json 矢量圖標(https://hightopo.com/guide/gu...)。矢量在 Hightopo(HT)中是矢量圖形的簡稱,常見的 png 和 jpg 這類的柵格位圖, 經過存儲每一個像素的顏色信息來描述圖形,這種方式的圖片在拉伸放大或縮小時會出現圖形模糊,線條變粗出現鋸齒等問題。 而矢量圖片經過點、線和多邊形來描述圖形,所以在無限放大和縮小圖片的狀況下依然能保持一致的精確度。並且 HT 的矢量圖形還有一個很是重要的特色,就是可以對矢量圖形上的任何一個部分都進行數據綁定,也就是說上圖中的五張圖,咱們能夠只繪製一張圖,經過數據綁定來改變這張圖上的文本以及數值內容。
矢量圖標中的數據綁定能夠用在工業中的生產看板、大屏中的數據顯示等等,都可以以一種高效的方式進行產品的整合。
矢量圖形的數據綁定可以再寫一篇文章進行闡述了,這裏就很少提,你們自行去官網上查看「矢量手冊」以及「數據綁定手冊」,說明的比較詳細。
獲取到對應的節點以後,經過 node.a 方法能夠獲取和設置數據綁定(https://hightopo.com/guide/gu...)的屬性,這裏咱們綁定的是文本內容「label」和數值「value」以及數值顏色「valueColor」:
var billboardArray = []; // 經過 tag 獲取節點 var temperature1 = dm.getDataByTag('回水溫度1');// 獲取 tag 爲"回水溫度1"的節點 billboardArray.push(temperature1); var temperature2 = dm.getDataByTag('回水溫度2'); billboardArray.push(temperature2); var returnPress = dm.getDataByTag('回水壓力'); billboardArray.push(returnPress); var givePress = dm.getDataByTag('供水壓力'); billboardArray.push(givePress); var giveTemp = dm.getDataByTag('供水溫度'); billboardArray.push(giveTemp); var giveWater = dm.getDataByTag('供水流量'); billboardArray.push(giveWater); // 文字標籤內容變換 billboardArray.forEach(function(billboard) { billboard.a('label', billboard.getTag());// 設置數據綁定屬性爲 label 的屬性值爲當前節點的 tag 內容 }); // 文字標籤數字變換+顏色變換 更改圖標中綁定的 value 屬性值 setInterval(function() { billboardArray.forEach(function(billboard) { var random = Math.random()*100; billboard.a('value', random.toFixed(2)); // 設置圖標中「數值內容顏色」 if (random > 70 && random <= 80) billboard.a('valueColor', '#00FFFF'); else if (random > 80 && random <= 90) billboard.a('valueColor', '#FFA000'); else if (random > 90) billboard.a('valueColor', '#FF0000'); else billboard.a('valueColor', ''); }); }, 1000);
工業互聯網 3D 的可視化應用很是普遍,除了裙房監控系統,工業設備好比變壓器的數據監控以及智能樓宇外還有不少不少,甚至能夠運用到農業以及城市規劃上......最後,有興趣的朋友能夠私信或留言交流一下技術或者交個朋友。