电子围栏绘制、校验、不同坐标系(wgs84,jcg02、bd09)的相互转换,看这一篇就够了!

317 阅读3分钟

作为一名前端开发者,在工作中经常会用到地图相关的API,比如百度、高德、腾讯等,但是不同地图平台使用的坐标系可能不一样,这就导致定位时会出现几百米到1000左右的误差,比如在小程序平台获取位置的时候我们可以选择wgs84或者国标gcj02标准,但是如果把这些数据拿到后台用百度地图来显示的话,就会出现几百米的误差,所以就需要对经纬度做一下转换,来抹平各个坐标系之间的差异。

本篇文章不仅会介绍不同坐标系的转换,还会介绍电子围栏的绘制与校验。希望能够帮到有需要的人!

1、电子围栏的绘制

我这里使用的是百度地图,其他地图请参考相关开发者文档

1、地图绘制

地图绘制之前需要先注册一个百度开发者账号,获取一个密钥,然后引入百度地图相关js文件,即可使用百度地图。

        var map = new BMap.Map('map'); //创建map实例
        var poi = new BMap.Point(116.307852, 40.057031); //地图中心点
        map.centerAndZoom(poi, 16);
        map.enableScrollWheelZoom();  //是否开启滚轮缩放

2、电子围栏的绘制

        //定义一个空数组、用于保存绘制成功后,每个围栏的坐标集合、有一点需要注意的是这里的圆形是由42个坐标点绘制而成,
        如果围栏的范围过大,可能精细度不够。
        var overlays = [];
        var overlaycomplete = function (e) {
            overlays.push(e.overlay);
        };
        
        var styleOptions = {
            strokeColor: "red", //边线颜色。
            fillColor: "red", //填充颜色。当参数为空时,圆形将没有填充效果。
            strokeWeight: 3, //边线的宽度,以像素为单位。
            strokeOpacity: 0.8, //边线透明度,取值范围0 - 1。
            fillOpacity: 0.6, //填充的透明度,取值范围0 - 1。
            strokeStyle: 'solid' //边线的样式,solid或dashed。
        }
        //实例化鼠标绘制工具
        var drawingManager = new BMapLib.DrawingManager(map, {
            isOpen: false, //是否开启绘制模式
            enableDrawingTool: true, //是否显示工具栏
            drawingToolOptions: {
                anchor: BMAP_ANCHOR_TOP_RIGHT, //位置
                offset: new BMap.Size(5, 5), //偏离值
            },
            circleOptions: styleOptions, //圆的样式
            polylineOptions: styleOptions, //线的样式
            polygonOptions: styleOptions, //多边形的样式
            rectangleOptions: styleOptions //矩形的样式
        });
        //添加鼠标绘制工具监听事件,用于获取绘制结果
        drawingManager.addEventListener('overlaycomplete', overlaycomplete);

        function clearAll() {
            for (var i = 0; i < overlays.length; i++) {
                map.removeOverlay(overlays[i]);
            }
            overlays.length = 0
        }

image.png

2、电子围栏的校验

这块主要是判断某个坐标是否在已经划定好的电子围栏内,可用于考勤定位打卡等场景!

话不多说,直接放代码!


function isPointInPolygon(point, polygon) {
  var pts = polygon;
  var N = pts.length;
  var boundOrVertex = true;
  var intersectCount = 0;
  var precision = 2e-10;
  var p1, p2;
  var p = point;
  p1 = pts[0];
  for (var i = 1; i <= N; ++i) {
    if (p.lat == p1.lat || p.lng == p1.lng) {
      return boundOrVertex
    }
    p2 = pts[i % N];
    if (p.lat < Math.min(p1.lat, p2.lat) || p.lat > Math.max(p1.lat, p2.lat)) {
      p1 = p2;
      continue
    }
    if (p.lat > Math.min(p1.lat, p2.lat) && p.lat < Math.max(p1.lat, p2.lat)) {
      if (p.lng <= Math.max(p1.lng, p2.lng)) {
        if (p1.lat == p2.lat && p.lng >= Math.min(p1.lng, p2.lng)) {
          return boundOrVertex
        }
        if (p1.lng == p2.lng) {
          if (p1.lng == p.lng) {
            return boundOrVertex
          } else {
            ++intersectCount
          }

        } else {
          var xinters = (p.lat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) + p1.lng;
          if (Math.abs(p.lng - xinters) < precision) {
            return boundOrVertex
          }

          if (p.lng < xinters) {
            ++intersectCount
          }
        }
      }
    } else {
      if (p.lat == p2.lat && p.lng <= p2.lng) {
        var p3 = pts[(i + 1) % N];
        if (p.lat >= Math.min(p1.lat, p3.lat) && p.lat <= Math.max(p1.lat, p3.lat)) {
          ++intersectCount
        } else {
          intersectCount += 2
        }
      }
    }
    p1 = p2
  }
  if (intersectCount % 2 == 0) {
    return false
  } else {
    return true
  }
}

这个方法接收两个参数,第一参数是当前坐标,第二个参数绘制电子围栏时拿到数据,直接调用即可。

3、不同坐标系的相互转换

上文中我们绘制电子围栏使用的是百度的API,所有拿到的所有坐标都是BD09标准的,如果我们需要把这个数据拿到其他平台来用的话,必须对其进行转行,比如微信小程序只支持wgs84和gcj02标准。

这里我们可以使用Gcoord这个库,使用方式也非常简单。

1、安装引入

npm install gcoord --save
或者直接在页面中引入:
<script src="https://unpkg.com/gcoord/dist/gcoord.js"></script>

import gcoord from 'gcoord'
或者
const gcoord = require('gcoord')

2、使用Gcoord

var result = gcoord.transform(
  [116.403988, 39.914266],    // 经纬度坐标
  gcoord.WGS84,               // 当前坐标系
  gcoord.BD09                 // 目标坐标系
);

console.log(result);  

此方法接收三个参数,如上图所示。

gcoord支持的坐标系也非常广泛、目前支持以下这个,可以满足我们的开发需求!

image.png

如果此文对你有帮助,请留下一个免费的关注与点赞,谢谢!