简介
使用Cesium
与前后端实时通信技术(WebSocket等)实现实时轨迹效果,适用于船舶/飞机
实时位置显示,轨迹追踪。
效果截图
实现-mars3d
在使用mars3d SDK
时,实现的方式比较简单,有以下几种实例对象都支持添加动态位置:
- BasePointEntity/BasePointPrimitive
- BillboardEntity/BillboardPrimitive
- PointEntity/PointPrimitive
- ModelEntity/ModelPrimitive
- LabelEntity/LabelPrimitive
- Route
仅LabelPrimitive、PointPrimitive、BillboardPrimitive、ModelPrimitive 等部分子类支持
/**
* 添加动态位置
* @param point LngLatPoint | Cesium.Cartesian3 | Array.<number>
* @param currTime Cesium.JulianDate | Date | string | number
*/
graphic.addDynamicPosition(point, currTime)
实现 cesium AIGXGPT:
每次更新时,点的位置是直接设置的,所以点会“闪到”新位置,而不是平滑地移动到新位置。如果你想要点平滑地移动到新位置,可以使用 Cesium 的 SampledPositionProperty
来实现平滑的动画效果。下面是如何修改代码来实现平滑移动的示例:
1. 使用 SampledPositionProperty
实现平滑移动
SampledPositionProperty
允许你为实体设置一系列的时间和位置,从而使实体在这些位置之间平滑过渡。
示例代码
import Cesium from 'cesium/Cesium';
import 'cesium/Widgets/widgets.css';
// 创建 Cesium 视图
const viewer = new Cesium.Viewer('cesiumContainer');
// 创建一个空的 CZML 数据源
const czmlDataSource = new Cesium.CzmlDataSource();
viewer.dataSources.add(czmlDataSource);
// 创建一个空的实体集合
const entities = {};
// 初始化 WebSocket 连接
const socket = new WebSocket('wss://your-websocket-server');
// 监听 WebSocket 消息
socket.onmessage = function(event) {
// 解析接收到的消息
const data = JSON.parse(event.data);
// 解析位置信息和时间信息
const { id, position, time } = data;
// 确保 ID 对应的实体存在
let entity = entities[id];
if (!entity) {
// 创建新的实体,并初始化位置属性为 SampledPositionProperty
const positionProperty = new Cesium.SampledPositionProperty();
entity = czmlDataSource.entities.add({
id: id,
position: positionProperty,
point: {
pixelSize: 10,
color: Cesium.Color.RED
}
});
entities[id] = entity;
}
// 更新 SampledPositionProperty
const positionProperty = entity.position;
const julianDate = Cesium.JulianDate.fromIso8601(time);
positionProperty.addSample(julianDate, Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude));
};
说明
SampledPositionProperty
:创建一个SampledPositionProperty
实例来存储时间和位置数据。每当接收到新数据时,就将新的位置和时间添加到这个属性中。平滑过渡:Cesium 会自动平滑地插值这些位置数据,使得点在更新过程中看起来是平滑移动的,而不是突然跳转到新位置。
添加样本:使用
positionProperty.addSample(time, position)
方法将新的位置数据添加到SampledPositionProperty
中,其中time
是JulianDate
对象,position
是Cartesian3
坐标。
注意事项
- 时间间隔:确保你添加的位置样本有合适的时间间隔,以确保动画平滑。频繁的更新可能会导致动画卡顿或不流畅。
- 性能:实时更新和动画可能会对性能产生影响,特别是在处理大量数据时。优化数据传输和处理逻辑可以改善性能。
通过这种方法,你可以实现点在 Cesium 中的平滑移动效果,使得点在更新时不会突然跳跃,而是平滑地过渡到新位置。
实现 cesium ChatGPT:
为了让 Cesium.Entity
模型的移动更加流畅,你可以使用 插值 方法,使模型的位置更新更加平滑。Cesium 提供了一个强大的工具来处理时间动态性的可视化——SampledPositionProperty
,它可以根据时间进行插值,从而实现更自然的过渡效果。
如何使用 SampledPositionProperty
来流畅移动模型?
SampledPositionProperty
允许你为 Entity
设置随时间变化的位置信息,并且 Cesium 会在位置之间进行插值,使移动更加平滑。你可以通过这种方式让模型在多个时间点之间以平滑的方式移动,而不是每次突然跳到新位置。
实现步骤:
- 使用
SampledPositionProperty
来代替直接更新modelEntity.position
。 - 随着新的位置信息到达,将它们添加到
SampledPositionProperty
,Cesium 会自动进行插值。 - 调整 Cesium 的
Clock
以确保时间和模型的移动同步。
示例代码:
import { useEffect } from "react";
import * as Cesium from "cesium";
import "cesium/Build/Cesium/Widgets/widgets.css";
export const CesiumPage = () => {
Cesium.Ion.defaultAccessToken =
"your-cesium-access-token-here"; // 请替换为你的 Cesium 令牌
useEffect(() => {
// 初始化 Cesium
const viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
selectionIndicator: false,
});
// 创建一个 SampledPositionProperty 来存储并插值位置
const positionProperty = new Cesium.SampledPositionProperty();
// 添加初始位置
const initialTime = Cesium.JulianDate.now();
const initialPosition = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 100);
positionProperty.addSample(initialTime, initialPosition);
// 创建一个 Entity 并加载 glb 模型
const modelEntity = viewer.entities.add({
name: "Dynamic Model",
position: positionProperty,
model: {
uri: "path/to/your/model.glb", // 替换为你的 glb 模型路径
minimumPixelSize: 64,
maximumScale: 200,
},
});
// 设置 Cesium 的时间控件,让模型的移动基于时间更新
viewer.clock.shouldAnimate = true; // 启动时钟动画
viewer.clock.multiplier = 1; // 时间推进速度(1 表示实时)
// 聚焦到模型的初始位置
viewer.zoomTo(modelEntity);
// 模拟实时更新位置信息
const updatePosition = () => {
setInterval(() => {
// 当前时间
const currentTime = Cesium.JulianDate.now();
// 生成新的经纬度和高度(模拟接收实时数据)
const newLongitude = -75.59777 + Math.random() * 0.01;
const newLatitude = 40.03883 + Math.random() * 0.01;
const newHeight = 100 + Math.random() * 10;
// 创建新的位置点
const newPosition = Cesium.Cartesian3.fromDegrees(newLongitude, newLatitude, newHeight);
// 将新的位置点和当前时间添加到位置属性中,Cesium 会自动进行插值
positionProperty.addSample(currentTime, newPosition);
}, 1000); // 每秒更新一次位置
};
updatePosition();
// 清理 Cesium Viewer
return () => {
if (viewer) {
viewer.destroy();
}
};
}, []);
return <div id="cesiumContainer" style={{ height: "100vh", width: "100%" }} />;
};
关键点解释:
SampledPositionProperty
:SampledPositionProperty
用来记录模型的位置,并根据时间来进行插值,使得模型的运动更加流畅。- 我们使用
addSample
方法为不同的时间点提供位置,Cesium 会在这些位置之间自动进行平滑的插值过渡。
实时更新位置:
- 通过
setInterval
模拟实时接收位置数据,并在每次接收到新位置时,将时间和位置点传给SampledPositionProperty
。 - 这样,模型不会直接跳到新位置,而是根据时间平滑移动。
- 通过
Cesium 的时间机制:
viewer.clock.shouldAnimate = true
启动了 Cesium 的时钟机制,确保模型根据时间变化移动。- 通过
viewer.clock.multiplier
控制时间的推进速度。你可以调整 multiplier 的值让时间加速或减速。
更自然的效果:
- 通过这种方式,模型会基于连续的时间和位置变化自动插值,移动过程看起来非常平滑,而不是突然跳跃到新位置。
优点:
- 平滑插值:
SampledPositionProperty
提供了平滑的插值,使得模型移动看起来更加自然。 - 时间控制:可以灵活控制模型在不同时间点的行为,尤其适合模拟实时跟踪或预测未来轨迹。
- 易于集成:你可以通过 API、WebSocket 或其他数据源来不断添加新的位置信息。
适用场景:
- 实时跟踪物体,比如无人机、车辆、船只等。
- 需要平滑移动而非突兀跳跃的场景。
- 基于时间动态的可视化,比如历史轨迹回放或未来位置预测。
通过这种方式,你可以在 Cesium 中实现流畅且自然的模型移动,特别适合动态数据的可视化。