Cesium应用(八):物体运动的实现思路

物体运动

  在 Cesium 三维GIS项目中,物体运动在仿真模拟,城镇/海洋数字孪生,无人机全景模拟,应急救援等业务场景中比较常见的项目需求。

业务场景

  在cesium实际开发中,根据业务需求,一般分为两种情况,以无人机为例:一种是根据无人机的实时飞行同步在cesium场景中,通常还有无人机视频回传,关键帧识别等功能;一种是历史轨迹回放,即无人机飞过的路径再次在cesium场景中显示。

实时点位驱动

  这里需要拿到无人机飞行时的接口,或者通过无人机回传时视频进行识别来获取无人机的飞行姿态和位置信息。实现步骤如下:

  1. 需要通过长链接websocket实时获取到无人机的飞行姿态,位置信息,监控视频等;
  2. 通过pinia/vuex建立一个飞行姿态数据缓冲区,用来实时存储websocket回传的数据,根据回传的数据计算出无人机的位置和控制模型朝向的四元数,
  3. 使用requestAnimationFrame动画帧来驱动无人机不断地更新位置和四元数,以达到无人机实时点位驱动。 伪代码如下:
js 复制代码
// 1、模拟websocket飞行姿态,位置信息,提交到pinia中
const submitFlightAttitude = (dt) => {
    const temp = flightParams.speed / 60 / 60 / 60 / 110
    flightParams.longitude += temp * Math.cos(flightParams.heading)
    flightParams.latitude -= temp * Math.sin(flightParams.heading)
    const { longitude, latitude, height, heading, pitch, roll } = flightParams
    if (height <= 120 && height >= 5) {
        flightParams.height += temp * Math.sin(pitch) * 110 * 1000 * 10
    } else {
        if (height > 120) flightParams.height = 120
        if (height < 5) flightParams.height = 5
    }
    const position = cesium.Cartesian3.fromDegrees(longitude, latitude, height)
    const hpr = new cesium.HeadingPitchRoll(heading, pitch, roll)
    const orientation = cesium.Transforms.headingPitchRollQuaternion(
        position,
        hpr
    )
    droneStore.setDroneFilghtParams({ position, orientation })
}
// 2、这里未做缓冲区处理,直接存储当前的无人机信息
import { reactive } from 'vue'
const droneFlight = reactive({
    position: null,
    orientation: null
})

export const useDroneFilght = () => {
    const setDroneFilghtParams = (val) => {        
        droneFlight.position = val.position
        droneFlight.orientation = val.orientation
    }
    
    return {
        droneFlight,
        setDroneFilghtParams
    };
}

export const droneFilghtStoreHook = () => {
    return useDroneFilght();
}
// 3、动画帧驱动无人机位置和姿态更新
const render = () => {
    model.position = droneStore.droneFlight.position
    model.orientation = droneStore.droneFlight.orientation
    requestAnimationFrameId = requestAnimationFrame(render)
}

时序轨迹回放

  首先轨迹回放意味着飞行的数据已经存储在数据库中了,包括具体的飞行时间,飞行路径的关键点等,在cesium中有很多方式可以实现,包括callbackProperty,SampledPositionProperty、requestAnimationFrame等来实现。这里使用SampledPositionProperty以时间进行插值来实现。实现步骤如下:

  1. 打开cesium初始时timeline部件,并使用css样式进行隐藏,以免影响到整体页面的美观。
  2. 以飞行时间来初始化开始时刻和结束时刻,并将该时间段赋值给时钟,或者以实际开始时刻和结束时刻进行赋值,设置时间倍率,来控制演示时间,最后将时钟聚焦到该飞行时间。
  3. 通过SampledPositionProperty使用时间进行计算出无人机飞行的路径。
  4. 时间计算出的路径,使用VelocityOrientationProperty自动计算出飞行姿态 伪代码如下:
js 复制代码
// 1、初始化时间轴
    timeline: true,  // 时间轴控件(底部时间进度条)
    viewer.timeline.container.style.display = "none";
// 2、时间初始化赋值
    const startTime = cesium.JulianDate.fromDate(new Date());
    const stopTime = cesium.JulianDate.addSeconds(startTime, TOTAL_FLIGHT_SECONDS, new cesium.JulianDate());
    viewer.clock.startTime = startTime.clone();
    viewer.clock.stopTime = stopTime.clone();
    viewer.clock.multiplier = 1;
    viewer.clock.clockRange = cesium.ClockRange.LOOP_STOP;
    viewer.timeline.zoomTo(startTime, stopTime);
// 3、时间插值计算
    const interval = TOTAL_FLIGHT_SECONDS / (path.length - 1);
    let positionProperty = new cesium.SampledPositionProperty();
    for (let i = 0; i < path.length; i++) {
        const time = cesium.JulianDate.addSeconds(startTime, i * interval, new cesium.JulianDate());
        const position = cesium.Cartesian3.fromDegrees(path[i].longitude, path[i].latitude, path[i].height);
        positionProperty.addSample(time, position);

    }
    positionProperty.setInterpolationOptions({
        interpolationDegree: 2,
        interpolationAlgorithm: cesium.HermitePolynomialApproximation
    });
    return positionProperty;
}
// 4、模型加载,自动计算飞行姿态
 model = viewer.entities.add({
        name: 'drone',
        availability: new cesium.TimeIntervalCollection([
            new cesium.TimeInterval({
                start: startTime,
                stop: stopTime,
            }),
        ]),
        orientation: new cesium.VelocityOrientationProperty(position),
        position: position,
        model: {
            uri: url,
            minimumPixelSize: 36,
            maximumScale: 128,
            runAnimations: true,
        },
    })

总结:

  本文主要介绍了 Cesium 三维场景中物体运动的两种实现方式。实时点位驱动方式通过 WebSocket 实时获取无人机姿态与位置数据,结合状态管理和动画帧实时更新模型位置与四元数,实现实时飞行态势展示。时序轨迹回放基于历史飞行数据,利用 Cesium 时间轴与插值属性生成平滑飞行路径,并自动匹配运动姿态,完成无人机历史轨迹的仿真回放。

实现效果:

相关推荐
用户41659673693551 小时前
Android WebView 加载 file:// 离线页面调试教程
android·前端
Asmewill1 小时前
curl命令学习笔记一
前端
我是一只快乐的小螃蟹1 小时前
1.2 ArrayList 源码解析
前端
星栈1 小时前
我用 Rust + Dioxus 做了个全栈跨平台笔记应用:再把新建、编辑和交付补上
前端·rust·前端框架
我是一只快乐的小螃蟹1 小时前
1.1 HashMap (JDK1.8) 源码解析
前端
爱勇宝4 小时前
小红花成长新版:模板来了,鼓励也更容易开始
前端·后端·程序员
竹林8184 小时前
Solana前端开发:我在一个NFT铸造页面上被@solana/web3.js的Connection和Transaction签名坑了两天
前端
冬奇Lab5 小时前
每日一个开源项目(第144篇):ai-website-cloner-template - 一条命令、多 Agent 并行,把任意网站逆向成 Next.js 代码
前端·人工智能·开源
玄玄子5 小时前
webpack publicPath作用原理
前端·webpack·程序员