ThingJS实现电子围栏功能

应用场景:

场景1:在场(厂)内作业中,叉车作为特种设备,必须按要求在场(厂)内行驶,未获得监管部门允许,不得私自驶入场(厂)外道路。

此时,需要智能终端设备能对厂车的行驶区域做监管预警,防止车辆未按规定区域行驶,这就用到了电子围栏

当设备位置超出/驶出电子围栏区域时,设备触发报警并上报平台预警。

场景2:监所里看管犯人,如果犯人离开了管控区域,则发生报警

废话不多说,先上个效果图

ElectronicFence.ts

/**
 * @description 电子围栏功能
 */
/**
 * 实现思路
 * 1、通过鼠标拾取点位,创建自定义形状的电子围栏
 * 2、移除电子围栏
 * 3、监测电子围栏(通过update方式,刷新移动物体,拿到电子围栏形成的点位x,z坐标,移动物体的x,z坐标。通过算法监测物体位置是否在围栏位置范围内)
 */
// 绘制电子围栏的工具
THING.Utils.dynamicLoad(['/vendor/areaTools/index.js'])

class ElectronicFence {
  private _app: any
  constructor() {
    this._app = THING.App.current
  }

/**
* @description 鼠标拾取点位,创建自定义形状的电子围栏
*/
  drawElectronicFence() {
    areaTools.init()
  }

/**
* @description 结束绘制电子围栏
*/
  endDrawElectronicFence() {
    // 将数组存储在localStore
    const points = areaTools.getCoordinatesArray()
    localStorage.setItem('electronicFencePoint', JSON.stringify(points))
    // 销毁拾取的平面
    areaTools.destroyArea()
  }

/**
* @description 创建电子围栏
*/
  createElectronicFence(
    name: string,
    points: any[],
    regionColor: string,
    lineColor: string
  ) {
    const area = this._app.create({
      type: 'PolygonRegion',
      name: `${name}_electronicFence`,
      points: points, // 传入世界坐标系下点坐标
      style: {
        regionColor: regionColor, // 区域颜色
        lineColor: lineColor, // 边框颜色
        regionOpacity: 0.7, // 不透明度 (默认是 0.5 半透明)
      },
    })
    return area
  }

/**
 * @description 移除电子围栏
 */
  removeElectronicFence() {
    const fences = this._app.query(/electronicFence/)
    if (fences.length) fences.destroyAll()
  }

  /**
 * @description 检测目标点是否进入电子围栏区域
 * @param {Array} checkPoint - 校验坐标
 * @param {Array} polygonPoints - 形成电子围栏的坐标
 * @returns {Boolean} true 或 false
 * 此方法仅判断处于同一个平面的目标点是否在区域内(只判断坐标x和z值),
 *  不考虑两者当前离地高度(坐标的y值)
 */
  monitorElectronicFence(checkPoint: any[], polygonPoints: any[]) {
    let counter = 0
    let p1, p2
    const pointCount = polygonPoints.length
    p1 = polygonPoints[0]
    for (let i = 1; i <= pointCount; i += 1) {
      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]) {
            const 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
    }
  }
}
export default ElectronicFence


Demo.vue

<!--
* @Author: 袁宇宙中有朵云
* @Description: 电子围栏Demo
-->
<template>
  <div class="demo">
    <button @click="drawFence">绘制电子围栏</button>
    <button @click="endDrawFence">结束绘制电子围栏</button>
    <button @click="createFence">创建电子围栏</button>
    <button @click="removeFence">移除电子围栏</button>
    <button @click="monitorFence">监测电子围栏</button>
    <div class="tips" v-show="tipMessage">{{ tipMessage }}</div>
  </div>
</template>

<script lang="ts" setup>
  import { ref, onMounted, onBeforeUnmount } from 'vue'
  import ElectronicFence from '@/controllers/business/ElectronicFence'

  // 电子围栏对象
  let areaPolygonObj: any = {}
  const tipMessage = ref('')

  onMounted(() => {
    window.electronicFence = new ElectronicFence()
  })

  onBeforeUnmount(() => {
    window.electronicFence = null
    removeFence()
  })
  function drawFence() {
    window.electronicFence.drawElectronicFence()
  }
  function endDrawFence() {
    window.electronicFence.endDrawElectronicFence()
  }
  function createFence() {
    // 获取localStorage中的围栏信息
    const points: any = localStorage.getItem('electronicFencePoint')
    areaPolygonObj = window.electronicFence.createElectronicFence('电子围栏1号', JSON.parse(points), '#3CF9DF', '#3CF9DF')
  }
  function removeFence() {
    window.electronicFence.removeElectronicFence()
    const box = app.query('box')[0]
    if (box) box.destroy()
    tipMessage.value = ''
  }
  
  // 模拟人物在电子围栏中移动的路线
  function monitorFence() {
    const paths = [
      [-322.83731293191397, -0.00004130086550686862, 291.00748323559094],
      [-306.4490531432021, -0.00004114802510697679, 286.5421925683819],
      [-304.3588156887912, -0.00004144668099810567, 295.2675387077349],
      [-290.86054423027514, -0.00004128456881435927, 290.53136922421515],
      [-298.2861463575858, -0.000041718462059761596, 303.2077260104783],
      [-319.55418467413523, -0.000041723725334022466, 303.361494722941],
      [-328.35732290653607, -0.00004182404337797763, 306.292324785822]
    ]
    // 创建一个白盒子
    const box = app.create({
      type: 'Box',
      name: 'box',
      position: paths[0],
    })
    box.movePath({
      path: paths,
      orientToPath: true,
      time: 10 * 1000,
      complete: () => {
        console.log('移动完成')
      },
      update: () => {
        const checkPoint = [box.position[0], box.position[2]]
        const points: any = localStorage.getItem('electronicFencePoint')
        const pointsArr: any[] = []
        JSON.parse(points).forEach((p: any) => {
          pointsArr.push([p[0], p[2]])
        })
        const isIn = window.electronicFence.monitorElectronicFence(checkPoint, pointsArr)
        if (isIn) {
          areaPolygonObj.style.regionColor = '#3CF9DF'
          tipMessage.value = ''
        } else {
          areaPolygonObj.style.regionColor = '#a94442'
          tipMessage.value = '当前位置不在电子围栏内'
        }
      }
    })
  }
</script>

<style lang="less" scoped>
.demo {
  position: absolute;
    top: 10px;
    width: 100%;
    height: 100%;
    pointer-events: none;

    button {
        pointer-events: all;
    }

    .tips {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: auto;
        height: 40px;
        background: rgba(255, 255, 255, 0.5);
        color: red;
        text-align: center;
        line-height: 20px;
    }
}
</style>


以上功能的实现,里面涉及了一个绘制电子围栏区域的小工具,代码未呈现出来。以上只是提供了一个大概实现思路,需要根据具体业务需求进行使用。

文章中使用的API,可通过ThingJS的API文档查看学习https://docs.thingjs.com/cn/apidocs/

  • 13
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

袁宇宙中有朵云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值