C语言编程:坐标系的平移和旋转

news2024/9/24 11:30:48

本文总结博主在工作中遇到的坐标系转换相关问题,以及C语言编程实现。

文章目录

  • 1 问题场景
  • 2 公式推导
    • 2.1 旋转坐标系推导
    • 2.2 平移坐标系推导
    • 2.3 完整公式
  • 3 C语言编程

1 问题场景

对于ADAS算法开发,在工作中遇到过很多需要坐标系转换的场景。例如,一辆车上有很多个传感器,包括摄像头、毫米波雷达和激光雷达。在同一时刻感知到外部环境信息后,由于不同传感器基于自身坐标系,在数据融合之前需要将目标信息转换到同一个坐标系之下(通常是汽车后轴中心点)。

例如,下图中的XOY坐标系是以车辆后轴中心点为原点,车头方向为X轴正方向,垂直车身向左是Y轴正方向。X’O’Y’是前视摄像头坐标系,以摄像头位置为坐标原点,坐标轴方向和XY相同。

在这里插入图片描述
X’O’Y’坐标系相对于XOY坐标系向前平移一个距离,左右也相应的有一个距离。已知一个点P在X’O’Y’坐标系中的坐标为(x’,y’),以及已知O’点在XOY坐标系的坐标(xo’,yo’),就可以通过坐标平移算出点P在XOY坐标系中的坐标。这是坐标系平移的例子。

再举个例子,车辆在运动的过程中,方向盘打了一个角度,汽车就会做一个圆周运动。在某一时刻t0,经过Δt时间,车辆不仅产生一个位置上的平移,自身还有一个旋转。

在这里插入图片描述
结合上图,比如说在t0时刻一个目标点在XOY坐标系下的坐标是(x,y),在t1时刻车辆运动到前面一点的位置,并且车头朝向偏左了一个角度。这时候,那个目标点和车的相对位置就改变了,需要重新计算它在X’O’Y’坐标系中的坐标。利用X’O’Y’坐标系相对于XOY坐标系的距离和角度,就可以求出来目标点在心得坐标系X’O’Y’坐标系中的坐标(x’,y’)。这个例子中包含了坐标系的平移和旋转。

2 公式推导

上面场景的问题总结如下:已知点P在XOY坐标系中的坐标为(px,py),X’O’Y’坐标系的原点O’在XOY坐标系中的坐标为(ox’,oy’),求点P在X’O’Y’坐标系中的坐标。这里坐标系采用了右手系,即X向右Y向上。旋转角度定义为逆时针为正角度,以便后面的推导。

在这里插入图片描述

两个坐标系之间通过平移和旋转两种运动转换得到。为简化推导,首先基于O’点做出一个中间坐标系X’’O’Y’’,先完成旋转运动。

在这里插入图片描述

这里问题就转换为先推导(px’,py’)和(px’’,py’’)的关系,再推导(px’’,py’’)和(px,py)的关系。

2.1 旋转坐标系推导

首先,过点P做垂直线PA⊥O’Y’,PB⊥O’X’,PC⊥O’Y’’,PD⊥O’X’’,那么很容易知道∠BPD = θ,如下图所示。
在这里插入图片描述
接着过点D做DE⊥O’X’,如下:
在这里插入图片描述
这样,就可以推导出px’:
p x ′    =    ∣ O ′ E ∣    + ∣    E B ∣    =    ∣ O ′ D ∣ ⋅ cos ⁡ θ    +    ∣ P D ∣ ⋅ sin ⁡ θ    =    p x ′ ′ ⋅ cos ⁡ θ      +    p y ′ ′ ⋅ sin ⁡ θ    px'\;=\;\vert O'E\vert\;+\vert\;EB\vert\;=\;\vert O'D\vert\cdot\cos\theta\;+\;\vert PD\vert\cdot\sin\theta\;=\;px''\cdot\cos\theta\;\;+\;py''\cdot\sin\theta\; px=OE+EB=ODcosθ+PDsinθ=px′′cosθ+py′′sinθ

