至于我为什么会想要来证明这个呢
最近在看 vue 文档,遇到了一个 vue 的示例点击此跳转


示例抽象:对于一个数据对象,需要根据数据对象的 value 属性 来构建一个雷达图
雷达图:在一个圆周上,平局分出 n 个点,然后把这 n 个点连接起来,对内部进行填充
问题抽象:已知有 n 个点,起始点坐标为 (x_0, y_0) ,求出绕点 (0, 0) 旋转后的终点坐标


# 问题剖分

  1. 既然要平均分成 n 个点,那么每个点的角度增量为 360 / n 度,我们设为 θ
  2. 然后又已知起始点的坐标为 (x_0, y_0)
  3. 那么终点的坐标为 (x_1, y_1)

我们就是要求这个 (x_1, y_1)

# 证明过程(方程联立)

# 条件

  1. 已知起始点坐标为 (x₀, y₀)
  2. 已知旋转角度为 θ

# 目标

  1. 求出绕点 (0, 0) 旋转后的终点坐标 (x₁, y₁)

# 证明

设起始点为 A(x₀, y₀) , 终点为 B(x₁, y₁) , 原点为 O(0, 0)OAOB 的旋转角度为 θOA 的旋转角度为 αOB 的旋转角度为 β ,长度为 r
则有 α + θ = β
sin(β) = sin(α + θ) = sin(α) * cos(θ) + cos(α) * sin(θ)
cos(β) = cos(α + θ) = cos(α) * cos(θ) - sin(α) * sin(θ)
sin(α) = y₀/r,cos(α) = x₀/r,sin(β) = y₁/r,cos(β) = x₁/r
代入上式得:
x₁ = r * cos(β) = r * cos(α + θ) = r * (cos(α) * cos(θ) - sin(α) * sin(θ))
y₁ = r * sin(β) = r * sin(α + θ) = r * (sin(α) * cos(θ) + cos(α) * sin(θ))
x₁ = r * ( (x₀/r) * cos(θ) - (y₀/r) * sin(θ) ) = x₀ * cos(θ) - y₀ * sin(θ)
y₁ = r * ( (y₀/r) * cos(θ) + (x₀/r) * sin(θ) ) = y₀ * cos(θ) + x₀ * sin(θ)
最终可得:
x₁ = x₀ * cos (θ) - y₀ * sin (θ)
y₁ = y₀ * cos (θ) + x₀ * sin (θ)
证毕

# 证明过程(坐标系旋转)

# 条件

  1. 已知起始点坐标为 A(x₀, y₀)
  2. 已知旋转角度为 θ
  3. 原坐标系的单位向量为 (e0_x, e0_y)
  4. 目标坐标系的单位向量为 (e1_x, e1_y)

# 目标

  1. 求坐标系旋转后的终点坐标 B(x₁, y₁) (相对于原坐标系的坐标)

# 证明

  1. 起始点 A 在原坐标系中的向量表达: 向量 A = x₀ × e0_x + y₀ × e0_y
  2. 终点 B 在目标坐标系中的向量表达(坐标不变,坐标系旋转): 向量 B = x₀ × e1_x + y₀ × e1_y
  3. 目标坐标系单位向量与原坐标系的关系(旋转 θ 角推导):
    • e1_x = cos(θ) × e0_x + sin(θ) × e0_y
    • e1_y = -sin (θ) × e0_x + cos (θ) × e0_y
  4. 最终,将 e1_x、e1_y 代入向量 B 的表达式:
    • 向量 B = x₀ × [cos (θ) × e0_x + sin (θ) × e0_y] + y₀ × [-sin (θ) × e0_x + cos (θ) × e0_y]
  5. 展开并按原坐标系单位向量分组:
    • 向量 B = [x₀ × cos (θ) - y₀ × sin (θ)] × e0_x + [x₀ × sin (θ) + y₀ × cos (θ)] × e0_y
  6. 由于向量 B 在原坐标系中的坐标为 (x₁, y₁),对应系数即为坐标值:
    • x₁ = x₀ × cos (θ) - y₀ × sin (θ)
    • y₁ = y₀ × cos (θ) + x₀ × sin (θ)

当然,这个是绕原点旋转的,那么如果要绕另一点旋转,只需要先把坐标平移到原点,旋转后再平移回来即可

# 旋转矩阵

总结上述过程,得到旋转矩阵为:

[ cos(θ)   -sin(θ) ]   ×   [ x₀ ]   =   [ x₀×cos(θ) - y₀×sin(θ) ] = (x₁, y₁)
[ sin(θ)    cos(θ) ]       [ y₀ ]       [ x₀×sin(θ) + y₀×cos(θ) ]

# 源码

这里的,index 是指第几个点,total 是总共有多少个点,这就可以求出雷达图中的每个点的坐标
只是计算过程,非可直接使用的代码,需要根据具体情况进行修改

export function valueToPoint(value, index, total) {
  const x = 0
  const y = 0
  const angle = ((Math.PI * 2) / total) * index
  const cos = Math.cos(angle)
  const sin = Math.sin(angle)
  const tx = x * cos - y * sin
  const ty = x * sin + y * cos
  return {
    x: tx,
    y: ty
  }
}