Skip to content

简介

使用Cesium与前后端实时通信技术(WebSocket等)实现实时轨迹效果,适用于船舶/飞机实时位置显示,轨迹追踪。

效果截图

实现-mars3d

在使用mars3d SDK时,实现的方式比较简单,有以下几种实例对象都支持添加动态位置:

  • BasePointEntity/BasePointPrimitive
  • BillboardEntity/BillboardPrimitive
  • PointEntity/PointPrimitive
  • ModelEntity/ModelPrimitive
  • LabelEntity/LabelPrimitive
  • Route

仅LabelPrimitive、PointPrimitive、BillboardPrimitive、ModelPrimitive 等部分子类支持

js
/**
 * 添加动态位置
 * @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 允许你为实体设置一系列的时间和位置,从而使实体在这些位置之间平滑过渡。

示例代码

javascript
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));
};

说明

  1. SampledPositionProperty:创建一个 SampledPositionProperty 实例来存储时间和位置数据。每当接收到新数据时,就将新的位置和时间添加到这个属性中。

  2. 平滑过渡:Cesium 会自动平滑地插值这些位置数据,使得点在更新过程中看起来是平滑移动的,而不是突然跳转到新位置。

  3. 添加样本:使用 positionProperty.addSample(time, position) 方法将新的位置数据添加到 SampledPositionProperty 中,其中 timeJulianDate 对象,positionCartesian3 坐标。

注意事项

  • 时间间隔:确保你添加的位置样本有合适的时间间隔,以确保动画平滑。频繁的更新可能会导致动画卡顿或不流畅。
  • 性能:实时更新和动画可能会对性能产生影响,特别是在处理大量数据时。优化数据传输和处理逻辑可以改善性能。

通过这种方法,你可以实现点在 Cesium 中的平滑移动效果,使得点在更新时不会突然跳跃,而是平滑地过渡到新位置。

实现 cesium ChatGPT:

为了让 Cesium.Entity 模型的移动更加流畅,你可以使用 插值 方法,使模型的位置更新更加平滑。Cesium 提供了一个强大的工具来处理时间动态性的可视化——SampledPositionProperty,它可以根据时间进行插值,从而实现更自然的过渡效果。

如何使用 SampledPositionProperty 来流畅移动模型?

SampledPositionProperty 允许你为 Entity 设置随时间变化的位置信息,并且 Cesium 会在位置之间进行插值,使移动更加平滑。你可以通过这种方式让模型在多个时间点之间以平滑的方式移动,而不是每次突然跳到新位置。

实现步骤:

  1. 使用 SampledPositionProperty 来代替直接更新 modelEntity.position
  2. 随着新的位置信息到达,将它们添加到 SampledPositionProperty,Cesium 会自动进行插值。
  3. 调整 Cesium 的 Clock 以确保时间和模型的移动同步。

示例代码:

javascript
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%" }} />;
};

关键点解释:

  1. SampledPositionProperty

    • SampledPositionProperty 用来记录模型的位置,并根据时间来进行插值,使得模型的运动更加流畅。
    • 我们使用 addSample 方法为不同的时间点提供位置,Cesium 会在这些位置之间自动进行平滑的插值过渡。
  2. 实时更新位置

    • 通过 setInterval 模拟实时接收位置数据,并在每次接收到新位置时,将时间和位置点传给 SampledPositionProperty
    • 这样,模型不会直接跳到新位置,而是根据时间平滑移动。
  3. Cesium 的时间机制

    • viewer.clock.shouldAnimate = true 启动了 Cesium 的时钟机制,确保模型根据时间变化移动。
    • 通过 viewer.clock.multiplier 控制时间的推进速度。你可以调整 multiplier 的值让时间加速或减速。
  4. 更自然的效果

    • 通过这种方式,模型会基于连续的时间和位置变化自动插值,移动过程看起来非常平滑,而不是突然跳跃到新位置。

优点:

  • 平滑插值SampledPositionProperty 提供了平滑的插值,使得模型移动看起来更加自然。
  • 时间控制:可以灵活控制模型在不同时间点的行为,尤其适合模拟实时跟踪或预测未来轨迹。
  • 易于集成:你可以通过 API、WebSocket 或其他数据源来不断添加新的位置信息。

适用场景:

  • 实时跟踪物体,比如无人机、车辆、船只等。
  • 需要平滑移动而非突兀跳跃的场景。
  • 基于时间动态的可视化,比如历史轨迹回放或未来位置预测。

通过这种方式,你可以在 Cesium 中实现流畅且自然的模型移动,特别适合动态数据的可视化。