接着推导py’,过点D做DF⊥PF(PF是PB的延长线),就可以推导出py’:
在这里插入图片描述
p y ′    =    ∣ P F ∣    −    ∣    B F ∣    =    ∣ P D ∣ ⋅ cos ⁡ θ    −    ∣ O D ∣ ⋅ sin ⁡ θ    =    p y ′ ′ ⋅ cos ⁡ θ      −    p x ′ ′ ⋅ sin ⁡ θ    py'\;=\;\vert PF\vert\;-\;\vert\;BF\vert\;=\;\vert PD\vert\cdot\cos\theta\;-\;\vert OD\vert\cdot\sin\theta\;=\;py''\cdot\cos\theta\;\;-\;px''\cdot\sin\theta\; py=PFBF=PDcosθODsinθ=py′′cosθpx′′sinθ

将上面两个推导的结果写到一起,后面的章节需要用到:
p x ′    =    p x ′ ′ ⋅ cos ⁡ θ      +    p y ′ ′ ⋅ sin ⁡ θ       p y ′    = −    p x ′ ′ ⋅ sin ⁡ θ    +    p y ′ ′ ⋅ cos ⁡ θ      px'\;=\;px''\cdot\cos\theta\;\;+\;py''\cdot\sin\theta\;\\\; py'\;=-\;px''\cdot\sin\theta\;+\;py''\cdot\cos\theta\;\; px=px′′cosθ+py′′sinθpy=px′′sinθ+py′′cosθ
这里也可以用矩阵变换的方式,一步就能得出这个结论。点P相当于绕着原点顺时针转了θ角度,所以通过旋转矩阵公式可以得出变换关系。
[ p x ′ p y ′ ]    =    [ cos ⁡ θ sin ⁡ θ − sin ⁡ θ cos ⁡ θ ] [ p x ′ ′ p y ′ ′ ] \begin{bmatrix}px'\\py'\end{bmatrix}\;=\;\begin{bmatrix}\cos\theta&\sin\theta\\-\sin\theta&\cos\theta\end{bmatrix}\begin{bmatrix}px''\\py''\end{bmatrix} [pxpy]=[cosθsinθsinθcosθ][px′′py′′]

2.2 平移坐标系推导

平移的推导过程就简单很多,见下图
在这里插入图片描述
就是简单的加减:

p x ′ ′    =    p x    −    o ′ x p y ′ ′    =    p y    −    o ′ y px''\;=\;px\;-\;o'x\\py''\;=\;py\;-\;o'y px′′=pxoxpy′′=pyoy

2.3 完整公式

