電子圍欄視覺化,提高安全運維效率

現代工業化的推進在極大加速現代化程序的同時也帶來的相應的安全隱患,在傳統的監控領域,一般都是基於Web前端技術來實現 2D 視覺化監控,本文采用ThingJS來構造輕量化的 3D 視覺化場景,該3D場景展示了一個現代化商場的數字孿生視覺化場景,包括人員的實時位置、電子圍欄的範圍、現場的安全情況等等,幫助直觀的瞭解當前人員的安全狀況。

電子圍欄

又稱周界防盜報警系統,監控防區工作狀態,實景中的電子圍欄系統用於農業、畜牧業,以及監獄、軍事設施等安全敏感地區。ThingJS平臺上,電子圍欄指的是一個區域,使用PolygonRegion屬性。建立物體物件或模型並開啟移動功能,即可開始檢測目標點是否進入電子圍欄區域,判斷true或false顯示告警反應。

電子圍欄視覺化,提高安全運維效率

本篇文章透過對數字孿生視覺化場景的搭建和模型的載入,人物實時定位程式碼的實現、電子圍欄和軌跡圖的實現進行闡述,瞭解如何透過使用ThingJS實現一個簡單的3D電子圍欄視覺化。

// 新增電子圍欄 new THING。widget。Button(‘新增電子圍欄’, function() { // 構成多邊形的點(取世界座標系下的座標) points = [ [81, 0。5, 63], [81, 0。5, 52], [72, 0。5, 52], [72, 0。5, 63] ]; if (polygonMarker) { return; } // 建立電子圍欄(區域) polygonMarker = app。create({ type: ‘PolygonRegion’, points: points, // 傳入世界座標系下點座標 style: { regionOpacity: 。6, regionColor: ‘#3CF9DF’, // 區域顏色 lineColor: ‘#3CF9DF’ // 線框顏色 } }); // 設定永遠在最上層顯示 polygonMarker。style。alwaysOnTop = false; })

電子圍欄視覺化,提高安全運維效率

當人物或物體物件出發警報時,有2種方式提醒注意,一是踏足的禁區圍欄顏色發生改變;二是展示面板顯示報警資訊,視覺化監控目標點的移動範圍。

完整程式碼如下:

