作业车辆电子围栏应用

作业车辆电子围栏应用

背景意义
基于地图的电子围栏应用十分广泛,共享单车取车、锁车点,家长给小孩买的定位手表,离开设定的范围就会进行越界报警等等,这些都是属于实时监控类的,今天我们一起聊聊围栏越界的数据统计,主要应用场景有洒水车、环卫车、巡逻车辆等有既定路线的车辆在规定路线作业的越界数据统计。
一、绘制围栏
基于web方式使用地图的绘制多边形控件,我们以高德为例(其他诸如百度、天地图都一样),通过使用高德的控件,在地图上进行多边形绘制,记录多边形的每个顶点坐标。
代码如下:

二、保存围栏
绘制完成以后,需要将围栏数据和相关联的业务数据存储到本地,以备业务使用,我们将绘制好的围栏按照多边形的顶点数量进行批量(循环)写入数据库,每一个顶点作为一条记录,数据表的字段属性主要包括业务编号、经度、维度、是否启用、描述,当然也可以扩展更多的属性。
表设计如下
ElectronicFenceInfos----围栏信息表
在这里插入图片描述
一般情况下,一个业务编号对应多条记录,即业务和空间关系是一对多关系。
示例数据如下

三、编辑围栏
用户根据业务查询对应的围栏信息,可以通过在线拖拽编辑(地图控件功能)进行修改围栏形状,修改完成以后可以进行提交保存,需要同步更新数据表中对应的围栏信息,保存逻辑是,先根据业务编号删除对应的记录,然后再写入新纪录即可。
四、删除围栏
根据业务编号查询对应的围栏信息,可以通过选定围栏进行删除操作,删除以后,数据库不在存档备份。
五、围栏查询
1、可以查看所有的围栏信息,地图上以不同颜色或者根据不同状态显示围栏边界信息。
2、通过业务编号查询具体围栏。
3、可以通过鼠标点击事件查看围栏属性信息。

六、围栏统计
1、通过地图服务商提供的web端围栏相交的api进行判断,然后进行统计,这种方法适合客户端点数较少,只追求结果值,此处不做介绍,可以查看不同厂家的api。
2、通过后台查询计算,根据数据库保存的位置记录信息和围栏进行比对生成新的数据集,同时统计出越界数量,也可以获取越界点集。
后台通用的算法为:引射线法判断点与多边形的相交情况。
判断算法如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 判断点是否在多边形内
{
    class Program
    {
        public static void Main(String[] args)
        {
            Point[] ps = new Point[] { new Point(120.2043, 30.2795), new Point(120.2030, 30.2511), new Point(120.1810, 30.2543), new Point(120.1798, 30.2781), new Point(120.1926, 30.2752) };
            Point n1 = new Point(120.1936, 30.2846);
            Point n2 = new Point(120.1823, 30.2863);
            Point n3 = new Point(120.2189, 30.2712);
            Point y1 = new Point(120.1902, 30.2712);
            Point y2 = new Point(120.1866, 30.2672);
            Point y4 = new Point(120.1869, 30.2718);
 
 
            Console.WriteLine(IsPtInPoly(120.2043, 30.2795, ps));
            Console.ReadLine();
        }
        /// <summary>
        /// 判断点是否在多边形内或多边形上
        /// </summary>
        /// <param name="ALon">经度</param>
        /// <param name="ALat">纬度</param>
        /// <param name="Points">多边形边界点集合</param>
        /// <returns></returns>
        public static bool IsPtInPoly(double ALon, double ALat, Point[] Points)
        {
            int iSum, iCount, iIndex;
            double dLon1 = 0, dLon2 = 0, dLat1 = 0, dLat2 = 0, dLon;
            if (Points.Length < 3)
            {
                return false;
            }
            iSum = 0;
            iCount = Points.Length;
            for (iIndex = 0; iIndex < iCount; iIndex++)
            {          
                if (ALon == Points[iIndex].getX() && ALat == Points[iIndex].getY())  //A点在多边形上    
                    return true;
 
                if (iIndex == iCount - 1)
                {
                    dLon1 = Points[iIndex].getX();
                    dLat1 = Points[iIndex].getY();
                    dLon2 = Points[0].getX();
                    dLat2 = Points[0].getY();
                }
                else
                {
                    dLon1 = Points[iIndex].getX();
                    dLat1 = Points[iIndex].getY();
                    dLon2 = Points[iIndex + 1].getX();
                    dLat2 = Points[iIndex + 1].getY();
                }
               
                //以下语句判断A点是否在边的两端点的纬度之间,在则可能有交点
                if (((ALat > dLat1) && (ALat < dLat2)) || ((ALat > dLat2) && (ALat < dLat1)))
                {
                    if (Math.Abs(dLat1 - dLat2) > 0)
                    {
                        //获取A点向左射线与边的交点的x坐标:
                        dLon = dLon1 - ((dLon1 - dLon2) * (dLat1 - ALat)) / (dLat1 - dLat2);
                        //如果交点在A点左侧,则射线与边的全部交点数加一:
                        if (dLon < ALon)
                        {
                            iSum++;
                        }
                        //如果相等,则说明A点在边上
                        if(dLon==ALon)
                            return true;
                    }
                }
            }
            if ((iSum % 2) != 0)
            {
                return true;
            }
            return false;
        }
    }
    public class Point
    {
        private Double x;
        private Double y;
        public Point(Double x, Double y)
        {
            this.x = x;
            this.y = y;
        }
        public Double getX()
        {
            return x;
        }
        public void setX(Double x)
        {
            this.x = x;
        }
        public Double getY()
        {
            return y;
        }
        public void setY(Double y)
        {
            this.y = y;
        }
 
    }
}

越界数量统计
根据时间查询,我们设置一天时间即可,当前统计前一天的。

七、统计下钻
根据时间查询,我们设置一天时间即可,当前统计前一天的,越界数量统计的时候可以将越界的点集保存下来。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值