基於HTML5 WebGL的工業化3D電子圍欄

来源:https://www.cnblogs.com/xhload3d/archive/2019/10/09/11639320.html
-Advertisement-
Play Games

現代工業化的推進在極大加速現代化進程的同時也帶來的相應的安全隱患,在傳統的可視化監控領域,一般都是基於 Web SCADA 的前端技術來實現 2D 可視化監控,本系統採用 Hightopo 的 HT for Web 產品來構造輕量化的 3D 可視化場景,該 3D 場景從正面展示了一個現代化工廠的現實... ...


前言

現代工業化的推進在極大加速現代化進程的同時也帶來的相應的安全隱患,在傳統的可視化監控領域,一般都是基於 Web SCADA 的前端技術來實現 2D 可視化監控,本系統採用 Hightopo 的 HT for Web 產品來構造輕量化的 3D 可視化場景,該 3D 場景從正面展示了一個現代化工廠的現實場景,包括工廠工人的實時位置、電子圍欄的範圍、現場的安全情況等等,幫助我們直觀的瞭解當前工廠人員的安全狀況。

本篇文章通過對工廠可視化場景的搭建和模型的載入,人物實時定位代碼的實現、電子圍欄和軌跡圖的實現進行闡述,幫助我們瞭解如何通過使用HT實現一個簡單的3D電子圍欄可視化。

以下是項目地址:基於HTML5 WebGL的工業化3D電子圍欄軌跡圖

效果預覽

工廠人員實時定位效果及電子圍欄效果

軌跡圖效果圖

軌跡圖

代碼實現

人物模型及場景

項目中使用的人物模型是通過 3dMax 建模生成的,該建模工具可以導出 obj 與 mtl 文件,在 HT 中可以通過解析 obj 與 mtl 文件來生成 3d 場景中的攝像頭模型。

項目中場景通過 HT 的 3d 編輯器進行搭建,場景中的模型有些是通過 HT 建模,有些通過 3dMax 建模,之後導入 HT 中。

繪製電子圍欄

場景中的電子圍欄並不是使用3dMax搭建的模型,HT提供了多種基礎形體類型供用戶建模使用,不同於傳統的3D建模方式,HT的建模核心都是基於API的介面方式, 通過預定義的圖元類型和參數介面,進行設置達到三維模型的構建。根據形狀,我將電子圍欄分成圓柱、長方體和底部為多邊形的棱柱。

以下是我繪製電子圍欄的相關偽代碼:

  1 G.makeShapes = function (data, typeName, color, lastColor, g3dDm) {
  2     //data是包含電子圍欄圖形信息的json對象數組
  3     let shapes = data;
  4     for (let i = 0; i < shapes.length; i++) {
  5         let shape = shapes[i];
  6         let type = Number(shape['type']);
  7         let x = Number(shape['x']);
  8         let y = Number(shape['y']);
  9         let z = Number(shape['z']);
 10         let width = Number(shape['width']);
 11         let height = Number(shape['height']);
 12         let tall = Number(shape['tall']);
 13         let radius = Number(shape['radius']);
 14         let vertexX = shape['vertexX'];
 15         let vertexY = shape['vertexY'];
 16         let nodePoints = [];
 17         let p3 = [];
 18         let s3 = [];
 19         let centerX = 0;
 20         let centerY = 0;
 21         let centerZ = 0;
 22         let node = new ht.Node();
 23         node.setTag(typeName + i);
 24         switch (type) {
 25             //第一種形狀:圓柱
 26             case 1:
 27                 p3 = [-x, tall / 2, -y];
 28                 s3 = [radius, tall, radius];
 29                 //定義電子圍欄樣式
 30                 node.s({
 31                     "shape3d": "cylinder",
 32                     "shape3d.color": color,
 33                     "shape3d.transparent": true,
 34                     "shape3d.reverse.color": color,
 35                     "shape3d.top.color": color,
 36                     "shape3d.top.visible": false,
 37                     "shape3d.bottom.color": color,
 38                     "shape3d.from.color": color,
 39                     "shape3d.to.color": color
 40                 });
 41                 node.p3(p3);    //設置三維坐標
 42                 node.s3(s3);    //設置形狀信息
 43                 break;
 44             //第二種形狀:長方體
 45             case 2:
 46                 centerX = x - width / 2;
 47                 centerY = y - height / 2;
 48                 centerZ = z + tall / 2;
 49                 p3 = [-Number(centerX) - width, Number(centerZ), -Number(centerY) - height];
 50                 s3 = [width, tall, height];
 51                 node.s({
 52                     "all.color": color,
 53                     "all.reverse.color": color,
 54                     "top.visible": false,
 55                     "all.transparent": true
 56                 });
 57                 node.p3(p3);
 58                 node.s3(s3);
 59                 break;
 60             //第三種形狀:底部為不規則形狀的等高體
 61             case 3:
 62                 let segments = [];
 63                 for (let i = 0; i < vertexX.length; i++) {
 64                     let x = -vertexX[i];
 65                     let y = -vertexY[i];
 66                     let newPoint = { x: x, y: y };
 67                     nodePoints.push(newPoint);
 68                     //1: moveTo,占用1個點信息,代表一個新路徑的起點
 69                     if (i === 0) {
 70                         segments.push(1);
 71                     }
 72                     else {
 73                         //2: lineTo,占用1個點信息,代表從上次最後點連接到該點
 74                         segments.push(2);
 75                         if (i === vertexX.length - 1) {
 76                             //5: closePath,不占用點信息,代表本次路徑繪製結束,並閉合到路徑的起始點
 77                             segments.push(5);
 78                         }
 79                     }
 80                 }
 81                 node = new ht.Shape();
 82                 node.setTag(typeName + i);
 83                 node.s({
 84                     'shape.background': lastColor,
 85                     'shape.border.width': 10,
 86                     'shape.border.color': lastColor,
 87                     'all.color': lastColor,
 88                     "all.transparent": true,
 89                     'all.opacity': 0.3,
 90                 });
 91                 p3 = [nodePoints[0]['x'], tall / 2, nodePoints[0]['y']];
 92                 node.p3(p3);
 93                 node.setTall(tall);
 94                 node.setThickness(5);
 95                 node.setPoints(nodePoints); //node設置點集位置信息
 96                 node.setSegments(segments); //node設置點集連接規則
 97                 break;
 98         }
 99         g3dDm.add(node);
100     }
101 }

 

 

