基于GIS实现路灯朝向自动校正

1,865 阅读3分钟

需求说明

之前做了个在高德地图上用GLCustomLayer加载gltf模型的图层,还在沾沾自喜的时候,领导找到我说你这个图层有问题啊,路灯朝向不对,路灯不照公路转头去照路边小情侣吗,赶紧给我改过来。

一开始接到领导这个任务到时候我内心OS其实拒绝的,5万多个模拟灯杆数据要调朝向得调到什么时候,而且这么无聊又耗时的工作一点意思都没有;领导好像从我向上翻的眼神中看到了我的小心思,他说你可以写个脚本让灯杆自己转啊。不愧是领导,格局一下子就打开了。

实现思路

计算灯杆朝向的角度需要一点点几何知识,我们假设所有灯杆朝向V0未校正前都是正北0度,灯杆正确朝向V1应该与距离其最近道路线段为90度,那么自动偏移的角度应该为V0和V1的夹角θ。

我们可以用向量法求V0和V1的夹角θ,向量的点积公式为

// 已知
V0·V1 = |V0||V1|cosθ
V0·V1 = (x0,y0)·(x1,y1) = x0*x1 + y0*y1

// 将向量V0,V1归一化,即向量长度为1
v0 = Math.sqrt(Math.pow(x0,2)+Math.pow(x1,2))
x0' = x0 / v0
y0' = y0 / v0

// 由此可得
θ = acos(V0·V1/(|V0||V1|)) = Math.acos((x0' * x1' + y0' * y1') / 1)

核心原理是这样,但是在实际开发中不需要自己重头开始写代码,我们借助地理空间分析库Turf.js来简化一下工作。不得不说有轮子就是香。

  1. 接收一个点要素P和一个线要素L,计算出该点在该线上最近的点要素P1并返回
let P1 = turf.nearestPointOnLine(L,P)
  1. 计算获取两点之间的地理方位,并与正北方向所形成的角度θ(正北为0度,逆时针到180,顺时针到-180)
let θ = turf.bearing(P,P1)
  1. 将角度θ转换为0~360正值(即正北0度,逆时针为正方向)
let angle = turf.bearingToAzimuth(θ)

相关代码

// 生成点元素
function addMarker(info) {
  let {lngLat, angle, id} = info
  let marker = new AMap.Marker({
    content: `<img src="./static/icon/arrow-up.svg" style="width: 30px; height: 30px;"/>`,
    offset: [-15, -30],
    position: lngLat,
    angle: angle,
    extData: {angle, id}
  })
  markers.push(marker)
  marker.setMap(map)
}

// 自动校准单个点元素朝向
function fitDirection(marker){

  let {lng, lat} = marker.getPosition()

  let line = turf.lineString(roadPath)
  let pt = turf.point([lng,lat])

  // 获得在线上,距离点pt最近的点P1
  let snapped = turf.nearestPointOnLine(line, pt, {units: 'miles'})

  //计算2个点所成方向与正北方向形成的角度
  let bear = turf.bearing([lng,lat], snapped.geometry.coordinates)

  //接收与正北方向所形成的角度(-180 ~ 180),返回正值(0 ~ 360)
  let angle = turf.bearingToAzimuth(bear)

  //朝向角度
  marker.setAngle(angle)

  //更新extData
  let extData = marker.getExtData()
  marker.setExtData(Object.assign(extData, {angle}))
}

扩展思考

实例中仅仅是用了一条道路的数据做演示,实际项目中有成百上千条道路数据,几万个灯杆数据,需要先做个预处理,将灯杆与道路关联起来。怎么知道每个灯杆要朝哪条道路校正朝向呢,目前我能想到的有两种做法:

1. 每个灯杆数据增加所属道路属性,与道路id关联起来;

2. 通过现有地理信息自动关联,比如将道路L自动拓宽变成多边形面M,位于M里面的点即为L关联的灯杆数据。

批量自动校正的方法当然会有误差,个别数据还需要人工校正,总体来说工作量是大大简化了。

在这里还是强烈推荐一下地理空间分析库Turf.js,GIS开发必备工具箱。

psilocine.github.io/turfjs-docs…