在机场使用的空管系统中,飞机的速度矢量线差不多是这样的:

模拟飞机飞行时的速度矢量线,这里就大概做个类似效果:

什么叫速度矢量线呢,个人理解就是根据飞机当前速度和航向预测它在未来一段时间内的飞机轨迹,以此来监测飞机是否偏离。

如何运行代码已经在上一篇博客《动态加载JSON数据模拟航迹线》讲过了。

在这个模拟DEMO中,主要存在四个图层,分别为地图底图、航迹线图层、速度矢量线图层、飞机图层(我用的点代替飞机图标),因为我自身有一个需求就是控制航迹和速度矢量线的显示与隐藏,这跟本文没多大关系。

技术准备

常规的数学公式都知道,路程 = 速度 * 时间,在地图上的一些相关计算,查阅了一些资料,并翻译了相关的计算博文《(译)计算距离、方位以及更多经纬度之间的点》,并Google到了一个相关的技术博客,只不过这是基于OL 2的一些例子,但是我从中得到了一些灵感。

1.实现

在上一篇博文的代码基础上添加,相关都做了详细注释

2.图层以及样式

 /**
* @name: 相关样式和图层:点 航迹线 飞机 标牌
* @test: test font
* @msg:
* @param {type}
* @return:
*/
//样式
let point_style = new ol.style.Style({//预测点
image:new ol.style.Circle({
radius:2,
snapToPixel:false,
fill:new ol.style.Fill({
color:'#333'
}),
stroke:new ol.style.Stroke({
color:"#333",
})
})
})
let route_style = new ol.style.Style({//航迹线
stroke:new ol.style.Stroke({
width:2,
color: 'yellow'
}),
zIndex:2
});
let vel_style = new ol.style.Style({//速度矢量线
stroke:new ol.style.Stroke({
color: '#333',
width: 1,
})
});
//创建轨迹线
let trackLine = new ol.geom.LineString([]);
//速度矢量线
let velLine = new ol.geom.LineString([]);
//矢量图层层
let aircfaftLayer = new ol.layer.Vector({//飞机图层
source:new ol.source.Vector(),
updateWhileInteracting: true,
updateWhileAnimating: true
})
let flightTrackLayer = new ol.layer.Vector({//航迹线图层
source:new ol.source.Vector({
features:[
new ol.Feature({
geometry:trackLine
})
]
}),
style:route_style,
updateWhileInteracting: true
});
let velLayer = new ol.layer.Vector({//速度矢量线图层

3.初始化地图

/*
* @name: 初始化地图
* @description:
* @param {type} none
* @return: */
let center = new ol.proj.fromLonLat([104.06250000000001, 30.65681556429287]);
//地图
let map = new ol.Map({
//图层顺序自下而上
layers: [
new ol.layer.Tile({
source: new ol.source.OSM({ })
}),flightTrackLayer,velLayer,aircfaftLayer,
],
renderer: 'canvas',
target: 'map',
view: new ol.View({
center: center,
zoom: 6
})
}); /**
* @name: 飞机 标牌 样式
* @description:
* @param {type} none
* @return:
*/
//标牌叠加层 + 指引线
let markerEl = document.getElementById('geo-marker');//标牌
let marker = new ol.Overlay({
positioning: 'bottom-center',
stopEvent: false,
dragging: false,
offset: [0, -10],
element: markerEl,
stopEvent: false
});
map.addOverlay(marker); //飞机样式 以点代替飞机图片
function createGoodStyle() {
return new ol.style.Style({
image:new ol.style.Circle({//点状模拟飞机
radius:6,
snapToPixel:false,
fill:new ol.style.Fill({
color:'yellow'
}),
stroke:new ol.style.Stroke({
color:"#333",
width:2
})
}) });
}
//设置地图中心
let centerAir = val => {
map.getView().setCenter(val);
}

4.加载数据

/**
* @name: 加载数据
* @description:
* @param {type} none
* @return:
*/
//添加飞机 + 更新位置 const KTS2KPH = 1.85200;//1 knot (kt) = 1.85200 kilometer per hour (kph)
const NM2KM = 1.852;
const pred_secs = 5 * 60; //5分钟
const bearing = 90; //航向
let coords = [], speedMH = [], flightData, intervalId, interval = 1000, i = 0;
let from , to, distance_whole, tiem_whole, distance_cur, point_cur, point_next;
const url = './data/openflights/vel.json';
let theAirplane = new ol.Feature([]); $('.startAnimate').click(() => {
//加载坐标数据
$.ajax({
url: url,
dataType: 'json',
success: function (response) {
console.log("飞行开始");
flightData = response.data;
coords = flightData.map(obj => {//坐标集合
return obj[0];
})
speedMH = flightData.map(obj => {//速度集合
return obj[1];
})
//飞机
theAirplane.setId(response.aircraftNum);
theAirplane.setStyle(createGoodStyle());
aircfaftLayer.getSource().addFeature(theAirplane); //预测点
let vel_point = new ol.Feature([]);
vel_point.setStyle(point_style);
velLayer.getSource().addFeature(vel_point); //模拟飞行
intervalId = setInterval(() => {
let position;
position = ol.proj.fromLonLat(coords[i]); //标牌
marker.setPosition(position);
markerEl.innerHTML = response.aircraftNum;//简标牌 //飞机
theAirplane.setGeometry(new ol.geom.Point(position)); //航迹
let point = new ol.proj.transform(coords[i], 'EPSG:4326', 'EPSG:3857');
trackLine.appendCoordinate(point); //以飞机当前位置为地图中心
centerAir(position); //速度矢量线
from = new LatLon(coords[0][1], coords[0][0]);//起点
to = new LatLon(coords[coords.length - 1][1], coords[coords.length - 1][0]);//终点
// console.log(from, to); distance_whole = from.distanceTo(to) / 1000;// km 总里程
tiem_whole = distance_whole / speedMH[i] / KTS2KPH;// hour 总耗时
// console.log(distance_whole, tiem_whole); point_cur = new LatLon(coords[i][1], coords[i][0]);//当前坐标
distance_cur = KTS2KPH * speedMH[i] * ( pred_secs * interval / 3600); //已经过里程
point_next = point_cur.destinationPoint(distance_cur, bearing); //预测5分钟后所在的坐标点
// console.log( distance_whole, tiem_whole, distance_cur, point_next);
let pointCur = ol.proj.fromLonLat([point_cur._lon, point_cur._lat]);
let pointNext = ol.proj.fromLonLat([point_next._lon, point_next._lat]); let pointNextArray = Array();
pointNextArray.push(pointNext);
console.log(pointNextArray); //预测点
vel_point.setGeometry(new ol.geom.Point(pointNext)); //速度矢量线
let velFeature = new ol.Feature(velLine);
velFeature.setStyle(vel_style);
velLine.setCoordinates([pointCur, pointNext]); //绘制速度矢量线
velLayer.getSource().addFeature(velFeature); i++;
if (i === flightData.length) {
clearInterval(intervalId);
console.log("飞行结束");
} }, interval); }
})
})

5.json数据

json数据来源于arc.js,该例子选取的是成都—上海的坐标数据,速度是我自己随意添加的:

{

    "ID": "1",
"aircraftNum": "B000",
"data": [
[[104.06250000000001, 30.65681556429287], "284"],
[[104.23659653944907, 30.67396833485058], "285"],
[[104.4107544999246, 30.690888911014596], "285"],
[[104.58497310591778, 30.70757705503652], "286"],
[[104.75925157857333, 30.724032532190993], "284"],
[[104.93358913572729, 30.740255110788784], "286"],
[[105.10798499194534, 30.75624456218971], "287"],
[[105.28243835856125, 30.772000660815337], "288"],
[[105.45694844371592, 30.787523184161603], "288"],
[[105.63151445239656, 30.80281191281125], "287"],
[[105.80613558647657, 30.817866630446186], "288"],
[[105.98081104475536, 30.8326871238596], "287"],
[[106.15554002299895, 30.847273182967992], "287"],
[[106.33032171398055, 30.861624600823], "286"],
[[106.50515530752187, 30.875741173623137], "285"],
[[106.68003999053437, 30.889622700725297], "287"],
[[106.85497494706121, 30.90326898465615], "285"],
[[107.02995935831927, 30.916679831123393], "288"],
[[107.20499240274177, 30.929855049026738], "287"],
[[107.38007325602092, 30.942794450468945], "286"],
[[107.55520109115115, 30.95549785076639], "285"],
[[107.73037507847249, 30.967965068459744], "287"],
[[107.90559438571445, 30.98019592532436], "286"],
[[108.08085817803996, 30.992190246380456], "288"],
[[108.25616561808987, 31.003947859903253], "287"],
[[108.43151586602752, 31.01546859743276], "285"],
[[108.60690807958395, 31.026752293783623], "286"],
[[108.7823414141029, 31.0377987870545], "285"],
[[108.9578150225866, 31.0486079186376], "287"],
[[109.13332805574153, 31.059179533227734], "285"],
[[109.30887966202457, 31.069513478831404], "286"],
[[109.48446898768944, 31.079609606775563], "285"],
[[109.66009517683327, 31.089467771716325], "287"],
[[109.83575737144373, 31.099087831647413], "285"],
[[110.011454711446, 31.108469647908397], "287"],
[[110.18718633475038, 31.11761308519283], "288"],
[[110.36295137729994, 31.126518011556165], "289"],
[[110.53874897311843, 31.135184298423425], "287"],
[[110.7145782543585, 31.14361182059676], "286"],
[[110.89043835135004, 31.151800456262833], "285"],
[[111.06632839264884, 31.1597500869999], "286"],
[[111.24224750508553, 31.16746059778481], "287"],
[[111.4181948138144, 31.17493187699975], "288"],
[[111.5941694423629, 31.182163816438862], "289"],
[[111.77017051268102, 31.18915631131456], "290"],
[[111.94619714519094, 31.195909260263747], "288"],
[[112.1222484588369, 31.202422565353807], "288"],
[[112.29832357113521, 31.208696132088367], "288"],
[[112.47442159822452, 31.21472986941292], "288"],
[[112.65054165491617, 31.220523689720157], "287"],
[[112.82668285474469, 31.226077508855244], "287"],
[[113.00284431001862, 31.231391246120737], "288"],
[[113.17902513187131, 31.236464824281384], "287"],
[[113.35522443031194, 31.241298169568736], "286"],
[[113.53144131427662, 31.245891211685535], "285"],
[[113.70767489167979, 31.250243883809823], "285"],
[[113.88392426946552, 31.254356122599024], "285"],
[[114.0601885536591, 31.258227868193615], "286"],
[[114.23646684941869, 31.26185906422076], "285"],
[[114.41275826108706, 31.265249657797618], "287"],
[[114.58906189224348, 31.268399599534526], "287"],
[[114.76537684575561, 31.271308843537938], "286"],
[[114.94170222383167, 31.27397734741316], "287"],
[[115.11803712807243, 31.276405072266883], "288"],
[[115.2943806595235, 31.27859198270948], "288"],
[[115.47073191872758, 31.28053804685718], "288"],
[[115.64709000577683, 31.282243236333912], "288"],
[[115.82345402036526, 31.28370752627301], "288"],
[[115.99982306184107, 31.284930895318737], "288"],
[[116.17619622925929, 31.285913325627515], "288"],
[[116.35257262143426, 31.28665480286904], "288"],
[[116.52895133699217, 31.28715531622708], "288"],
[[116.70533147442355, 31.28741485840016], "287"],
[[116.8817121321361, 31.28743342560202], "288"],
[[117.0580924085071, 31.28721101756178], "288"],
[[117.23447140193603, 31.286747637524012], "287"],
[[117.41084821089731, 31.286043292248515], "287"],
[[117.58722193399282, 31.285097992009906], "287"],
[[117.76359167000443, 31.283911750597046], "287"],
[[117.93995651794664, 31.282484585312172], "286"],
[[118.11631557711907, 31.280816516969885], "286"],
[[118.29266794715906, 31.278907569895903], "286"],
[[118.46901272809394, 31.276757771925578], "286"],
[[118.64534902039362, 31.27436715440231], "286"],
[[118.82167592502275, 31.271735752175562], "286"],
[[118.99799254349321, 31.268863603598895], "286"],
[[119.17429797791613, 31.26575075052759], "285"],
[[119.35059133105422, 31.262397238316204], "285"],
[[119.52687170637368, 31.258803115815805], "285"],
[[119.70313820809623, 31.254968435371172], "285"],
[[119.87938994125103, 31.250893252817523], "285"],
[[120.05562601172639, 31.2465776274773], "285"],
[[120.2318455263214, 31.242021622156606], "285"],
[[120.40804759279759, 31.237225303141468], "285"],
[[120.58423131993031, 31.232188740193873], "285"],
[[120.76039581756008, 31.226912006547636], "285"],
[[120.93654019664363, 31.221395178904057], "284"],
[[121.11266356930511, 31.215638337427364], "284"],
[[121.28876504888679, 31.20964156573994], "284"],
[[121.46484375, 31.203404950917395], "283"]
] }

后续要完成的就是拖拽飞机标牌以及控制图层的显示与隐藏

查看源码:GitHub

OpenLayers学习笔记(十一)— 飞机速度矢量线预测的更多相关文章

  1. OpenLayers学习笔记(十二)— 飞机速度矢量线预测(二)

    根据计算公式实现预测线 作者:狐狸家的鱼 GitHub:八至 之前有一篇博客简单写了一个模拟demo,根据物体当前的速度和方向预测多少时间后所在的位置,具体计算是参考<(译)计算距离.方位以及更 ...

  2. python3.4学习笔记(十一) 列表、数组实例

    python3.4学习笔记(十一) 列表.数组实例 #python列表,数组类型要相同,python不需要指定数据类型,可以把各种类型打包进去#python列表可以包含整数,浮点数,字符串,对象#创建 ...

  3. Go语言学习笔记十一: 切片(slice)

    Go语言学习笔记十一: 切片(slice) 切片这个概念我是从python语言中学到的,当时感觉这个东西真的比较好用.不像java语言写起来就比较繁琐.不过我觉得未来java语法也会支持的. 定义切片 ...

  4. OpenLayers学习笔记(十)— 动态加载JSON数据模拟航迹线

    在openlayers 3 上,加载本地json数据,动态绘制航迹线,以飞机当前位置为地图中心,此例子是模拟DEMO 本文链接:动态加载JSON数据模拟航迹线 作者:狐狸家的鱼 GitHub:八至 前 ...

  5. SharpGL学习笔记(十一) 光源创建的综合例子:光源参数可调节的测试场景

    灯光的测试例子:光源参数可以调节的测试场景 先看一下测试场景和效果. 场景中可以切换视图, 以方便观察三维体和灯光的位置.环境光,漫射光,镜面反射光都可以在四种颜色间切换. 灯光位置和摄像机位置(Lo ...

  6. JavaScript权威设计--JavaScript函数(简要学习笔记十一)

    1.函数调用的四种方式 第三种:构造函数调用 如果构造函数调用在圆括号内包含一组实参列表,先计算这些实参表达式,然后传入函数内.这和函数调用和方法调用是一致的.但如果构造函数没有形参,JavaScri ...

  7. OpenLayers学习笔记4——使用jQuery UI实现測量对话框

    OpenLayers学习最好的方式就是跟着其自带的演示样例进行学习,另外对web前端的开发设计要了解,慢慢积累,这样在一般的小项目中应该是足够用了. 本篇參照量測demo实现对话框形式的量測,抛砖引玉 ...

  8. openlayers学习笔记(十三)— 异步调用JSON数据画点、文字标注与连线

    使用Openlayers 3实现调用本地json数据在地图上添加点.文字标注以及连线. 生成底图地图 首先得有一个地图作为底图,代码如下: let vectorSource = new ol.sour ...

  9. java jvm学习笔记十一(访问控制器)

     欢迎装载请说明出处: http://blog.csdn.net/yfqnihao/article/details/8271665 这一节,我们要学习的是访问控制器,在阅读本节之前,如果没有前面几节的 ...

随机推荐

  1. Java设计模式---Strategy策略模式

    参考于 : 大话设计模式 马士兵设计模式视频 1.场景介绍 购物网站上有一个产品,有三个字段,档次,价格,重量. 有些同学喜欢轻的,有些手头紧,想要便宜的,有些喜欢档次高的. 那么我们为了提高网站用户 ...

  2. 剑指前端(前端入门笔记系列)—— JS基本数据类型及其类型转换

    基本数据类型 ECMAScript中有5中简单数据类型性(也称为基本数据类型):Undefined.Null.Boolean.Number和String,还有一种复杂数据类型——Object,Obje ...

  3. HTML/CSS快速入门

    Web概念 JavaWeb 使用java语言开发基于互联网的项目 软件架构 C/S架构:Client/Server 客户端/服务器 用户本地有一个客户端程序,在远程有一个服务端程序 如QQ,英雄联盟. ...

  4. 一起学Android之ViewPager

    本文以一个简单的小例子,简述在Android开发中ViewPager的常见用法,仅供学习分享使用. 概述 ViewPager是一个支持使用者左右滑动的布局管理控件,可以通过一个实现的(适配器)Page ...

  5. .NET Core 学习笔记2——管理nuget包

    .NET Core 基于Nuget包.它是一个.nupkg后缀的zip文件. 工具 dotnet 工具 vs2017 的程序包管理控台 这两个工具都可以用命令行来下载安装,更新,上传包(上传要先在网站 ...

  6. Python 经典面试题汇总之数据库篇

    数据库和缓存 1.列举常见的关系型数据库和非关系型都有那些? 关系型数据库(需要有表结构) mysql.oracle.splserver.postgresql.db2.sybase 非关系型数据库(是 ...

  7. selenium-自动化用例(十一)

    思路 将页面操作与用例case分别封装,编写case时就可以用同一个操作方法对应多个case 如下图: PageGUI:存放页面操作方法,每个页面写一个文件,每个文件中写同一个页面不同的操作,例如检索 ...

  8. Vue.js01:跑马灯效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. fastjson SerializerFeature详解

  10. Anaconda在Windows上安装不上原因

    倒腾了一下午安装Anaconda,[所有程序]中只有一个Anaconda的目录,目录中只有一个anaconda prompt,最后发现是因为环境中原先就安装了Java环境,将之前安装的java环境卸载 ...