考慮到電子圍欄在某些情況下可能會影響到對人物位置的觀察,設置了隱藏電子圍欄的功能。在HT中用戶可以自定義設置標簽Tag作為模型唯一的標識,我將所有的電子圍欄模型的標簽首碼都統一併且保存在fenceName中,需要隱藏的時候則遍歷所有標簽名稱首碼為fenceName的模型,並且根據模型種類的不同設置不同的隱藏方式。

以下是相關偽代碼:

 1 g3dDm.each((data) => {
 2     if (data.getTag() && data.getTag().substring(0, 4) === fenceName) {
 3         if (data.s('all.opacity') === '0') {
 4             data.s('all.opacity', '0.3');
 5         }
 6         else {
 7             data.s('shape3d.visible', true);
 8             data.s('all.visible', true);
 9             data.s("2d.visible", true);
10             data.s("3d.visible", true);
11         }
12     }
13 });

人物模型實時定位

因為項目使用的是http協議獲取數據,因此使用定時器定時刷新人物數據信息,HT有設置節點位置的setPosition3d方法,因此不做過多介紹,但是人物節點的位置的刷新還包括人物的朝向,因此每次人物移動都需要和上次位置進行比對,計算出偏移的角度。

相關偽代碼如下:

 1 // 刷新數據的人物結點與原來的人物節點標簽相同,則存在做位置更新
 2 if (realInfoData.tagId === tag.getTag()) {
 3     //計算位置朝向偏移參數
 4     let angleNumber = Math.atan2(((-p3[2]) - (-tag.p3()[2])), ((-p3[0]) - (-tag.p3()[0])));
 5     //如果在原地就不轉向,判斷人物在平面位置是否發生變化
 6     if (p3[0] !== tag.p3()[0] || p3[2] !== tag.p3()[2]) {
 7         if (angleNumber > 0) {
 8             angleNumber = Math.PI - angleNumber;
 9         } else {
10             angleNumber = -Math.PI - angleNumber;
11         }
12         //設置人物朝向
13         tag.setRotation3d(0, angleNumber + Math.PI / 2, 0);
14     }
15     //設置人物位置
16     tag.p3(p3);
17 }

人物觸發警報

當人物觸發警報時,有2種方式同時提醒系統使用者。一是人物頭上的面板顏色發生改變,並且顯示報警信息。

