至于我为什么会想要来证明这个呢
最近在看 vue 文档,遇到了一个 vue 的示例点击此跳转
示例抽象:对于一个数据对象,需要根据数据对象的 value 属性 来构建一个雷达图
雷达图:在一个圆周上,平局分出 n 个点,然后把这 n 个点连接起来,对内部进行填充
问题抽象:已知有 n 个点,起始点坐标为 (x_0, y_0) ,求出绕点 (0, 0) 旋转后的终点坐标
# 问题剖分
- 既然要平均分成 n 个点,那么每个点的角度增量为
360 / n度,我们设为θ - 然后又已知起始点的坐标为
(x_0, y_0) - 那么终点的坐标为
(x_1, y_1)
我们就是要求这个 (x_1, y_1)
# 证明过程(方程联立)
# 条件
- 已知起始点坐标为
(x₀, y₀) - 已知旋转角度为
θ
# 目标
- 求出绕点
(0, 0)旋转后的终点坐标(x₁, y₁)
# 证明
设起始点为 A(x₀, y₀) , 终点为 B(x₁, y₁) , 原点为 O(0, 0) , OA 到 OB 的旋转角度为 θ , 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 (θ)
证毕
# 证明过程(坐标系旋转)
# 条件
- 已知起始点坐标为
A(x₀, y₀) - 已知旋转角度为
θ - 原坐标系的单位向量为
(e0_x, e0_y) - 目标坐标系的单位向量为
(e1_x, e1_y)
# 目标
- 求坐标系旋转后的终点坐标
B(x₁, y₁)(相对于原坐标系的坐标)
# 证明
- 起始点 A 在原坐标系中的向量表达:
向量 A = x₀ × e0_x + y₀ × e0_y - 终点 B 在目标坐标系中的向量表达(坐标不变,坐标系旋转):
向量 B = x₀ × e1_x + y₀ × e1_y - 目标坐标系单位向量与原坐标系的关系(旋转 θ 角推导):
e1_x = cos(θ) × e0_x + sin(θ) × e0_ye1_y = -sin (θ) × e0_x + cos (θ) × e0_y
- 最终,将 e1_x、e1_y 代入向量 B 的表达式:
向量 B = x₀ × [cos (θ) × e0_x + sin (θ) × e0_y] + y₀ × [-sin (θ) × e0_x + cos (θ) × e0_y]
- 展开并按原坐标系单位向量分组:
向量 B = [x₀ × cos (θ) - y₀ × sin (θ)] × e0_x + [x₀ × sin (θ) + y₀ × cos (θ)] × e0_y
- 由于向量 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 | |
} | |
} |