Rで 線形代数:アフィン変換 を試みます。
1. アフィン変換(Affine Transformation)とは
定義
アフィン変換とは、幾何学的な変換の一種で、「線形変換」と「平行移動」を組み合わせたものです。 あるベクトル(または点)v
を、アフィン変換によって新しい点 v'
に移す操作は、以下の数式で表されます。
v' = Mv + t
-
M
: 線形変換を表す行列。回転、拡大・縮小、せん断(歪ませる)などを担当します。 -
t
: 平行移動を表すベクトル。図形全体を特定の位置にずらす操作を担当します。 -
v
: 変換前の点の位置ベクトル。 -
v'
: 変換後の点の位置ベクトル。
線形変換との違い
行列を掛けるだけの線形変換 (v' = Mv
) は、必ず原点 (0,0)
を不動点とします。つまり、原点は動きません。
一方、アフィン変換は平行移動 + t
を含むため、原点を動かすことができます。
これにより、図形を座標空間内の任意の位置に移動させることが可能になり、より自由度の高い変換が実現できます。
アフィン変換の性質
アフィン変換には、変換後も維持されるいくつかの性質があります。
- 直線性: 直線は、変換後も直線のままです。(曲線になったりしない)
- 点の共線性: 一つの直線の上にある3点は、変換後も一つの直線の上にあります。
- 平行性: 平行な直線は、変換後も平行なままです。
- 比の維持: 一つの線分を特定の比で内分する点は、変換後も同じ比で線分を内分します。
簡単に言えば、「図形を引き伸ばしたり、回転させたり、ずらしたりはするが、ぐにゃぐにゃに曲げたりはしない変換」とイメージすると分かりやすいです。
2. Rによるシミュレーション
ここでは、一つの三角形に対して、回転、拡大、平行移動を組み合わせた変換を適用してみます。
Rコード
# --------------------------------------------------
# アフィン変換のシミュレーション
# --------------------------------------------------
# 描画用の関数を定義
<- function(original_shape, M, t) {
plot_affine # Step 1: 線形変換 v_tmp = Mv
<- t(M %*% t(original_shape))
transformed_shape
# Step 2: 平行移動 v' = v_tmp + t
<- sweep(transformed_shape, 2, t, "+")
final_shape
# 描画範囲を自動設定
<- rbind(original_shape, final_shape)
all_points <- range(all_points) * 1.2 + c(-1, 1) # 少し余裕を持たせる
plot_range plot(NULL,
xlim = plot_range, ylim = plot_range,
xlab = "x", ylab = "y", asp = 1,
main = "Affine Transformation (Original -> Final)"
)
# 軸線
abline(h = 0, v = 0, lty = 2, col = "grey")
# 元の図形を描画
polygon(original_shape, col = "#AAAAFF80", border = "blue")
# 変換後の図形を描画
polygon(final_shape, col = "#FFAAAA80", border = "red")
legend("topleft",
legend = c("Original Shape", "Final Shape (Transformed & Translated)"),
fill = c("#AAAAFF80", "#FFAAAA80"),
border = c("blue", "red"),
bty = "n"
)
}
# --- シミュレーションの準備 ---
# 1. 変換対象の図形を定義(三角形の頂点座標)
# 閉じた図形にするため、始点を末尾に再度追加
<- rbind(c(0, 0), c(2, 0), c(1, 2), c(0, 0))
triangle
# --- シナリオ1: 回転 + 平行移動 ---
cat("--- シナリオ1: 回転 + 平行移動 Figure 1 ---\n")
# (a) 線形変換行列 M: 45度回転
<- pi / 4 # 45度をラジアンに変換
theta <- matrix(c(cos(theta), sin(theta), -sin(theta), cos(theta)), nrow = 2)
M1 cat("回転行列 M1:\n")
print(M1)
# (b) 平行移動ベクトル t
<- c(3, 1)
t1 cat("\n平行移動ベクトル t1:", t1, "\n\n")
# シミュレーション実行
plot_affine(triangle, M1, t1)
# --- シナリオ2: 拡大・縮小 + せん断 + 平行移動 ---
cat("--- シナリオ2: 複雑な変換 Figure 2 ---\n")
# (a) 線形変換行列 M: x方向に1.5倍、y方向に0.8倍し、さらに歪ませる
<- matrix(c(1.5, 0.5, 0, 0.8), nrow = 2)
M2 cat("変換行列 M2:\n")
print(M2)
# (b) 平行移動ベクトル t
<- c(-4, 2)
t2 cat("\n平行移動ベクトル t2:", t2, "\n\n")
# シミュレーション実行
plot_affine(triangle, M2, t2)
--- シナリオ1: 回転 + 平行移動 Figure 1 ---
回転行列 M1:
[,1] [,2]
[1,] 0.7071068 -0.7071068
[2,] 0.7071068 0.7071068
平行移動ベクトル t1: 3 1
--- シナリオ2: 複雑な変換 Figure 2 ---
変換行列 M2:
[,1] [,2]
[1,] 1.5 0.0
[2,] 0.5 0.8
平行移動ベクトル t2: -4 2
実行結果と解説
シナリオ1: 回転 + 平行移動 Figure 1
- まず、原点にある青い三角形が、行列
M1
によって原点を中心に45度回転されます。 - 次に、その回転された三角形が、平行移動ベクトル
t1 = (3, 1)
によって、全体が右に3、上に1だけ平行移動し、最終的な赤い三角形の位置に移ります。 - 直線性や平行性(この図形には平行な辺はありませんが)が保たれていることがわかります。
シナリオ2: 複雑な変換 Figure 2
- 青い三角形が行列
M2
によって線形変換されます。M2
は、x方向のスケール変更、y方向のスケール変更、さらにせん断(歪み)を組み合わせた複雑な変換です。 - その歪んだ図形が、平行移動ベクトル
t2 = (-4, 2)
によって、左に4、上に2だけ平行移動し、最終的な赤い図形の位置に移ります。 - このように複雑な変形と移動を組み合わせても、直線が直線のままであるなど、アフィン変換の基本的な性質は維持されています。
以上です。