cesium 使用时间轴显示轮船实时位置轨迹,通过粒子系统添加轮船尾浪效果

您所在的位置:网站首页 k238实时动态位置 cesium 使用时间轴显示轮船实时位置轨迹,通过粒子系统添加轮船尾浪效果

cesium 使用时间轴显示轮船实时位置轨迹,通过粒子系统添加轮船尾浪效果

2024-07-14 10:17| 来源: 网络整理| 查看: 265

cesium 通过websocket接收轮船实时位置,通过粒子系统添加轮船尾浪效果

啊~ 宝宝儿们,我是一个前端小白白,最近呢,在尝试做一个GIS效果,就是webscoket接收后台传递过来的轮船实时位置,一秒钟推送一次,传递过来的信息包括了轮船的id、轮船经度和纬度、以及轮船的方向角度。要求使用cesium实时展示轮船的位置和朝向。但是我之前没有接触过cesium,根本不会,文档都是英文的,我都不会看,然后我连基本的操作和概念都不会,不知道正经应该怎么整,所以就瞎搞,好在实现了一些效果,然后呢就记录一下。首先呢,我的效果实现的有点瑕疵,因为不知道正经怎么搞,所以说代码写的并不是很规范或者是使用的方法并不一定就是对的,仅供参考,不可尽信哈!交流学习嘛~~~

参考资料

我就是一个代码裁缝。 在这里插入图片描述 首先就两个参考文档给大家分享一下,一个是cesium的中文文档,一个是案例地址。

cesium中文文档 【传送门】 cesium官方案例【传送门】

实现代码 创建cesium

创建cesium、创建模型、使用个性化图层影像啥的,这些我之前的博客已经写过来,就不再重复了,然后我本地址在这个地方

但是有一个地方更新一下,创建的时候地形影像可以用这个,效果更好一点。