将上面两个小节的公式代入得出完整公式:
p x ′    =    ( p x    −    o ′ x ) ⋅ cos ⁡ θ      +    ( p y    −    o ′ y ) ⋅ sin ⁡ θ       p y ′    = −    ( p x    −    o ′ x ) ⋅ sin ⁡ θ    +    ( p y    −    o ′ y ) ⋅ cos ⁡ θ      px'\;=\;(px\;-\;o'x)\cdot\cos\theta\;\;+\;(py\;-\;o'y)\cdot\sin\theta\;\\\; py'\;=-\;(px\;-\;o'x)\cdot\sin\theta\;+\;(py\;-\;o'y)\cdot\cos\theta\;\; px=(pxox)cosθ+(pyoy)sinθpy=(pxox)sinθ+(pyoy)cosθ
后面基于这个公式编写C语言程序

3 C语言编程

首先,分析一下这个程序的需求。输入是一个点的在旧坐标系下的坐标,以及新坐标系相对于旧坐标系的位置和旋转角度。输出是该点在新坐标系下的坐标。

这里,博主设计一个简单的函数来实现这个算法。

#include <stdio.h>
#include <math.h>

#define PI 3.1415926F

typedef struct Point_Tag
{
    float X;
    float Y;
} Point_Type;//点结构体

typedef struct CoordinatePosition_Tag
{
    float deltaX;
    float deltaY;
    float theta;
} CoordinatePosition_Type;//新坐标系相对旧坐标系位置结构体

//坐标系变换函数
void coordinate_transformation(const Point_Type*              const point_old_system_sp,
                               const CoordinatePosition_Type* const coordinate_position_sp,
                                     Point_Type*              const point_new_system_sp)
{
    point_new_system_sp->X =  (point_old_system_sp->X - coordinate_position_sp->deltaX) * cosf(coordinate_position_sp->theta) +
                              (point_old_system_sp->Y - coordinate_position_sp->deltaY) * sinf(coordinate_position_sp->theta);
    point_new_system_sp->Y = -(point_old_system_sp->X - coordinate_position_sp->deltaX) * sinf(coordinate_position_sp->theta) +
                              (point_old_system_sp->Y - coordinate_position_sp->deltaY) * cosf(coordinate_position_sp->theta);
}

//main函数中简单测试
int main()
{
    Point_Type point_old_system;
    CoordinatePosition_Type coordinate_position;
    Point_Type point_new_system;

    point_old_system.X = 2.0F;
    point_old_system.Y = 2.0F;
    coordinate_position.deltaX = 0.0F;
    coordinate_position.deltaY = 0.0F;
    coordinate_position.theta = (45.0F/180.0F*PI);

    coordinate_transformation(&point_old_system,&coordinate_position,&point_new_system);

    printf("NEW_X = %f,NEW_Y = %f", point_new_system.X,point_new_system.Y);

} 

代码实现是比较简单的,就是把公式翻译成C代码。功能函数中传了三个参数,前两个指针是用来输入点在就坐标系的位置,和新坐标系在旧坐标系的位置和角度。第三个指针用于获取输出结果。

>>返回个人博客总目录

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

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

相关文章

进制转换(十进制与十六进制互转)

之前的一家公司基本上都是基于单片机进行开发&#xff0c;一般与上位机的通信都是按照自定义的协议进行操作&#xff0c;测试的时候会经常都对协议进行修改并且涉及到进制之间的转换&#xff0c;例如获取版本是十六进制的需要转换成十进制的版本信息&#xff0c;例如修改时间需…

013-从零搭建微服务-认证中心(五)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;https://gitee.com/csps/mingyue 源码地址&#xff08;前端&#xff09;&#xff1a;https://gitee.com/csps…

LoRa模块(SX1278)详解

LoRa模块&#xff08;SX1278&#xff09; 0. LoRa概述概念LoRa技术的主要特点LoRa技术的工作原理 1. 常见的LoRa模块2. Semtech SX12783. STM32使用SX1278方法示例代码 0. LoRa概述 概念 LoRa&#xff08;Long Range&#xff09;是一种长距离、低功耗的无线通信技术&#xff…

被劫持的礼物

根据题目其实也猜得到这道题的大致考察内容 下载好后得到一个wireshark的流量文件 根据提示&#xff0c;flag是账号和密码组合的MD5值&#xff0c;想到登录&#xff0c;其实就想到两个登录框 也就是POST请求方法 打开文件后会也会得到一些 http的包&#xff0c;过滤一下 查看到…

线性DP—入门篇

线性动态规划的主要特点是状态转移的推导是按照问题规模 从小到大依次推导&#xff0c;较大规模的问题的解依赖较小规模的问题的解。 数字三角形&#xff1a; [USACO1.5][IOI1994]数字三角形 Number Triangles - 洛谷https://www.luogu.com.cn/problem/P1216我们来看一道经典…

ModaHub魔搭社区:向量数据库Milvus产品问题(三)

目录 Milvus 的数据落盘逻辑是怎样的&#xff1f; Mishards 推荐的配置是什么&#xff1f; Mishards 支持 RESTful API 吗&#xff1f; 什么是归一化&#xff1f;Milvus 中为什么有时候需要归一化&#xff1f; 为什么欧氏距离和内积在计算向量相似度时的结果不一致&#x…

【Git原理与使用】-- 分支管理

目录 理解分支 创建分支 查看当前分支 创建本地分支 切换分支 合并分支 删除分支 合并冲突 分支管理策略 分支策略 bug 分支 不建议的合并方式 建议的合并方式 第一步 第二步 删除临时分支 理解分支 分支就是科幻电影里面的平行宇宙&#xff0c;当你正在电脑前…

java 全局、局部异常处理详解及result结果封装

1、引入spring-boot-starter-web依赖和new-swagger依赖 <dependency><groupId>com.jjw</groupId><artifactId>new-swagger</artifactId><version>1.0-SNAPSHOT</version> </dependency> <dependency><groupId>or…

Linux系统编程:进程的替换

目录 一. 进程替换的原理 二. 进程替换的方法 2.1 进程替换的相关函数 2.2 进程替换为其它的C/C程序或其它语言编写的程序 三. 自主实现简单地命令行解释器 四. 总结 一. 进程替换的原理 进程替换&#xff0c;就是对进程所执行的代码进行替换&#xff0c;让正在运行的一个…

华为OD机试真题 Python 实现【简单的自动曝光】【2023Q1 100分】,附详细解题思路

目录 一、题目描述二、输入描述三、输出描述四、备注五、解题思路六、Python算法源码七、效果展示1、输入2、输出3、说明4、再输入5、输出6、说明 一、题目描述 一个图像有 n 个像素点&#xff0c;存储在一个长度为 n 的数组 img 里&#xff0c;每个像素点的取值范围[0,255]的…

HOT33-排序链表

leetcode原题链接&#xff1a;排序链表 题目描述 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出…

html内盒子长宽增加溢出但是外盒子不自动向下延

自动扩展 问题描述 外盒子设置固定px&#xff0c;导致内盒子如图片长宽增加后&#xff0c;溢出但是外盒子不自动扩展&#xff08;向下延申&#xff09; 图片高230时正常 设置250后超出 问题解决 /*height: 660px;*/ /*设死就不能自动扩展&#xff0c;内块块长宽超出&#x…

vuex-persistedstate —— 数据持久化

在之前的篇目当中对于 Vuex 中的相关内容都讲得差不多&#xff0c;但是在项目中去使用vuex&#xff0c;虽然数据状态得到管理了&#xff0c;但数据在每一次都需要去重新加载&#xff0c;那么对于数据的持久化vue是没有给解决的&#xff0c;而是通过第三方的工具去进行数据的持久…

代码随想录算法训练营第17期第4天(5休息) | 24. 两两交换链表中的节点、19. 删除链表的倒数第 N 个结点、面试题 02.07. 链表相交、​​​​​​142. 环形链表 II

目录 24. 两两交换链表中的节点 19. 删除链表的倒数第 N 个结点 面试题 02.07. 链表相交 ​​​​​​142. 环形链表 II 这题不是很难&#xff0c;目前除了从【.】变成了【->】之外&#xff0c;python和C也没啥区别 另外就是对虚拟头结点的掌握了 /*** Definition for …

爬虫小白入门在服务器上-部署爬虫或者开服务接口并供给他人访问

目录 一、准备工作-服务器1、先准备一个服务器&#xff08;以阿里云为例子&#xff09;2、开通服务端口号访问权限 二、准备工作-Xshell登录服务器1、xshell基本登录操作2、xftp基本操作 三、部署代码到服务器上1、部署一个python爬虫脚本在服务器上定时运行等2、部署一个pytho…

Java-API简析_占位符类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/131504916 出自【进步*于辰的博客】 因为我发现目前&#xff0c;我对Java-API的学习意识比较薄弱…

区块链开发:JS/TS本地|项目环境搭建

区块链开发&#xff1a;JS/TS本地|项目环境搭建 本地环境搭建VSCode Solidity扩展全局安装Solc,corepackVSCode配置本地Solc安装Ganache搭建JS虚拟环境 项目测试安装依赖编写代码部署合约test_blockchain.ts 设置Script部署查看 报错说明1. Error&#xff1a;missing revert da…

【EasyX】使用C/C++实现 流星雨效果(配上详细注释解释)

&#x1f38a;专栏【​​​​​​​EasyX】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Love Story】 &#x1f970;大一同学小吉&#xff0c;欢迎并且感谢大家指出我的问题&#x1f970; 文章目录 &#x1f354;效果&#x…

RNN LSTM

参考资料&#xff1a; 《机器学习2022》李宏毅史上最详细循环神经网络讲解&#xff08;RNN/LSTM/GRU&#xff09; - 知乎 (zhihu.com) LSTM如何来避免梯度弥散和梯度爆炸&#xff1f; - 知乎 (zhihu.com) 1 RNN 的结构 首先考虑这样一个 slot filling 问题&#xff1a; 注意…

云解析DNS

云解析过程&#xff1a; DNS查询的结果通常会在本地域名服务器中进行缓存&#xff0c;如果本地域名服务器中有缓存的情况下&#xff0c;则会跳过如下DNS查询步骤&#xff0c;很快返回解析结果。下面的示例则概述了本地域名服务器没有缓存的情况下&#xff0c;DNS查询所需的8个步…