浅谈osgEarth操控器类的createLocalCoordFrame函数如何将局部坐标系的点转为世界坐标系下的Martix(ENU坐标)

news2024/12/29 9:58:01

在osgEarth操控器类的EarthManipulator中的如下函数:

void EarthManipulator::setLookAt(const osg::Vec3d& center,
                            double            azim,
                            double            pitch,
                            double            range,
                            const osg::Vec3d& posOffset)
{
    setCenter( center );
    .... // 其它代码略
}

void EarthManipulator::setCenter( const osg::Vec3d& worldPos )
{
    _center = worldPos;
    createLocalCoordFrame( worldPos, _centerLocalToWorld );
    .... // 其它代码略
}

如上代码在osgEarth操控器EarthManipulator类的setLookAt函数调setCenter函数设置相机视点看向的位于地球上的某焦点区域的中心_center_center是世界坐标系表示的点,也即是地心地固坐标系表示的点。setCenter函数调用createLocalCoordFrame函数,其代码如下:

bool
EarthManipulator::createLocalCoordFrame( const osg::Vec3d& worldPos, osg::CoordinateFrame& out_frame ) const
{
    if ( _srs.valid() )
    {
        osg::Vec3d mapPos;
        _srs->transformFromWorld( worldPos, mapPos );
        _srs->createLocalToWorld( mapPos, out_frame );
    }
    return _srs.valid();
}

其中: 

_srs->transformFromWorld( worldPos, mapPos );

是将地心地固坐标系表示的点worldPos转为经度、纬度、高程坐标系(一般为WGS84)下的点,并保存到mapPos变量中。按上面的调用流程来看,就是将_center转为经纬度、高程坐标系下的坐标,并保存到mapPos变量中。如下代码:

_srs->createLocalToWorld( mapPos, out_frame );

将mapPos变即最开始的_center转为经纬度高程后的坐标再转为out_frame。上述createLocalToWorld函数到底是干什么用的呢?断点跟踪到底层代码:

bool
SpatialReference::createLocalToWorld(const osg::Vec3d& xyz, osg::Matrixd& out_local2world ) const
{
    if (!valid())
        return false;

    if ( isProjected() && !isCube() )
    {
        ....// 其它代码略
    }
    else if ( isGeocentric() )
    {
        ....// 其它代码略
    }
    else
    {
        // convert to ECEF:
        osg::Vec3d ecef;
        if ( !transform(xyz, getGeocentricSRS(), ecef) )
            return false;

        // and create the matrix.
        out_local2world = _ellipsoid.geocentricToLocalToWorld(ecef);
    }
    return true;
}

 在else语句中又将经纬度、高程坐标系下的_center转回地心地固坐标,接下来通过geocentricToLocalToWorld将这个地心地固坐标下_center进行转换

osg::Matrix
Ellipsoid::geocentricToLocalToWorld(const osg::Vec3d& geoc) const
{
    osg::Matrix m;
    EM.computeLocalToWorldTransformFromXYZ(geoc.x(), geoc.y(), geoc.z(), m);
    return m;
}

发现上述代码调用了osg里面的函数:

inline void EllipsoidModel::computeLocalToWorldTransformFromXYZ(double X, double Y, double Z, osg::Matrixd& localToWorld) const
{
    double  latitude, longitude, height;
    convertXYZToLatLongHeight(X,Y,Z,latitude,longitude,height);
  
    localToWorld.makeTranslate(X,Y,Z);
    computeCoordinateFrame(latitude, longitude, localToWorld);
}

这个函数前面很简单:又将地心地固坐标_center转成经纬度、高程坐标系坐标;这个函数后面断点跟进去如下:

inline void EllipsoidModel::computeCoordinateFrame(double latitude, double longitude, osg::Matrixd& localToWorld) const
{
    // Compute up vector
    osg::Vec3d    up      ( cos(longitude)*cos(latitude), sin(longitude)*cos(latitude), sin(latitude));
    // Compute east vector
    osg::Vec3d    east    (-sin(longitude), cos(longitude), 0);
    // Compute north vector = outer product up x east
    osg::Vec3d    north   = up ^ east;
    // set matrix
    localToWorld(0,0) = east[0];
    localToWorld(0,1) = east[1];
    localToWorld(0,2) = east[2];
 
    localToWorld(1,0) = north[0];
    localToWorld(1,1) = north[1];
    localToWorld(1,2) = north[2];
 
    localToWorld(2,0) = up[0];
    localToWorld(2,1) = up[1];
    localToWorld(2,2) = up[2];
}

