首页 > 其他分享 >Cesium 根据飞机航线计算飞机的Heading(偏航角)、Pitch(俯仰角)、Roll(翻滚角)

Cesium 根据飞机航线计算飞机的Heading(偏航角)、Pitch(俯仰角)、Roll(翻滚角)

时间:2024-04-02 12:22:37浏览次数:24  
标签:pitch heading let Pitch Cesium targetPosition Roll pos1

需求

设置飞机的一些坐标位置(经纬度高度),插值得到更多的坐标位置,然后飞机按照这些坐标集合形成的航线飞行,飞机的朝向、俯仰角以及飞机转弯时的翻转角根据坐标集合计算得出,而不需要手动设置heading、pitch、roll。

坐标插值

不知道为什么,可能是飞行速度变化太大,我用Cesium自带的插值,计算出的航线很奇怪

// 如下代码插值计算出的航线有问题
property.setInterpolationOptions({ 
    interpolationDegree : 5, 
    interpolationAlgorithm : Cesium.LagrangePolynomialApproximation 
}); 

自己写的插值计算,效果等同于Cesium自带的线性插值:

/**
 * 重新采样this.DronePositions
 */
DetectsDrones.prototype.sameple = function () {
    for (let i = 0; i < 3; i++) {
        this.samepleOnce();
    }
}

/**
 * 重新采样this.DronePositions
 */
DetectsDrones.prototype.samepleOnce = function () {
    for (let i = 0; i < this.DronePositions.length - 1; i += 2) {
        let pos1 = this.DronePositions[i];
        let pos2 = this.DronePositions[i + 1];
        let time1 = dayjs(pos1.time, 'YYYY-MM-DD HH:mm:ss');
        let time2 = dayjs(pos2.time, 'YYYY-MM-DD HH:mm:ss');
        let time = time1.add(time2.diff(time1) / 2.0, 'millisecond');
        let lng = (pos1.targetPosition.lng + pos2.targetPosition.lng) / 2.0;
        let lat = (pos1.targetPosition.lat + pos2.targetPosition.lat) / 2.0;
        let height = (pos1.targetPosition.height + pos2.targetPosition.height) / 2.0;
        let heading = (pos1.targetPosition.heading + pos2.targetPosition.heading) / 2.0;
        let pitch = (pos1.targetPosition.pitch + pos2.targetPosition.pitch) / 2.0;
        let roll = (pos1.targetPosition.roll + pos2.targetPosition.roll) / 2.0;
        let pos = {
            time: time.format('YYYY-MM-DD HH:mm:ss.SSS'),
            targetPosition: {
                lng: lng,
                lat: lat,
                height: height,
                heading: heading,
                pitch: pitch,
                roll: roll,
            }
        }
        this.DronePositions.splice(i + 1, 0, pos);
    }
}

根据航线坐标集合计算heading、pitch、roll

