求点 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=r∗cosθ=r∗sinθ
{ x ′ = r ∗ cos ( ϕ + θ ) y ′ = r ∗ sin ( ϕ + θ ) \left\{ \begin{aligned} x' & = r * \cos( \phi + \theta) \\ y' & = r * \sin( \phi + \theta) \\ \end{aligned} \right. {x′y′=r∗cos(ϕ+θ)=r∗sin(ϕ+θ)
展开得:
{ 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. {x′y′=r∗cosϕ∗cosθ−r∗sinϕ∗sinθ=r∗sinϕ∗cosθ+r∗cosϕ∗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. {x′y′=x∗cosθ−y∗sinθ=y∗cosθ+x∗sinθ
写为矩阵:
[ 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} [x′y′]=[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 点旋转的过程看作 PQ 向量旋转得到 P’Q 向量,于是根据 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} [x′−x2y′−y2]=[cosθsinθ−sinθcosθ]∗[x1−x2y1−y2]
于是得到 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} [x′y′]=[cosθsinθ−sinθcosθ]∗[x1−x2y1−y2]+[x2y2]
算法实现:
from collections import namedtuple
import mathPoint = 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 resdef 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.xt[1] += q.yreturn 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()