相關代碼如下:

 1 switch(obj.alarmType){
 2     case null:
 3         if(panel){//無警報
 4             panel.a('alarmContent','');
 5             panel.a('bg','rgba(6,13,36,0.80)');
 6         }
 7         break;
 8     case '0':
 9         panel.a('alarmContent','進入圍欄');
10         panel.a('bg','rgb(212,0,0)');
11         break;
12     case '1':
13         panel.a('alarmContent','SOS');
14         panel.a('bg','rgb(212,0,0)');
15         break;
16     case '2':
17         panel.a('alarmContent',''); //離開圍欄
18         panel.a('bg','rgba(6,13,36,0.80)');   
19         break;
20     case '3':
21         panel.a('alarmContent','長時間未動');
22         panel.a('bg','rgb(212,0,0)');
23         break;
24 }

 

二是頁面的右側面板會增加警報信息。

相關代碼如下:

1 data.a('text', info);
2 list.dm().add(data);

軌跡圖軌跡實現原理

在發生警報後,需要根據人物的軌跡圖回溯發生警報的來龍去脈。如果使用根據點集每走一步就繪製一個canvas腳步節點的方式去重現軌跡,很容易造成節點繪製過多,頁面卡頓的情況,因此我使用一整條管道的方式代替一個人物的所有腳步節點,使用管道的好處是,每個人物的軌跡圖從開始到結束只有一個管道的圖元信息,因此對頁面的渲染更加友好和流暢。

生成管道軌跡的代碼如下:

 1 //生成軌跡
 2 this.ployLines[i] = new ht.Polyline();
 3 this.ployLines[i].setParent(node);
 4 this.points[i] = [];
 5 this.points[i].push({ x: p3[0], y: p3[2], e: p3[1] -50 });
 6 this.ployLines[i].setPoints(this.points[i]);
 7 this.ployLines[i].s({
 8     'shape.border.color': 'red'
 9 });
10 g3dDm.add(this.ployLines[i]);

 

人物前進一步,則往管道的點集中推進一個點的坐標,同時繪製新的管道部分。同理,人物後退一步,則管道的點集中推出當前最後一個點的坐標,同時管道失去最後兩點連接的部分。另外我通過使用定時器,對軌跡圖的前進和後退分別做了快進和快退的處理。以下為軌跡圖的運行效果:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 關於CSS的書寫規範和順序,是大部分前端er都必須要攻剋的一門關卡,如果沒有按照良好的CSS書寫規範來寫CSS代碼,會影響代碼的閱讀體驗。這裡總結了一個CSS書寫規範、CSS書寫順序供大家參考,這些是參考了國外一些文章以及我的個人經驗總結出來,我想對寫CSS的前端用戶來說是值得學習的。 CSS書寫順 ...
  • vue對比jquery vue:mvvm 數據驅動影響視圖 適用於複雜數據jquery:mvc 視圖塞入數據 適用於複雜視圖動效 (其實都是js 的封裝,以及對html 的擴展) 相關指令 v-text 等同大鬍子效果 但是會轉換為字元串 v-html 綁定html屬性 v-if三兄弟 只會渲染判斷 ...
  • 1. Promise 的含義 Promise 是非同步編程的一種解決方案,比傳統的解決方案 回調函數和事件更合理、更強大。 1.1 什麼是Promise 簡單來說就是一個容器,裡面保存著某個未來才會結束的事件(也就是非同步操作)的結果。從語法上來講,Promise是一個對象,從它可以獲取非同步操作的消息, ...
  • //js layui.use(['laydate', 'layer', 'element', 'form','laypage'], function() { form = layui.form, form.on('switch(used)', function(data){ var s... ...
  • 一.安裝依賴 ​ or` 二.使用 三.官方文檔 "點我官方文檔" "點我中文官方文檔" ...
  • <script type="text/javascript"> String.prototype.reverse = function(){ this.split("").reverse().join("") } //在二進位中迴文數最低位會是1 那麼代表這個數會是奇數 var num = 11 w... ...
  • 4、數字 4.1 不同進位表示法 ES6中新增了不同進位的書寫格式,在後臺傳參的時候要註意這一點。 4.2 精確到指定位數的小數 將數字四捨五入到指定的小數位數。使用 Math.round() 和模板字面量將數字四捨五入為指定的小數位數。 省略第二個參數 decimals ,數字將被四捨五入到一個整 ...
  • 真實生活中的對象、屬性和方法 在真實生活中,汽車是一個對象。 汽車有諸如車重和顏色等屬性,也有諸如啟動和停止的方法: car.name = porsche car.model = 911 car.length = 4499mm car.color = white car.start() car.dr ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...