从网上抄的计算heading和pitch的方法(参考博客:https://blog.csdn.net/u010447508/article/details/105562542?_refluxos=a10):

/**
 * 根据两个坐标点,获取Heading(朝向)
 * @param { Cesium.Cartesian3 } pointA 
 * @param { Cesium.Cartesian3 } pointB 
 * @returns 
 */
function getHeading(pointA, pointB) {
    //建立以点A为原点,X轴为east,Y轴为north,Z轴朝上的坐标系
    const transform = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
    //向量AB
    const positionvector = Cesium.Cartesian3.subtract(pointB, pointA, new Cesium.Cartesian3());
    //因transform是将A为原点的eastNorthUp坐标系中的点转换到世界坐标系的矩阵
    //AB为世界坐标中的向量
    //因此将AB向量转换为A原点坐标系中的向量,需乘以transform的逆矩阵。
    const vector = Cesium.Matrix4.multiplyByPointAsVector(
        Cesium.Matrix4.inverse(transform, new Cesium.Matrix4()),
        positionvector,
        new Cesium.Cartesian3()
    );
    //归一化
    const direction = Cesium.Cartesian3.normalize(vector, new Cesium.Cartesian3());
    //heading
    let heading = Math.atan2(direction.y, direction.x) - Cesium.Math.PI_OVER_TWO;
    heading = Cesium.Math.TWO_PI - Cesium.Math.zeroToTwoPi(heading);
    return Cesium.Math.toDegrees(heading);
}

/**
 * 根据两个坐标点,获取Pitch(仰角)
 * @param { Cesium.Cartesian3 } pointA 
 * @param { Cesium.Cartesian3 } pointB 
 * @returns 
 */
function getPitch(pointA, pointB) {
    let transfrom = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
    const vector = Cesium.Cartesian3.subtract(pointB, pointA, new Cesium.Cartesian3());
    let direction = Cesium.Matrix4.multiplyByPointAsVector(Cesium.Matrix4.inverse(transfrom, transfrom), vector, vector);
    Cesium.Cartesian3.normalize(direction, direction);
    //因为direction已归一化,斜边长度等于1,所以余弦函数等于direction.z
    let pitch = Cesium.Math.PI_OVER_TWO - Cesium.Math.acosClamped(direction.z);
    return Cesium.Math.toDegrees(pitch);
}

根据航线坐标集合计算heading、pitch、roll:
代码中this.DronePositions是无人机群的坐标集合,坐标放在targetPosition属性中

/**
 * 计算无人机群的heading
 */
DetectsDrones.prototype.calcHeading = function () {
    // 清空原有heading
    this.DronePositions.map(pos => {
        pos.targetPosition.heading = undefined;
    });

    for (let i = 0; i < this.DronePositions.length - 1; i++) {
        let pos1 = this.DronePositions[i];
        let pos2 = this.DronePositions[i + 1];
        let heading = -90 + getHeading(Cesium.Cartesian3.fromDegrees(pos1.targetPosition.lng, pos1.targetPosition.lat), Cesium.Cartesian3.fromDegrees(pos2.targetPosition.lng, pos2.targetPosition.lat));
        if (!pos1.targetPosition.heading) {
            pos1.targetPosition.heading = heading;
        }
        pos2.targetPosition.heading = heading;
    }
}

/**
 * 计算无人机群的pitch
 */
DetectsDrones.prototype.calcPitch = function () {
    // 清空原有pitch
    this.DronePositions.map(pos => {
        pos.targetPosition.pitch = undefined;
    });

    for (let i = 0; i < this.DronePositions.length - 1; i++) {
        let pos1 = this.DronePositions[i];
        let pos2 = this.DronePositions[i + 1];
        let pitch = getPitch(Cesium.Cartesian3.fromDegrees(pos1.targetPosition.lng, pos1.targetPosition.lat, pos1.targetPosition.height), Cesium.Cartesian3.fromDegrees(pos2.targetPosition.lng, pos2.targetPosition.lat, pos2.targetPosition.height));
        if (!pos1.targetPosition.pitch) {
            pos1.targetPosition.pitch = pitch;
        }
        pos2.targetPosition.pitch = pitch;
    }
}

/**
 * 计算无人机群的roll(不支持转弯大于90度)
 */
DetectsDrones.prototype.calcRoll = function () {
    // 清空原有roll
    this.DronePositions.map(pos => {
        pos.targetPosition.roll = undefined;
    });

    for (let i = 1; i < this.DronePositions.length - 1; i++) {
        let pos1 = this.DronePositions[i];
        let pos2 = this.DronePositions[i + 1];
        let deltaHeading = pos2.targetPosition.heading - pos1.targetPosition.heading;
        pos2.targetPosition.roll = deltaHeading / 1.5;
    }
}

效果

遇到的问题

  1. 插值计算的问题,就是设置的坐标集合,是拆线,最好把它插值成平滑曲线,但是Cesium自带的插值,有时间参数,而我想仅仅通过经纬度集合来插值。
  2. 我写的计算roll的方法有问题,不支持转弯大于90度的情况,花了一些时间,没搞定。转弯小于90度,凑合用,测试了几组数据没问题,但仍不确定有没有BUG。
    抛砖引玉,有没有高手给个提示,插值问题怎么解决?roll的正确的通用的计算方法?

标签:pitch,heading,let,Pitch,Cesium,targetPosition,Roll,pos1
From: https://www.cnblogs.com/s0611163/p/18107778

相关文章

  • MogDB/openGauss如何实现事务的rollback
    MogDB/openGauss如何实现事务的rollback本文出处:https://www.modb.pro/db/113262数据库最主要的功能就是存储数据,然而我们在进行数据库操作时,却很容易发生误操作数据的情况,那么在MogDB中该如何实现误操作数据恢复呢?本文通过具体示例简要介绍如何通过回滚还原到误操作前的状......
  • import resolve from '@rollup/plugin-node-resolve' 这个包的作用是什么
    importresolvefrom'@rollup/plugin-node-resolve'这行代码引入了Rollup.js的一个插件——@rollup/plugin-node-resolve。这个插件在使用Rollup进行模块打包时起到至关重要的作用,具体作用如下:**1.Node.js模块解析:@rollup/plugin-node-resolve插件的主要职责是帮助Ro......
  • rollup 插件开发 - 输出钩子
    rollup插件开发-输出钩子outputOptions(outputOptions:OutputOptions)=>OutputOptions\|null替换或操作传递给bundle.generate()或bundle.write()的输出选项对象。返回null不会替换任何内容。如果我们只需要读取输出选项,则建议使用renderStart钩子,因为......
  • @rollup/plugin-url 使用及原理介绍
    @rollup/plugin-url使用及原理介绍一款用于将导入的文件转换成data-uri或者es模块的插件。安装npminstall@rollup/plugin-url-D使用在rollup.config.js文件中引入插件并进行简单配置。importurlfrom'@rollup/plugin-url';exportdefault{input:'......
  • helm 安装 nginx-ingress-controller v1.10.0
    1、说明准备nginx-ingress三种不同的部署模式Deployment+LoadBalancer采用deployment进行部署nginx-ingress-controller,需要创建一个type:LoadBalancer的service进行关联nginx-ingress-controller这组pod。通常是在使用公有云进行创建负载均衡器并绑定公网地址。只要将域名......
  • 每日面经分享(SpringBoot part4:Controller层)
    SpringBootController层的作用a.请求映射:Controller层使用注解(如@RequestMapping、@GetMapping、@PostMapping等)将HTTP请求映射到相应的方法上。这些方法根据URL路径、请求方法、请求参数等来决定要执行的操作。b.参数解析:Controller层负责解析HTTP请求中的参数(如路径......
  • cesium内存泄漏问题优化
    在vue开发SPA实际项目中,不止涉及到使用cesium可视化的大屏一个界面,在切换页面或者关闭该功能、弹框后,cesium加载的模型,图层,实体等等信息会缓存到电脑的显存中,但是切回cesium界面的时候,又会重新进入页面的挂载周期,进行新的cesium实例的渲染,显存占用会越来越大,达到临界值后,页面会......
  • WPF解决当ScrollViewer中嵌套ItemsControl时,不能使用鼠标来滚动翻页
    1.在DataGrid中添加PreviewMouseWheel事件,并将事件的Handled属性设置为false,以便将滚动事件传递给ScrollViewer。示例代码如下:<DataGridPreviewMouseWheel="DataGrid_PreviewMouseWheel"><!--DataGrid的其他设置--></DataGrid>privatevoidDataGrid_PreviewMouseWh......
  • P2854 [USACO06DEC] Cow Roller Coaster S
    原题链接题解1.当没有花费限制的时候,我们可以将其抽象为简单的背包问题2.如果有了花费限制,那么我们就再加一维条件3.如果一个线段能用,那么它前面一定是铺满的,那我们令线段按起点排序,通过某种运算,保证放这个线段时,前面的线段组成是最优的比如在\(i\)点结尾位置花费\(j\)所......
  • Cesium的相机(2)
    本节主讲相机的Heading\Pitch和Roll。Cesium的相机主要是通过局部坐标的偏航角、俯仰角和翻滚角确定相机姿态的。上一节我们知道,Cesium在获取这三个角度的时候,会将以地球球心为原点的地心地固坐标ECEF转为ENU东北天坐标系,ENU坐标系中,X轴指向正东,Y轴指向正北,Z轴指向天顶。所谓的......