目录
实现效果
三维地图Cesium,加载一个模型,模型沿着给定的一组经纬度
实现思路
- 车的运行使用czml文件的特性来加载小车模型和小车运行的固定路线,同时定义它们是怎么随时间的变化而变化的。
- 路径长度已知,运行速度已知,结合三维cesium的时钟,就可以知道火车移动完成这段路线需要的时间。
- 改变运行速度或改变当前移动的位置(经纬度点)发生变化,就重新计算时间,然后重新加载czml文件。
功能点
目前已经实现的功能:
1、加载指定可自定义火车模型
2、移动的路线可以自定义修改,也可以在地图上自己选择移动路线(取路线代码已有)
3、给定指定的移动速度
4、视角切换(第一视角、自由视角、跟随视角)
5、根据指定的经纬度点为起点开始移动
6、停止移动、开始移动、到站提示、从起点重新移动、默认相机的视角
7、根据实际业务,接口获取获取的速度、移动路线、车的状态(前进、静止、后退)来控制模型的状态
选择移动路线
1、方法:at3DMapGetPointTakingRoute()
2、初始化成功后,执行at3DMapGetPointTakingRoute函数
TO.at3DMapGetPointTakingRoute()
3、 打开页面,用鼠标点击需要的路线,页面会以红点的样式进行标注,每标注一个点,控制台会以数组的形式打印所有标注的点
4、 把打印数据赋值给routePath变化,完成了路线的数据采集
// 路线
export const routePath = [
[116.44411704836098,39.95279202225133],[116.44807033296253,39.956431604742875],
[116.45386442263022,39.952900124343756],[116.45546340934312,39.951275636111355],
[116.45567209160625,39.9494096918938],[116.4556296095857,39.94616403625391],
]
加载模型和移动路线
加载模型和路线的方式有好几种:
1)使用实体单独加载模型和移动路线
2)使用czml格式描述它们两个的关系
我们这里采用第二种,之前打算用第一种,加载起来是很方便,但是需要计算模型与移动路线的关系等细节,就先不打算了。。。
具体如何使用czml文件描述模型和移动路线的关系,网上有很多,可以自行查阅。
let testModel = window.location.origin + '/Apps/SampleData/models/GroundVehicle/GroundVehicle.glb';
export function modelCzml(useRoutePath,startTime,endTime){
let minx = startTime+'/'+endTime;
return [
{
"id": "document",
"version": "1.0"
},
{
"id": "Vehicle",
"availability": minx ,
"label": {
"fillColor": [
{
"rgba": [0, 0, 0, 255]
}
],
"font": "bold 10pt Segoe UI Semibold",
"horizontalOrigin": "CENTER",
"outlineColor": {
"rgba": [0, 0, 0, 255]
},
"pixelOffset": {
"cartesian2": [40.0, 50.0]
},
"scale": 1.0,
"show": [
{
"boolean": true
}
],
"style": "FILL",
"text": "测试火车移动",
"verticalOrigin": "CENTER"
},
"model": {
"gltf": testModel,
"minimumPixelSize": 120,
"maximumScale": 50
},
"orientation": {
"velocityReference": "#position"
},
"viewFrom": {
// "cartesian": [300, 20, 300]
"cartesian": [500, 2000, 779]
},
"properties": {
"fuel_remaining": {
"epoch": startTime,
"number": [0, 22.5, 1500, 21.2]
}
},
"path": {
"material": {
"solidColor": {
"color": {
"rgba": [255, 255, 0, 255]
}
}
},
"width": [
{
"number": 4.0
}
],
"show": [
{
"boolean": true
}
]
},
"position": {
"interpolationAlgorithm": "LAGRANGE",
"interpolationDegree": 1,
"wrap": false,
"epoch": startTime,
"cartographicDegrees": useRoutePath
// useRoutePath:时间、经度、纬度、高度加载显示的格式为[0, 102.23404378554466, 27.825736605050523, 2500,10, 102.23691954070244, 27.82887625908256, 2500,]
}
}
]
}
重新运行
1、使用trainLoadRun()函数
2、该方法接收三个参数:
1)targetPoint:起点的经纬度,也就是路线起点
2)currentVelocity:移动速度
3)tractionMethod:火车移动状态(前进 后退 静止)
trainLoadRun(targetPoint,currentVelocity=this.currentVelocity,tractionMethod=this.tractionMethod){
// 如果当前火车是后退,判断当前火车是否在运行路线上,如果在,则找到当前火车所在点,并反转火车路线数组
let that = this;
if (that.latAndLonPosition(targetPoint).exists) {
let index = that.latAndLonPosition(targetPoint).index
that.byLonAndLatUpdateTrainPosition(index, currentVelocity, tractionMethod)
} else {
console.error('当前经纬度不在轨迹运行路线上:',targetPoint)
}
}
指定位置(经纬度点)开始移动
也是用targetPoint方法,改变下targetPoint的位置
注意:给的经纬度点要是不在移动路线上是不做处理的
视角切换
1、第一视角
1)相机一直在相对小车指定的位置
2)该模式无法通过鼠标或者键盘操作地图视角
3)路线方向变化,车的头部以及方向也随着变化
firstPerspectiveTow() {
let that = this;
try {
let center = that.trainModel.position.getValue(
that.viewer.clock.currentTime
);
let orientation = that.trainModel.orientation.getValue(
that.viewer.clock.currentTime
)
let transform = that.Cesium.Matrix4.fromRotationTranslation(that.Cesium.Matrix3.fromQuaternion(orientation), center);
// viewer.camera.lookAtTransform(transform, new Cesium.Cartesian3(-100, 0, 50))
that.viewer.camera.lookAtTransform(transform, new that.Cesium.Cartesian3(-60, 0, 50))
} catch (e) {
console.log('err in firstPerspectiveTow function')
}
}
2、自由视角
1)将viewer.trackedEntity的值为:undefined即可
viewer.trackedEntity = undefined;
3、跟随视角
viewer.trackedEntity = trainOpera.trainModel;
到站提示
根据当前已经移动的距离与总路线的距离作比较,总路线减去已经移动的路线,误差值在10米为到站,当然,这个误差值可以自己定义
arriveAtStation(clock,callBack){
let that = this;
let cDistance = that.walkedThrough();
let diff = Math.abs(that.fullRoutePathDistance.total - cDistance);
if (that.tractionMethod == '后退'){
diff = that.fullRoutePathDistance.total - diff
}
if (diff < 9){
// 可以在这里分发到站广播
callBack && callBack();
clock.shouldAnimate = false;
that.arriveAatStation()
}
}
运行
停止
设置时钟的shouldAnimate为false即可
clock.shouldAnimate = false;
联动接口
或者的运行速度,运行状态(前进、静止、后退)等信息,通过接口的形式可以进行控制
接口数据更新的时间根据自己的事迹情况来定
如:获取接口数据的方法
// 通过接口实时获取火车运行的相关信息
getTrainInfo() {
let that = this;
let res = {currentlonLat:'112.938333,40.332444',tractionMethod:'前进',speed:23}; //火车当前前进方式,3种状态:前进 后退 静止
if (!res || res === '{}') return false;
let currentSpeed;
if (res.speed && res.speed.includes('km/h')){
currentSpeed = res.speed.split('km/h')[0] //火车运行速度
}
// 获取当前火车所在经纬度
let targetPoint;
if (res.currentlonLat){
let point = res.currentlonLat.split(',');
targetPoint = {lon: point[0],lat: point[1]}
} else {
console.log('经纬度坐标丢失');
return false;
}
if (res.tractionMethod == '静止' || currentSpeed == '0'){
that.tractionMethod = res.tractionMethod;
that.viewer.clock.shouldAnimate = false;
return false;
}
// 如果页面火车已经到了,但是接口没有返回"静止"状态,前端做停止运行动作
if (window.isEmit && res.tractionMethod != '静止'){
window.TO.viewer.clock.shouldAnimate = false;
return false;
} else {
window.isEmit = false;
}
that.viewer.clock.shouldAnimate = true;
// 运行状态不一样,要重新计算