【cesium入门】系列是将CesiumJS官网教程文章翻译为中文,并且提供Vue3版本的代码GitHub - cesiumjs教程的vue3版本 。希望这个系列可以帮助你更好的学习cesium。
前言
本教程向您展示如何使用离散点数据(FlightRadar24收集的雷达数据),可视化从旧金山到哥本哈根的真实航班的飞行路线。
压缩成20m的gif,在帧率和分辨率上都有很大的降低,gif看起来流畅度和清晰度不够
您将学习如何:
- 添加全球 3D 建筑物、地形和图像的基础图层。
- 根据一段时间内的位置信息准确地可视化飞机飞行路线和状态。
“开始前”和“Step1: 创建Cesium应用”可参考【Cesium 入门】快速开始或者【Cesium 入门】在3D城市中可视化一个拟建的建筑,在这里就不详细列出了。
Step1: 可视化单个样本
FlightRadar24使用包括雷达在内的多种方法跟踪空中交通。数据样本是json格式。
[{"longitude":-122.39053,"latitude":37.61779,"height":-27.32},
{"longitude":-122.39035,"latitude":37.61803,"height":-27.32},
{"longitude":-122.39019,"latitude":37.61826,"height":-27.32},
{"longitude":-122.39006,"latitude":37.6185,"height":-27.32},
{"longitude":-122.38985,"latitude":37.61864,"height":-27.32},
{"longitude":-122.39005,"latitude":37.61874,"height":-27.32},
{"longitude":-122.39027,"latitude":37.61884,"height":-27.32},
{"longitude":-122.39057,"latitude":37.61898,"height":-27.32},
{"longitude":-122.39091,"latitude":37.61912,"height":-27.32},
{"longitude":-122.39121,"latitude":37.61926,"height":-27.32},
{"longitude":-122.39153,"latitude":37.61937,"height":-27.32},
{"longitude":-122.39175,"latitude":37.61948,"height":-27.32},
...]
先可视化单个样本:
1添加下面的代码以可视化场景中的单个点,并将相机飞到该点。
2单击红色点以查看其附带的描述。此描述可用于附加信息,如每个点的确切位置或捕获时间。
// STEP 3 CODE (first point)
// This is one of the first radar samples collected for our flight.
const dataPoint = { longitude: -122.38985, latitude: 37.61864, height: -27.32 };
// Mark this location with a red point.
const pointEntity = viewer.entities.add({
description: `First data point at (${dataPoint.longitude}, ${dataPoint.latitude})`,
position: Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height),
point: { pixelSize: 10, color: Cesium.Color.RED }
});
// Fly the camera to this point.
viewer.flyTo(pointEntity);
Step2: 可视化飞行路线
原教程中直接将雷达数据复制到代码中,这样会导致代码很长,通过fetch接口导入json,可视化整个雷达样本系列,请将上面的代码(步骤3)替换为以下代码段
# Utils文件编写公共方法
export const fetchLocalJson = async (path) => {
try {
const response = await fetch(path);
if (!response.ok) {
throw new Error('Network response was not ok ' + response.statusText);
}
let value = await response.json();
return value
} catch (error) {
console.error('Fetch error:', error);
}
};
# 替换上面可视化单个样本代码
flightData = await fetchLocalJson('/flight.json')
// STEP 3 CODE (all points)
// These are all the radar points from this flight.
// Create a point for each.
for (let i = 0; i < flightData.length; i++) {
const dataPoint = flightData[i];
viewer.entities.add({
description: `Location: (${dataPoint.longitude}, ${dataPoint.latitude}, ${dataPoint.height})`,
position: Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height),
point: { pixelSize: 10, color: Cesium.Color.RED }
});
}
现在你可以看到全系列的飞机雷达样本,从登机口到跑道,一直到降落在哥本哈根的跑道上!
Step3: 可视化随时间变化的运动
到目前为止,我们已经可视化了各个雷达样本。CesiumJS内置支持在一段时间内收集的样本之间进行插值,这样我们就可以看到飞机在任何给定时刻的位置。
我们将创建一个SampledPositionProperty来存储每个位置以及时间戳。源数据不包括每个样本的时间戳,但我们知道航班号是SK936,计划于2020年3月9日太平洋标准时间下午4:10起飞。我们假设位置样本间隔30秒采集。
注: SampledPositionProperty中时间是JulianDate对象,位置是Cartesian3对象(三维笛卡尔坐标)
JulianDate {
"dayNumber": 2458918,
"secondsOfDay": 58687
}
Cartesian3 {
"x": 3521815.3233993687,
"y": 790336.7870177948,
"z": 5241013.037260981
}
// 单个样本的SampledPositionProperty
let positionProperty = new Cesium.SampledPositionProperty();
const time = Cesium.JulianDate.addSeconds(start, i * timeStepInSeconds, new Cesium.JulianDate());
const position = Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height);
// Store the position along with its timestamp.
// Here we add the positions all upfront, but these can be added at run-time as samples are received from a server.
positionProperty.addSample(time, position);
探索动画飞行:
- 使用左下角的按钮播放并暂停动画。
- 在底部的时间轴中单击并拖动以跳过场景时间。
- 双击地面上的任意位置以将摄影机与移动实体分离。
跨大西洋飞行就是一个很好的例子,说明3D可视化如何使数据更容易解释。事实上,连接雷达样本的线大多是直的。在2D地图上,当使用常见的web mercator投影时,它会显得弯曲:
async function movementOvertime (type) {
if (!flightData) {
flightData = await fetchLocalJson('/flight.json')
}
/* Initialize the viewer clock:
Assume the radar samples are 30 seconds apart, and calculate the entire flight duration based on that assumption.
Get the start and stop date times of the flight, where the start is the known flight departure time (converted from PST
to UTC) and the stop is the start plus the calculated duration. (Note that Cesium uses Julian dates. See
https://simple.wikipedia.org/wiki/Julian_day.)
Initialize the viewer's clock by setting its start and stop to the flight start and stop times we just calculated.
Also, set the viewer's current time to the start time and take the user to that time.
*/
const timeStepInSeconds = 30;
const totalSeconds = timeStepInSeconds * (flightData.length - 1);
start = Cesium.JulianDate.fromIso8601("2020-03-09T23:10:00Z");
stop = Cesium.JulianDate.addSeconds(start, totalSeconds, new Cesium.JulianDate());
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.timeline.zoomTo(start, stop);
// Speed up the playback speed 50x.
viewer.clock.multiplier = 50;
// Start playing the scene.
viewer.clock.shouldAnimate = true;
// The SampledPositionedProperty stores the position and timestamp for each sample along the radar sample series.
positionProperty = new Cesium.SampledPositionProperty();
for (let i = 0; i < flightData.length; i++) {
const dataPoint = flightData[i];
// Declare the time for this individual sample and store it in a new JulianDate instance.
const time = Cesium.JulianDate.addSeconds(start, i * timeStepInSeconds, new Cesium.JulianDate());
const position = Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height);
// Store the position along with its timestamp.
// Here we add the positions all upfront, but these can be added at run-time as samples are received from a server.
positionProperty.addSample(time, position);
}
// STEP 4 CODE (green circle entity)
// Create an entity to both visualize the entire radar sample series with a line and add a point that moves along the samples.
let model = null
if (type === 'greenPoint') {
model = {
availability: new Cesium.TimeIntervalCollection([ new Cesium.TimeInterval({ start: start, stop: stop }) ]),
position: positionProperty,
point: { pixelSize: 30, color: Cesium.Color.GREEN },
path: new Cesium.PathGraphics({ width: 3 })
}
} else {
model = loadAirModel()
}
const airplaneEntity = viewer.entities.add(model);
// Make the camera track this moving entity.
viewer.trackedEntity = airplaneEntity;
}
movementOvertime('greenPoint')
Step4: 附上飞机模型
作为最后一步,我们将把飞机的 3D 模型而不是绿点附加到我们的实体上。
下载飞机模型,使用飞机模型
// STEP 6 CODE (airplane entity)
function loadAirModel() {
// Load the glTF model from Cesium ion.
const airplaneModelUrl = '/Cesium_Air.glb'
return {
availability: new Cesium.TimeIntervalCollection([ new Cesium.TimeInterval({ start: start, stop: stop }) ]),
position: positionProperty,
// Attach the 3D model instead of the green point.
model: { uri: airplaneModelUrl, minimumPixelSize: 100 },
// Automatically compute the orientation from the position.
orientation: new Cesium.VelocityOrientationProperty(positionProperty),
path: new Cesium.PathGraphics({ width: 3 })
}
}
动画效果可参考文章开头的gif
到这里飞行路线展示基本就结束啦
源码可从_GitHub - cesiumjs教程的vue3版本_下载
如果文章对你有帮助,希望可以收获你的点赞收藏加关注,我会持续带来更多有价值的内容!