Based on HTML5 WebGL 3D industrial electronic fence

Foreword

Modern industrialization in advance greatly accelerate the process of modernization, it also brings the appropriate security risks in the traditional visual surveillance, are generally based on Web SCADA front-end technology to achieve 2D visual monitoring, the system uses the HT for Hightopo Web product is constructed of lightweight 3D visualization scene, the 3D scene from the front, showing the reality of a modern factory scene, including real-time location of factory workers, the scope of electronic fence, site safety conditions, etc., to help us understand the current intuitive factory security personnel.

This article by loading the factory to build visual scenes and models, to achieve real-time positioning character code, the electronic fence and implement trajectories are set forth to help us understand how to implement a simple electronic fence 3D visualization through the use of HT.

The following items are Address: based on HTML5 WebGL 3D industrial electronic fence , trajectories

Results preview

Plant personnel effects and real-time positioning electronic fence effect

Trajectories renderings

Trajectories

Code

The character models and scenes

The character models used in the project are generated by 3dMax modeling, the modeling tool can export obj and mtl files can be generated in HT camera model 3d scene by parsing obj and mtl files.

The project to build the scene by HT of 3d editor, scene of some of the model by HT modeling, some by 3dMax modeling, after the import of HT.

Drawing electronic fence

Electronic fence scene model built 3dMax not used, HT embodiment provides an interface for the user to type more base body model used, unlike conventional 3D modeling, modeling kernel API HT are based by predefined parameters and interfaces element types, to build three-dimensional model is provided to achieve. The shape, the electronic fence I into a cylindrical, rectangular, and polygonal prism bottom.

Here are the pseudo-code I draw the electronic fence:

  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]);

 

Before the figures further, the pipeline to the point of focus to promote the coordinates of a point, while creating a new section of pipe. Similarly, the characters take a step back, the focus point of the pipeline launch coordinates of the last point of the current, while the last two pipeline lose some connections. In addition, I by using a timer, for forward and backward trajectories were made to fast forward and rewind process. The following operating results for the trajectories:

Guess you like

Origin www.cnblogs.com/xhload3d/p/11639320.html