前言
人生一迹,谨以此记录Cesium相关系列知识
问题背景:我的Cesium飞机和地面接收器如何建立联系?
在蔚蓝的海面上,我的经典Cesium飞机绕着美丽的宝岛飞行。绿意盎然的山川和深蓝的海峡在光照下格外耀眼。突然,机内通信设备发出连连响声,我透过窗户看到地面上的接收器正在闪烁着灯光,它们正试图与我建立一个更稳定的连接。
这些接收器是大陆上的神经末梢,它们负责监测岛屿周围的空域情况,并向空中的飞行员提供实时信息。但今天有些不同,它们似乎比平时更加迫切地想要传递某些信息。
我轻按几个按钮,调整了无线电频率,接收器的声音变得清晰起来。它们发来的不是常规导航信号,而是一串急促的代码,让我感到一丝不寻常。
"陈迹陈迹, 这里是1号地面站,你的左侧引擎数据有异常,请立即检查。" 地面控制人员的声音通过频道传来,带着一丝紧张。
我迅速抬头看向仪表盘,那里的指示灯果然亮起了警告。我的心跳随之加快,我知道我必须迅速采取行动。这场地面接收器与飞机之间的纠缠,可能才刚刚开始...
超抽象化:两个模型(A和B),两种状态(动与静)
次抽象化:动态模型A与静态模型B,动态模型A与动态模型B
具象化:卫星与地面接收器,两个飞机空中模拟加油
一、Cesium加载高德底图
二、场景定位
三、轨迹数据结构
由于书接上回,因此部分内容就不作重复叙述了,又想观看细节的移步:上一篇文章:关于实时往返轨迹线
四、动态模型A与静态模型B(飞机与地面接收器)
4.1 加载静态地面接收器模型
首先创建一个静态实体对象,即用cesium简单加载gltf模型。
// 创建一个静态实体对象
var dish_entity = viewer.entities.add({
name: 'satellite',
model: {
uri: "Data/satellite_dish.glb",
show: true,
scale: 5000,
silhouetteColor:Cesium.Color.RED,
silhouetteSize:1
},
position: Cesium.Cartesian3.fromDegrees(118.82359094,24.9452259)
});
4.2 加载动态飞机模型
也就是创建一个动态实体对象,和加载静态模型唯一的区别就是暂时不设置position的参数,后续设置完采样器之后,动态设置模型的position位置和orientation朝向。
// 创建一个动态飞机实体对象
var air_entity = viewer.entities.add({
name: 'air_model',
model: {
uri: "Data/airPlane_cesium.gltf",
show: true,
scale: 2000,
}
});
定义一个采样器对象,用于差值计算模型运行轨迹中的点。
var positionSampler = new Cesium.SampledPositionProperty();
positionSampler.setInterpolationOptions({
interpolationDegree: 2,
interpolationAlgorithm: Cesium.HermitePolynomialApproximation
});
设置初始时间和模型轨迹点位(时间信息和位置信息),注意此处的positionData里面的time是指上一个点位到本点位的时间,单位为秒。
var positionData = [
{ time: 0, longitude: 121.33830361, latitude: 25.54411517 },
{ time: 20, longitude: 119.7230824, latitude:23.027839 },
];
var start = Cesium.JulianDate.fromDate(new Date(2023, 2, 29));
遍历整个模型点位轨迹数组,将时间和点位信息添加到采样器对象中
for (var i = 0; i < positionData.length; i++) {
var data = positionData[i];
var time = new Cesium.JulianDate.addSeconds(start, data.time, new Cesium.JulianDate());
var position = new Cesium.Cartesian3.fromDegrees(data.longitude, data.latitude);
positionSampler.addSample(time, position);
}
最后一步设置飞机模型的position和orientation,设置orientation的目的是为了保证飞机模型在轨迹转弯时保证路线和模型朝向一致。
air_entity.position = positionSampler;
air_entity.orientation = new Cesium.VelocityOrientationProperty(positionSampler);
4.3 设置时间
此步骤主要是定义Cesium的时间轴相关参数,包含起始时间、终止时间和当前时间
var stop = Cesium.JulianDate.addSeconds(start, 30, new Cesium.JulianDate());
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.shouldAnimate = true;
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
viewer.clock.multiplier = 1;
五、全部代码及效果图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我的飞机绕着宝岛飞</title>
<!-- <link rel="stylesheet" href="./CesiumUnminified/Widgets/widgets.css">
<script type="text/javascript" src="./CesiumUnminified/Cesium.js"></script> -->
<link rel="stylesheet" href="./Cesium/Widgets/widgets.css">
<script type="text/javascript" src="./Cesium/Cesium.js"></script>
</head>
<body>
<div id="cesiumContainer"></div>
<script type="text/javascript">
let viewer = new Cesium.Viewer('cesiumContainer');
// 更换底图
let imageryLayers = viewer.imageryLayers;
let map = new Cesium.UrlTemplateImageryProvider({
url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}", //高德地图
minimumLevel: 3,
maximumLevel: 16,
});
imageryLayers.addImageryProvider(map); //添加地图贴图
// 场景定位
viewer.camera.flyTo({
destination : Cesium.Cartesian3.fromDegrees(121.195,21.813,738947.02),
orientation :{
heading : Cesium.Math.toRadians(355.1),
pitch : Cesium.Math.toRadians(-75.3),
roll :0.0
}
});
// 创建一个动态飞机实体对象
var air_entity = viewer.entities.add({
name: 'air_model',
model: {
uri: "Data/airPlane_cesium.gltf",
show: true,
scale: 2000,
},
});
// 创建一个静态实体对象
var dish_entity = viewer.entities.add({
name: 'satellite',
model: {
uri: "Data/satellite_dish.glb",
show: true,
scale: 5000,
silhouetteColor:Cesium.Color.RED,
silhouetteSize:1
},
position: Cesium.Cartesian3.fromDegrees(118.82359094,24.9452259)
});
// 创建一个连接线对象
var line_entity = viewer.entities.add({
name: 'line',
polyline: {
positions: new Cesium.CallbackProperty( (time) =>{
var tarpos = air_entity.position.getValue(time);
if(!tarpos) return
var cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(tarpos);
var lon = Cesium.Math.toDegrees(cartographic.longitude);
var lat = Cesium.Math.toDegrees(cartographic.latitude);
return Cesium.Cartesian3.fromDegreesArray([lon,lat,118.82359094,24.9452259])
}, false),
width: 10.0,
material: new Cesium.PolylineGlowMaterialProperty({
color: Cesium.Color.DEEPSKYBLUE,
glowPower: 0.25,
}),
}
})
// 定义一个数组,存储物体运动的时间和位置点
var positionData = [
{ time: 0, longitude: 121.33830361, latitude: 25.54411517 },
{ time: 5, longitude: 119.7230824, latitude:23.027839 },
];
// 创建一个采样器对象,用于插值计算物体运动的位置
var positionSampler = new Cesium.SampledPositionProperty();
positionSampler.setInterpolationOptions({
interpolationDegree: 2,
interpolationAlgorithm: Cesium.HermitePolynomialApproximation
});
// 起始时间
var start = Cesium.JulianDate.fromDate(new Date(2023, 2, 29));
// 遍历数组,将时间和位置点添加到采样器对象中
for (var i = 0; i < positionData.length; i++) {
var data = positionData[i];
var time = new Cesium.JulianDate.addSeconds(start, data.time, new Cesium.JulianDate());
var position = new Cesium.Cartesian3.fromDegrees(data.longitude, data.latitude);
positionSampler.addSample(time, position);
}
air_entity.position = positionSampler;
air_entity.orientation = new Cesium.VelocityOrientationProperty(positionSampler); //根据坐标转头
// 定义时钟参数,设置开始时间、结束时间和当前时间
var stop = Cesium.JulianDate.addSeconds(start, 5, new Cesium.JulianDate());
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.shouldAnimate = true;
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
viewer.clock.multiplier = 1;
</script>
</body>
</html>