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