可以看出,上面这个函数就是生成了一个旋转矩阵,再结合上面的那个平移的代码:

localToWorld.makeTranslate(X,Y,Z);

可以看出,生成的这个矩阵是一个旋转平移矩阵。而且是先旋转,后平移。 上面坐标结合下图很容易理解:

图1 坐标转换图 

 经过这么多转换后,_center向东、向北,向天方向的姿态就出来了,如下:

                                                             图2 ECEF、ENU、BLH坐标系

 淡绿色坐标系为东北天(ENU)坐标系,经过这么多次转换后,_center就相当于三个淡绿色坐标系的原点(说明:在osgEarth操控器中,程序初始流程刚进入时,_center其实是位于图2中的1位置处,即地心地固坐标系Y轴负半轴和赤道圆交点处,这里为了便于观察,将ENU放到易于观察的角度了)。另外:图2中灰色的X、Y、Z轴表示的地心地固坐标系(ECEF),桔黄色表示的是经纬度坐标系(BLH)。

  地心地固坐标系和ENU坐标系之间的换算,可以参考如下博文:

地心地固坐标系(ECEF)与站心坐标系(ENU)的转换。

参考链接:

osgearth 代码 hack(一) GeoTransfrom 如何工作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/499678.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二、PEMFC基础之电化学与反应动力学

