博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于OpenLayers+rbush实现高德轨迹样式
阅读量:6030 次
发布时间:2019-06-20

本文共 4533 字,大约阅读时间需要 15 分钟。

hot3.png

一 前言

  近期翻阅博客,看到社区大神一休哥的一篇文章,同样,该大神还展示过一个使用rbush库如何在前端快速从海量数据进行空间检索的案例:,很有分享精神的前端GIS专家,更多关于前端GIS检索数据的技术可参考搜狐的干货专访:。关于轨迹样式带导航箭头这种常见问题,笔者基于兴趣和朋友们的总结,也试着用熟悉的OpenLayers的StyleFunction去实现一个这样的玩具,在此分享给大家。

高德轨迹箭头.png

 

  基于已知的一条轨迹,实现这样的一个导航轨迹箭头,需要解决三个问题:

  • 在轨迹上根据固定像素间隔,计算当前地图分辨率下箭头总数量。
  • 计算当前地图分辨率下,每个箭头的绘制位置。
  • 计算好箭头的数量和位置后,要确定箭头的方向。

一 箭头数量

  由高德轨迹箭头图可知,每隔固定像素,打上一个箭头。假设当前的线LineString地理长度为length,当前固定像素间隔stpes=n像素,在当前地图比例尺res已知的情况下,n像素地理距离是resn,那么箭头总数count=length/(resn):

let length=line_geom.getLength();//线图形的地理长度const steps=40;//每隔40像素打一个箭头点let geo_steps=map_res*steps;//40像素长度在当前地图比例尺下地理长度。let arrow_count=length*1.0/geo_steps;

多么浅显易懂的道理啊,第一个问题很顺利的解决了。

二 箭头位置

  第一步得到了箭头的总数,在获取箭头位置时,一个重要的API是线条LineString的getCoordinateAt,利用它我们在轨迹线上获取箭头点的位置。

/*fraction:参考点的百分比,如0就是LineString的起点,1就是LineString的终点,0.5就是LineString的中点。*/linestring.getCoordinateAt(fraction, opt_dest)

  假如箭头总数为arrowsNum,那么arrowsNum个箭头的数量分别是