terrainProvider: Cesium.createWorldTerrain({ requestWaterMask: true, // required for water effects requestVertexNormals: true // required for terrain lighting }) 使用时间轴

我是这么想的,因为后端使用websocket接受实时数据嘛不是,一秒钟收发一条船的当前位置,更新位置的时候需要船模型缓慢的移动过去而不是直接从一个闪现到另一个点,这样看上去更圆滑,所以说我搜了半天,都是一跳一跳的,起码我的那点本事发现就只有时间轴是可以缓慢的移动过去而不是跳过去,所以说就用了时间轴。

时间轴的原理是啥哈,简单说一下我的理解,方便没有用过的人不至于一脸懵逼。

我的理解是哈~~ 就是在这个 cesium示例上创建一个时间线,需要设置这个时间线的开始时间和结束时间,然后我的船模型通过位置信息与时间线绑定,就是在那个时间,船模型的位置在哪一个时间点,我不知道我说清楚了没有,然后播放时间线的时候,船模型会根据你的时间线出现在你绑定的位置上。

就是假设哈!你的时间轴开始时间是今天的00:00:00,结束时间是今天的23:59:59,然后你又绑定了船模型的位置,比如今天00:00:00秒的时候,船在A点,这个A点是经纬度坐标哈!然后今天的01:00:00秒船模型在B点,然后运行的时候,模型就会在今天00:00:00秒的时候出现在A点,01:00:00的时候出现在B点,两点创建一条直线嘛,然后中间隔得这一个小时,cesium会自动计算从A点到B点走过的位置,会让船匀速的用一个小时的时间,从A点走到B点,我应该说清楚了吧宝宝们?如果不用时间轴而是接受数据之后直接更新船模型的位置信息,船是会直接闪现到更新后的位置,一秒钟一次,放近看船模型就是跳着走的,这个效果不好,需要其他的处理船才会平移过去,但是我不会!所以我用了时间轴,她帮我缓慢的移动过去。 OK,就是这个意思哈。如果有更好的方式就用其他的,我菜,我不大会。我现在的大脑袋瓜子就只允许我这么做了。 在这里插入图片描述

创建时间轴

我们不是创建了实例了嘛,然后使用时间轴的时候我们需要改点东西。就是开启时间轴,就是下面这个代码。

viewer = new Cesium.Viewer('map', { baseLayerPicker: false, // 影像切换 animation: true, //是否显示动画控件 timeline: false, //是否显示时间线控件 infoBox: false, //是否显示点击要素之后显示的信息 geocoder: false, //是否显示地名查找控件 timeline: true, //是否启用时间线控件 fullscreenButton: false, shouldAnimate: true, navigationHelpButton: false, //是否显示帮助信息控件 terrainProvider: Cesium.createWorldTerrain({ requestWaterMask: true, // required for water effects requestVertexNormals: true // required for terrain lighting }) })

其实就是设置 timeline 为 true,这个是必须的哈,不然时间轴不管用。设置了之后呢,可能就会出现下面这个东西。 在这里插入图片描述 然后界面如果不想显示左边的控制台和下面的时间线也没有关系,我们关闭就可以,怎么关闭呢,两个参数设置一下

animation 设置成 false,左边的控制台就没有了,时间线添加下面这行代码隐藏

viewer.timeline.container.style.display = 'none';

通过上面上面两个步骤,控制台和时间轴都不显示了就,很棒!

时间轴设置

上面我们启用的时间轴时间是默认的哈,就是系统默认的,我们可以根据自己的需要自己设置修改时间轴的开始时间结束时间啥的,然后就是下面这个样子哈宝宝们~

start = Cesium.JulianDate.fromDate(new Date()); // 设置时间轴当前时间为开始时间 start = Cesium.JulianDate.addHours(start, 8, new Cesium.JulianDate()); // 开始时间加8小时改为北京时间 stop = Cesium.JulianDate.addSeconds(start, 400, new Cesium.JulianDate()); // 设置结束时间为开始时间加400秒 // 设置时钟开始时间 viewer.clock.startTime = start.clone(); // 设置时钟当前时间 viewer.clock.currentTime = start.clone(); // 设置时钟结束时间 viewer.clock.stopTime = stop.clone(); // 时间速率,数字越大时间过的越快,设置1好像是和实际时间一样 viewer.clock.multiplier = 1 ; // 时间轴绑定到viewer上去 viewer.timeline.zoomTo(start, stop); // 循环执行,到达终止时间,重新从起点时间开始 viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;

然后通过上面的代码,我们就自定义了时间轴的开始时间和结束时间。

添加模型绑定时间轴

然后我们可以添加一个模型实验一下子哈,我们先写死这个轮船的位置信息,先不从websocket获取哈,然后呢,就是单纯的测试一下时间轴怎么用哈。

首先创建一个船模型。

let property = computeFlight(data) // 这是通过一个方法把时间轴和船的位置信息绑定了 entity = viewer.entities.add({ availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start: start, stop: stop })]), position: property, orientation: new Cesium.VelocityOrientationProperty(property), // 根据速度计算方向角 model: { uri: './models/boat2.gltf', //gltf文件的URL scale: 0.05, //放大倍数 color: Cesium.Color.fromCssColorString('rgba(0, 253, 239, 0.6)'), // 船模型颜色 silhouetteColor: Cesium.Color.fromCssColorString('rgba(0, 255, 0, 1)'), // 船模型边框颜色 silhouetteSize: 1 // 船模型边框宽度 }, path: { // 船路径 resolution: 1, // 这个不知道是啥 material: new Cesium.PolylineGlowMaterialProperty({ glowPower: 0.1, // 颜色透明度 color: Cesium.Color.fromCssColorString('rgba(0, 253, 239, 0.5)') // 路线颜色 }), width: 2 // 路线的显示宽度 } }); viewer.trackedEntity = entity; // 视角跟随模型

然后是时间轴与位置绑定的函数

function computeFlight(source) { let property = new Cesium.SampledPositionProperty(); for (let i = 0; i { particleSystem.modelMatrix = computeModelMatrix(entity, time); // 粒子系统和模型绑定,让他跟着模型跑 });

然后需要三个函数。

function applyGravity(p, dt) { const position = p.position; Cesium.Cartesian3.normalize(position, gravityScratch); Cesium.Cartesian3.multiplyByScalar( gravityScratch, 0 * dt, gravityScratch ); p.velocity = Cesium.Cartesian3.add( p.velocity, gravityScratch, p.velocity ); } function computeEmitterModelMatrix() { //方向 let hpr = Cesium.HeadingPitchRoll.fromDegrees(80, 80, 80, new Cesium.HeadingPitchRoll()); var trs = new Cesium.TranslationRotationScale(); //以modelMatrix(飞机)中心为原点的坐标系的xyz轴位置偏移 trs.translation = Cesium.Cartesian3.fromElements(-30, 0, 0, new Cesium.Cartesian3()); trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, new Cesium.Quaternion()); return Cesium.Matrix4.fromTranslationRotationScale(trs, new Cesium.Matrix4()); } // 计算当前时间点飞机模型的位置矩阵 function computeModelMatrix(entity, time) { // //获取位置 let position = Cesium.Property.getValueOrUndefined(entity.position, time, new Cesium.Cartesian3()); if (!Cesium.defined(position)) { return undefined; } //获取方向 let modelMatrix; let orientation = Cesium.Property.getValueOrUndefined(entity.orientation, time, new Cesium.Quaternion()); if (!Cesium.defined(orientation)) { modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position, undefined, new Cesium.Matrix4()); } else { modelMatrix = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromQuaternion(orientation, new Cesium.Matrix3()), position, new Cesium.Matrix4()); } return modelMatrix; }

然后具体每个参数是啥意思呢,可以自行百度,或者是查看官方文档,主要就是配置成自己的样子不好整,单纯的加进去倒是挺容易的,关于粒子系统的使用百度方法博文还是蛮多的,讲的都很详细,我就不瞎逼逼赖赖了,毕竟我会的也不多,就不瞎误导别人了。

推荐两篇博文可以看一下子关于粒子系统讲解的(我就是参考他们两个大佬博文改的呀): https://blog.csdn.net/weixin_43889028/article/details/111405420 https://blog.csdn.net/UmGsoil/article/details/76542720

好了,这样的话,就有尾浪效果了,动态的哟~

在这里插入图片描述

完美,效果就比以前好了很多。 在这里插入图片描述

通过websocket实时显示船的位置

OK,到最重要,也是我做的最烂的一部分了,我不建议大家看,因为我觉得我这样有问题,但是做都做了,详细代码就不说了,分享一下思路吧就,大佬们如果有更好的还请教教我呀!

我是这样想的: 在这里插入图片描述 哦,不对,是这样考虑:

因为他每秒钟返回一个轮船信息嘛不是,所以说我websocket收到轮船消息了我就处理这个数据,这个数据包含着 轮船唯一标识符id,轮船经度、轮船纬度、轮船偏向角度。

所以说我就设置了当前的时间为时间轴的开始时间,结束时间超级超级长,就是在开始时间加上了999999999之类的,我说清楚了吧?

然后每当接收到新数据的时候,我就动态绑定最新的经纬度和时间。

let time = Cesium.JulianDate.addSeconds(start, 这是秒数, new Cesium.JulianDate); let selfPosition = Cesium.Cartesian3.fromDegrees(longitude, latitude, 0); property.addSample(time, selfPosition)

但是有一个问题哈,就是我处理逻辑需要时间嘛不是,所以说前端的时间轴可能会追上我设置的船的事实位置,所以说呢,我监听了一下时间轴的事件,如果时间轴快追上来就先暂停,等新的位置信息更新了在继续。

// 计算时间差距看是否追上,追上暂停一秒钟 这个second其实设计的是第几次发我,理论上一秒钟一次嘛不是,但是感觉有坑会 viewer.clock.onTick.addEventListener(function (clock) { let s = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, start) if (s >= second - 1) { viewer.clock.shouldAnimate = false } else { setTimeout(() => { viewer.clock.shouldAnimate = true }, 1000); } if (a


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3