// 新增圖片標註 new THING。widget。Button(‘新增圖片標註’, function() { var coord = [83, 0。5, 61]; if (marker1) { return; } // 建立目標點(marker) marker1 = app。create({ type: “Marker”, id: “marker1”, url: “/guide/examples/images/navigation/user。png”, position: coord, size: 1 }) }) var point = [ [81, 63], [81, 52], [72, 52], [72, 63] ]; // 移動圖片標註 new THING。widget。Button(‘移動圖片標註’, function() { var markerEndPoint = [68, 0。5, 55]; if (marker1 != null) { var moveState = marker1。getAttribute(‘moveState’); if (moveState == ‘complete’) { marker1。off(‘update’, null, ‘監控圖片標註’); return; } // 目標點移動 marker1。moveTo({ position: markerEndPoint, // 移動到終點位置 time: 2 * 1000, orientToPath: true, // 沿路徑方向 complete: function(ev) { marker1。off(‘update’, null, ‘監控圖片標註’); $(‘。warninfo1’)。css(‘display’, ‘none’); $(‘。warninfo2’)。css(‘display’, ‘block’); $(‘。warninfo3’)。css(‘display’, ‘none’); marker1。setAttribute(‘moveState’, ‘complete’); } }) } if (points != null) { // 監控圖片標註是否進入電子圍欄區域 if (marker1 != null) { marker1。on(‘update’, function() { if (polygonMarker != null) { var intoPolygonMarker = isInPolygon([marker1。position[0], marker1。position[2]], point); if (intoPolygonMarker) { polygonMarker。regionColor = ‘#a94442’; polygonMarker。lineColor = ‘#a94442’ $(‘。warninfo1’)。css(‘display’, ‘block’); $(‘。warninfo2’)。css(‘display’, ‘none’); $(‘。warninfo3’)。css(‘display’, ‘none’); } else { polygonMarker。regionColor = ‘#3CF9DF’; polygonMarker。lineColor = ‘#3CF9DF’ $(‘。warninfo1’)。css(‘display’, ‘none’); $(‘。warninfo2’)。css(‘display’, ‘none’); $(‘。warninfo3’)。css(‘display’, ‘block’); } } }, ‘監控圖片標註’) } } }) // 新增模型標註 new THING。widget。Button(‘新增模型標註’, function() { //建立目標點(Obj) people = app。query(‘#worker’)[0]; people。position = [83, 0。1, 56]; people。visible = true; people。scale = [1。5, 1。5, 1。5]; }) // 移動模型標註 new THING。widget。Button(‘移動模型標註’, function() { var objEndPoint = [70, 0。1, 60]; if (people != null) { var moveState = people。getAttribute(‘moveState’); if (moveState == ‘complete’) { people。off(‘update’, null, ‘監控圖片標註’); return; } // 播放模型動畫 people。playAnimation({ name: ‘走’, speed: 1, loopType: THING。LoopType。Repeat, }); // 模型移動 people。moveTo({ position: objEndPoint, // 移動到終點位置 orientToPath: true, // 沿路徑方向 time: 8 * 1000, complete: function(ev) { people。stopAnimation(‘走’); people。off(‘update’, null, ‘監控模型標註’); $(‘。warninfo1’)。css(‘display’, ‘none’); $(‘。warninfo2’)。css(‘display’, ‘block’); $(‘。warninfo3’)。css(‘display’, ‘none’); people。setAttribute(‘moveState’, ‘complete’); } }) } if (points != null) { // 監控模型標註是否進入電子圍欄區域 if (people != null) { people。on(‘update’, function() { if (polygonMarker != null) { var intoPolygonMarker = isInPolygon([people。position[0], people。position[2]], point); if (intoPolygonMarker) { polygonMarker。regionColor = ‘#a94442’; polygonMarker。lineColor = ‘#a94442’ $(‘。warninfo1’)。css(‘display’, ‘block’); $(‘。warninfo2’)。css(‘display’, ‘none’); $(‘。warninfo3’)。css(‘display’, ‘none’); } else { polygonMarker。regionColor = ‘#3CF9DF’; polygonMarker。lineColor = ‘#3CF9DF’ $(‘。warninfo1’)。css(‘display’, ‘none’); $(‘。warninfo2’)。css(‘display’, ‘none’); $(‘。warninfo3’)。css(‘display’, ‘block’); } } }, ‘監控模型標註’) } } }) // 重置 new THING。widget。Button(‘重置’, function() { if (polygonMarker) { polygonMarker。destroy(); polygonMarker = null; } if (marker1) { marker1。destroy(); marker1 = null; } if (people) { people。visible = false; people。setAttribute(‘moveState’, null); } $(‘。warninfo1’)。css(‘display’, ‘none’); $(‘。warninfo1’)。css(‘display’, ‘none’); $(‘。warninfo1’)。css(‘display’, ‘block’); }) createTip(); // 建立提示面板}); /** * 建立提示面板 */ function createTip() { var html = `

目標已進入圍欄
到達目的地
目標未進入圍欄
`; $(‘#div2d’)。append($(html));} /** * 關閉提示面板 */function fenClose() { $(“。fencing”)。hide();}/** * 檢測目標點是否進入電子圍欄區域 * @param {Array} checkPoint - 校驗座標 * @param {Array} polygonPoints - 形成電子圍欄的座標 * @returns {Boolean} true 或 false * @description 此方法僅判斷處於同一個平面的目標點是否在區域內(只判斷座標x和z值), * 不考慮兩者當前離地高度(座標的y值) */function isInPolygon(checkPoint, polygonPoints) { var counter = 0; var i; var xinters; var p1, p2; var pointCount = polygonPoints。length; p1 = polygonPoints[0]; for (i = 1; i <= pointCount; i++) { p2 = polygonPoints[i % pointCount]; if (checkPoint[0] > Math。min(p1[0], p2[0]) && checkPoint[0] <= Math。max(p1[0], p2[0])) { if (checkPoint[1] <= Math。max(p1[1], p2[1])) { if (p1[0] != p2[0]) { xinters = (checkPoint[0] - p1[0]) * (p2[1] - p1[1]) / (p2[0] - p1[0]) + p1[1]; if (p1[1] == p2[1] || checkPoint[1] <= xinters) { counter++; } } } } p1 = p2; } if (counter % 2 == 0) { return false; } else { return true; }}

—————————————————

數字孿生視覺化:https://www。thingjs。com/