二、PEMFC基础之电化学与反应动力学 1.电流、电流密度2.反应速率常数3.交换电流密度4.电化学动力学奠基石B-V方程5.活化损失计算Tafel公式6.计算案例 1.电流、电流密度 由法拉第定律 i d Q d t n F d N d t i\frac{dQ}{dt}\frac{nFdN}{dt} idtdQ​dtnFdN​ j i A j\frac{…

查询缓存实现、缓存更新策略选择、解决缓存穿透缓存雪崩缓存击穿问题

文章目录 1 什么是缓存?1.1 为什么要使用缓存1.2 如何使用缓存 2 给商户信息查询业务添加缓存2.1 缓存模型和思路2.2 代码如下 3 缓存更新策略3.1 数据库缓存不一致解决方案:3.2 数据库和缓存不一致采用什么方案3.3 删除缓存还是更新缓存?3.4 如何保证缓…

MySQL --- DQL

使用DDL语句来操作数据库以及表结构(数据库设计)使用DML语句来完成数据库中数据的增、删、改操作(数据库操作) 学习数据库操作方面的内容:查询(DQL语句)。 查询操作我们分为两部分学习&#…

chatgpt如何接入本地知识库?我们来看看EMNLP 2022 INFO是如何融入本地知识的

一、概述 title:You Truly Understand What I Need : Intellectual and Friendly Dialogue Agents grounding Knowledge and Persona 论文地址:You Truly Understand What I Need : Intellectual and Friendly Dialog Agents grounding Persona and Know…

基于S/Key协议的身份认证系统设计与实现【python】

实验内容 1 、 身份认证系统设计 设计身份认证系统的功能、主要界面、主要软件模块,以及采用的认证技术路线和方法。 2 、 编程实现所设计的身份认证系统 在C、Python或Java程序设计环境下,编程实现基于S/Key协议的身份认证系统。要求实现的身份认证…

计算机中丢失msvcp140.dll无法启动此程序怎么办?msvcp140.dll在哪里

电脑系统中的 msvcp140.dll 文件是 Microsoft Visual C Redistributable 组件的一部分,它们提供了许多在 Windows 操作系统中运行的应用程序所需的重要函数和库。如果丢失了 msvcp140.dll 文件,你可能会遇到多种错误,比如无法运行应用程序、系…

【RabbitMQ】安装及六种模式

文章目录 安装rabbitmq镜像访问容器内部15672端口映射到外面的端口地址RabbitMQ六种模式Hello world模式Work queues模式Publish/Subscribe模式交换机fanout类型 Routing模式Topics模式RPC模式 rabbitmq:0->1的学习 学习文档:https://www.cnblogs.com…

Java集合之双列集合

双列集合特点 双列集合一次需要添加一对数据,分别是键和值键不能重复,值可以重复键和值是一一对应的,每一个键只能找到自己对应的值键 值这个整体称为“键值对”或者“键值对对象”,Java中叫“Entry对象” 双列集合的体系结构 Ma…

linux系统systemd初始化进程

前言:目前绝大多数服务器系统以及从RHEL6换成RHEL7了,以前习惯使用service来管理系统服务的,那么现在就比较郁闷了,RHEL7系统中使用systemctl命令来管理服务。 systemctl启动、重启、停止、查看状态命令: systemctl …

算法竞赛字符串篇之C++中string的成员函数

2023年5月7日,周日中午: 今天决定从字符串这个知识点开始学起,记录一下我今天的字符串学习。 不定期更新。 相关的英文文档: https://cplusplus.com/reference/string/string/ 容量方面的成员函数: empty&#xff…

基于AT89C51单片机的电子闹钟设计与仿真

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87761718?spm=1001.2014.3001.5503 源码获取 主要内容: 基于51单片机设计一个电子闹钟,至少具有以下功能:时间的设定、时间的调整、闹钟的设定、温度的设定。 基本要求:…

排队论_M/M/1/inf/inf 问题

例:某修理店只有一一个修理工人,来修理的顾客到达数服从泊松分布,平均每小时4人;修理时间服从负指数分布,平均需6分钟。求: (1)修理店空闲的概率; (2)店内有3个顾客的概率; (3)店内至少有1个顾客的概率; (4)店内顾客的平均数; (5)顾客在店内的…

显著性检测:从传统方法到深度学习网络的演进与挑战

显著性检测技术在计算机视觉领域中扮演着至关重要的角色,它是一项对图像中最显著或最有区别的视觉特征进行分析和提取的技术。显著性检测技术可以为计算机视觉任务提供帮助,例如图像分割、目标检测、场景理解、图像检索和人机交互等方面。 本文将从传统方…

【MySQL】基于规则的优化(内含子查询优化;派生表;物化表;半连接;标量子查询;行子查询)

概念 常量表:下述两种查询方式查询的表: 类型1:查询的表中一条记录都没有,或者只有一条记录。 类型2:使用主键等值匹配或者唯一二级索引列等值匹配作为搜索条件来查询某个表 派生表:放在FROM子句后面的子…

UDP报头、TCP报头、IP报头、MAC头部、ARP头部

前言:DUP报头、TCP报头、IP报头、MAC头部、ARP头部。 UDP报头: UDP报头由八个字节组成,每个字段都是两个字节 : 1.源端口号:发送方端口号,需要对方回信的时候选用,不需要对方回信的时候置0 …

[LeetCode复盘] LCCUP‘23春季赛组队赛 20230507

[LeetCode复盘] LCCUP23春季赛组队赛 20230507 一、本周周赛总结1. 符文储备1. 题目描述2. 思路分析3. 代码实现 2. 城墙防线1. 题目描述2. 思路分析3. 代码实现 3. 提取咒文1. 题目描述2. 思路分析3. 代码实现 4. 生物进化录1. 题目描述2. 思路分析3. 代码实现 5. 与非的谜题…

HNU-操作系统OS-实验Lab3

OS_Lab3_Experimental report 湖南大学信息科学与工程学院 计科 210X wolf (学号 202108010XXX) 实验目的 了解虚拟内存的Page Fault异常处理实现了解页替换算法在操作系统中的实现 实验内容 本次实验是在lab2的基础上,借助于页表机制…

【python数据分析】运算符与表达式

🙋‍ 哈喽大家好,本次是python数据分析、挖掘与可视化专栏第三期 ⭐本期内容:运算符与表达式 🏆系列专栏:Python数据分析、挖掘与可视化 👍保持开心,拒绝拖延,你想要的都会有&#x…

车载软件架构——闲聊几句AUTOSAR BSW(四)

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 我们并不必要为了和谐,而时刻保持通情达理;我们需要具备的是,偶尔有肚量欣然承认在某些方面我们可能会有些不可理喻。该有主见的时候能掷地有声地镇得住场…