座標を回転して異なる座標を求める数式とプログラム
1. 原点からの回転
以下のような半径5の円がある時に点P(5, 0)から90度座標を回転する方法で点P'(0, 5)の座標を求めるプログラムを書く
https://gyazo.com/9d174bead5b3383919b743bb1ce6e3b4
数式
$ P'(x',y') = P(x\cos\theta - y\sin\theta, x\sin\theta + y\cos\theta)
これは下記の行列計算を簡略化したもの
$ P'\Bigl( \begin{matrix} x' \\ y' \end{matrix} \Bigr) = \Bigl( \begin{matrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{matrix} \Bigr)\Bigl( \begin{matrix} x \\ y \end{matrix} \Bigr)
今回はP(5,0)を90度回転させたいので、数式は次のようになる
$ P'(x',y') = P(5\cos90^\circ - 0\sin90^\circ, 5\sin90^\circ + 0\cos90^\circ)
コード
code:rotate1.go
type Point struct {
X, Y float64
}
// angle には 90度回転させたい場合は 90.0 を渡す
func (p Point) Rotate(angle float64) Point {
var (
sin, cos = math.Sincos(angle * math.Pi / 180)
nx = cos*p.X - sin*p.Y
ny = sin*p.X + cos*p.Y
)
p.X = nx
p.Y = ny
return p
}
次の例
2. 原点以外の座標を中心座標とする円の点の回転
以下のような原点をO(4, 4)とする半径4の円がある時に、点P(8, 4)を90度回転する方法で点P'(4, 8)の座標を求めるプログラムを書く
https://gyazo.com/c0ca2ae220cd5394282ce4c7f2e7a271
これをコードで表現するにあたって、先程とは前提条件が異なることに注意する
先程の数式では、明示こそしていなかったものの、原点はO(0, 0)であった
今回の例では原点の座標が異なるため、先程の数式に当てはめるために、それぞれの座標を原点O(0, 0)の位置までスライドし、計算後に座標を再度スライドして戻すことで求める
https://gyazo.com/fc5bbb09ed9c9b1382191ef904b297c1
これをコードで表現すると次のようになる
コード
引数cpにはスライド移動する前の円の中心座標を渡す
code:rotate2.go
// Rotate は任意の角度回転した座標を返す。
// cpは中心座標
func (p Point) Rotate(angle float64, cp Point) Point {
p.X -= cp.X
p.Y -= cp.Y
var (
sin, cos = math.Sincos(angle * math.Pi / 180)
nx = cos*p.X - sin*p.Y
ny = sin*p.X + cos*p.Y
)
p.X = nx + cp.X
p.Y = ny + cp.Y
return p
}
次の例
必須条件
描画する場合は起点となる座標を1つ決定し、それを回転する方法で求める
各頂点には、固有のIDを振り、頂点それぞれを識別できるようにテキストを描画する
注意点
数学の世界では左下が原点であり、X軸については右が正の値、Y軸については上が正の値になっている
プログラムの世界では、ディスプレイやブラウザを見てもわかるかもしれないが、左上が原点になっており、X軸については右が正の値、Y軸については下が正の値になっている
そうでないやつもあった気がするが
よって、前述と同じ感覚でコードを書くと逆方向に回転したSVGが生成されてしまう点に留意する
これを解消するにはp.Rotate(-90.0, cp)という具合に負の値を渡せばよい
以下に