for(let i=1;i

  得到每个箭头的位置后,我们先可视化下吧,OpenLayers的地图样式完全由StyleFunction实现的,完整样式代码如下:

/*feature:地图上的要素对象,既有属性,也有坐标图形。res:当前地图分辨率参数。return:返回一个定制的渲染样式*/var styleFunction = function(feature,res){        //轨迹线图形       var trackLine= feature.getGeometry();       var styles = [          new ol.style.Style({            stroke: new ol.style.Stroke({              color: '#2E8B57',              width: 10            })          })        ];        //轨迹地理长度        let length=trackLine.getLength();        //像素间隔步长        let stpes=40;//像素步长间隔        //将像素步长转实际地理距离步长        let geo_steps=stpes*res;        //箭头总数        let arrowsNum=parseInt(length/geo_steps);        for(let i=1;i

箭头位置计算与可视化结果.png

三 箭头方向

  之前的逻辑,我们已经计算了一个轨迹样式的雏形了,把地图上箭头位置的黄点改成一个箭头图标,做下方向旋转就可以了。在说明此前,需要说明下轨迹,segment线段,箭头点之间的关系,如下图:

 

轨迹,segment,箭头位置之间的关系.png

 

  观察示意图,总结如下:

  • 一条完整的轨迹由多个连续的segment组成。
  • 通过getCoordinateAt方法计算得到的箭头点,一定是在轨迹线上的某个点。
  • 每个箭头点的方向是由箭头点落在的segment的方向决定的。
    很显然,计算箭头方向其实就是计算每个箭头点到底落在了哪个segment上,将segme方向赋予箭头点。这里我们引入了rbush库构建空间索引,计算轨迹点与segment对应关系。
      之所以我要引入rbush库,是解决循环计算问题,想象下如果不引入rbush库,只能使用如下的伪代码暴力计算了:
for(let i=0;i

感觉逻辑很简单啊,这样做难道不可以吗?想象下,箭头数量,segment的数量其实都是不可控的,一个复杂的轨迹线可能由成百上千的近万的segments,这样一个个循环去匹配,效率是不是就有问题了?所以引入了空间索引。这里查询,使用了rbush进行btree查询,查询的结果后再详细比对是否和箭头相交,累了,直接贴代码了,不详述了:

var styleFunction = function(feature,res){        //轨迹线图形       var trackLine= feature.getGeometry();       var styles = [          new ol.style.Style({            stroke: new ol.style.Stroke({              color: '#2E8B57',              width: 10            })          })        ];        //对segments建立btree索引        let tree= rbush();//路段数        trackLine.forEachSegment(function(start, end) {            var dx = end[0] - start[0];            var dy = end[1] - start[1];            //计算每个segment的方向,即箭头旋转方向            let rotation = Math.atan2(dy, dx);            let geom=new ol.geom.LineString([start,end]);            let extent=geom.getExtent();            var item = {              minX: extent[0],              minY: extent[1],              maxX: extent[2],              maxY: extent[3],              geom: geom,              rotation:rotation            };            tree.insert(item);        });        //轨迹地理长度        let length=trackLine.getLength();        //像素间隔步长        let stpes=40;//像素步长间隔        //将像素步长转实际地理距离步长        let geo_steps=stpes*res;        //箭头总数        let arrowsNum=parseInt(length/geo_steps);        for(let i=1;i
1){ let results=treeSearch.filter(function(item){ //箭头点与segment相交,返回结果。该方法实测不是很准,可能是计算中间结果 //保存到小数精度导致查询有点问题 // if(item.geom.intersectsCoordinate(arraw_coor)) // return true; //换一种方案,设置一个稍小的容差,消除精度问题 let _tol=1;//消除精度误差的容差 if(item.geom.intersectsExtent([arraw_coor[0]-_tol,arraw_coor[1]-_tol,arraw_coor[0]+_tol,arraw_coor[1]+_tol])) return true; }) if(results.length>0) arrow_rotation=results[0].rotation; } styles.push(new ol.style.Style({ geometry: new ol.geom.Point(arraw_coor), image: new ol.style.Icon({ src: '../static/content/images/arrowright.png', anchor: [0.75, 0.5], rotateWithView: true, rotation: -arrow_rotation }) })); } return styles; }

轨迹箭头效果图.png

 

看着还凑合吧,但其实要做到高德那个精细的样式,才万里第一步,祝诸君继续研究,期待更好的效果。

作者:遥想公瑾当年
链接:https://www.jianshu.com/p/e68e8e1b7474
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转载于:https://my.oschina.net/u/1464512/blog/1936680

你可能感兴趣的文章
算法刷题笔记-stack-四则运算
查看>>
3.16
查看>>
Linux下arp用法
查看>>
表单文件上传与文件下载
查看>>
jquery 中prop()的使用方法
查看>>
下午考
查看>>
WKWebView
查看>>
创建字符设备的三种方法
查看>>
走在网页游戏开发的路上(六)
查看>>
nginx 配置的server_name参数(转)
查看>>
Uva592 Island of Logic
查看>>
C++基础代码--20余种数据结构和算法的实现
查看>>
footer固定在页面底部的实现方法总结
查看>>
nginx上传文件大小
查看>>
数字通信原理笔记(一)---概述
查看>>
HDU 2243 考研路茫茫——单词情结(自动机)
查看>>
Dubbo OPS工具——dubbo-admin & dubbo-monitor
查看>>
如何将OpenCV中的Mat类绑定为OpenGL中的纹理
查看>>
CutyCapt
查看>>
Dungeon Master ZOJ 1940【优先队列+广搜】
查看>>