二维旋转变换

求点 P(x1, y1) 绕点 Q(x2, y2) 逆时针旋转 θ 得到的点的坐标

先看绕原点旋转的情况:

在这里插入图片描述

如图所示点 v 绕 原点旋转 θ 角,得到点v’,假设 v点的坐标是(x, y) ,那么可以推导得到 v’点的坐标(x’, y’):

{ x = r ∗ cos ⁡ θ y = r ∗ sin ⁡ θ \left\{ \begin{aligned} x & = r * \cos\theta \\ y & = r * \sin\theta \\ \end{aligned} \right. {xy=rcosθ=rsinθ

{ x ′ = r ∗ cos ⁡ ( ϕ + θ ) y ′ = r ∗ sin ⁡ ( ϕ + θ ) \left\{ \begin{aligned} x' & = r * \cos( \phi + \theta) \\ y' & = r * \sin( \phi + \theta) \\ \end{aligned} \right. {xy=rcos(ϕ+θ)=rsin(ϕ+θ)

展开得:

{ x ′ = r ∗ cos ⁡ ϕ ∗ cos ⁡ θ − r ∗ sin ⁡ ϕ ∗ sin ⁡ θ y ′ = r ∗ sin ⁡ ϕ ∗ cos ⁡ θ + r ∗ cos ⁡ ϕ ∗ sin ⁡ θ \left\{ \begin{aligned} x' & = r * \cos\phi * \cos\theta - r * \sin\phi * \sin\theta \\ y' & = r * \sin\phi * \cos\theta + r * \cos\phi * \sin\theta \\ \end{aligned} \right. {xy=rcosϕcosθrsinϕsinθ=rsinϕcosθ+rcosϕsinθ

带入 x 和 y 的表达式:

{ x ′ = x ∗ cos ⁡ θ − y ∗ sin ⁡ θ y ′ = y ∗ cos ⁡ θ + x ∗ sin ⁡ θ \left\{ \begin{aligned} x' & = x * \cos\theta - y * \sin\theta \\ y' & = y * \cos\theta + x* \sin\theta \\ \end{aligned} \right. {xy=xcosθysinθ=ycosθ+xsinθ

写为矩阵:

[ x ′ y ′ ] = [ cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ ] ∗ [ x y ] \begin{bmatrix} x'\\ y'\\ \end{bmatrix}= \begin{bmatrix} \cos\theta&-\sin\theta\\ \sin\theta&\cos\theta\\ \end{bmatrix}* \begin{bmatrix} x\\ y\\ \end{bmatrix} [xy]=[cosθsinθsinθcosθ][xy]

于是我们得到旋转变换矩阵 M:

M = [ cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ ] M = \begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix} M=[cosθsinθsinθcosθ]

设旋转后的到的坐标为 P’(x’, y’),类似于平面向量中将起点平移至原点的思想,我们可以将 P 点绕 Q 点旋转的过程看作 QP 向量旋转得到 QP’ 向量,于是根据 P 和 Q 坐标有:

[ x ′ − x 2 y ′ − y 2 ] = [ cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ ] ∗ [ x 1 − x 2 y 1 − y 2 ] \begin{bmatrix} x' - x_2\\ y' - y_2\\ \end{bmatrix}= \begin{bmatrix} \cos\theta&-\sin\theta\\ \sin\theta&\cos\theta\\ \end{bmatrix}* \begin{bmatrix} x_1 - x_2\\ y_1 - y_2\\ \end{bmatrix} [xx2yy2]=[cosθsinθsinθcosθ][x1x2y1y2]

于是得到 P’ 坐标为:

[ x ′ y ′ ] = [ cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ ] ∗ [ x 1 − x 2 y 1 − y 2 ] + [ x 2 y 2 ] \begin{bmatrix} x'\\ y'\\ \end{bmatrix}= \begin{bmatrix} \cos\theta&-\sin\theta\\ \sin\theta&\cos\theta\\ \end{bmatrix}* \begin{bmatrix} x_1 - x_2\\ y_1 - y_2\\ \end{bmatrix} + \begin{bmatrix} x_2\\ y_2\\ \end{bmatrix} [xy]=[cosθsinθsinθcosθ][x1x2y1y2]+[x2y2]

算法实现:

from collections import namedtuple
import math

Point = namedtuple("Point", ["x", 'y'])


def matrix_mul(M: list[list[float]], vec: list[float]) -> list[float]:
    res = []
    for row in M:
        res.append(sum([a * b for (a, b) in zip(row, vec)]))
    return res


def rotate(p: Point, q: Point, theta: float) -> Point:
    M = [
        [math.cos(theta), -math.sin(theta)],
        [math.sin(theta), math.cos(theta)]
    ]
    pq = [p.x - q.x, p.y - q.y]
    t = matrix_mul(M, pq)
    t[0] += q.x
    t[1] += q.y
    return Point(t[0], t[1])


def main():
    print(rotate(Point(1.414, 0), Point(0, 0), math.pi / 4), "expect (1, 1)")
    print(rotate(Point(1, 1), Point(0, 0), -math.pi / 4), "expect (1.414, 0)")
    print(rotate(Point(2, 2), Point(1, 1), -math.pi / 4), "expect (2.414, 1)")


if __name__ == '__main__':
    main()
  • 16
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值