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

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

文章目录

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

1 问题场景

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

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

C语言编程:坐标系的平移和旋转_第1张图片
X’O’Y’坐标系相对于XOY坐标系向前平移一个距离,左右也相应的有一个距离。已知一个点P在X’O’Y’坐标系中的坐标为(x’,y’),以及已知O’点在XOY坐标系的坐标(xo’,yo’),就可以通过坐标平移算出点P在XOY坐标系中的坐标。这是坐标系平移的例子。

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

C语言编程:坐标系的平移和旋转_第2张图片
结合上图,比如说在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向上。旋转角度定义为逆时针为正角度,以便后面的推导。

C语言编程:坐标系的平移和旋转_第3张图片

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

C语言编程:坐标系的平移和旋转_第4张图片

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

2.1 旋转坐标系推导

首先,过点P做垂直线PA⊥O’Y’,PB⊥O’X’,PC⊥O’Y’’,PD⊥O’X’’,那么很容易知道∠BPD = θ,如下图所示。
C语言编程:坐标系的平移和旋转_第5张图片
接着过点D做DE⊥O’X’,如下:
C语言编程:坐标系的平移和旋转_第6张图片
这样,就可以推导出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’:
C语言编程:坐标系的平移和旋转_第7张图片
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 平移坐标系推导

平移的推导过程就简单很多,见下图
C语言编程:坐标系的平移和旋转_第8张图片
就是简单的加减:

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 
#include 

#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代码。功能函数中传了三个参数,前两个指针是用来输入点在就坐标系的位置,和新坐标系在旧坐标系的位置和角度。第三个指针用于获取输出结果。

>>返回个人博客总目录

你可能感兴趣的:(c语言,开发语言)