123456789101112131415161718192021222324252627282930313233343536373839404142434445 |
"""演示11: 齐次变换矩阵 — 平移/旋转/缩放 + 复合变换。
2D 演示: 一个三角形依次经过 旋转 -> 缩放 -> 平移 三个变换,
说明齐次坐标如何把三种变换统一成矩阵乘法。
"""
import os
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
from figure_style import figures_dir, configure
configure()
OUT = figures_dir()
os.makedirs(OUT, exist_ok=True)
# 齐次坐标: 三角形顶点 (x, y, 1)
tri = np.array([[0., 0., 1.], [2., 0., 1.], [0., 1., 1.]])
theta = np.radians(45)
R = np.array([[np.cos(theta), -np.sin(theta), 0],
[np.sin(theta), np.cos(theta), 0],
[0, 0, 1]]) # 旋转
S = np.array([[1.5, 0, 0], [0, 0.5, 0], [0, 0, 1]]) # 缩放
T = np.array([[1, 0, 3], [0, 1, 2], [0, 0, 1]]) # 平移
steps = [("原始", tri, "tab:gray"),
("旋转 45°", R @ tri, "tab:blue"),
("旋转+缩放", S @ R @ tri, "tab:orange"),
("旋转+缩放+平移", T @ S @ R @ tri, "tab:green")]
fig, ax = plt.subplots(figsize=(8, 8))
for name, pts, color in steps:
xy = pts[:2].T
ax.add_patch(Polygon(xy, closed=True, fill=False, ec=color, lw=2, label=name))
ax.plot(*xy, ".", c=color, ms=6)
ax.set_title("齐次变换矩阵: 复合变换 = 矩阵连乘 (T·S·R·p)", fontsize=13)
ax.set_xlim(-1, 6); ax.set_ylim(-1, 4)
ax.set_aspect("equal"); ax.grid(alpha=0.3); ax.legend(fontsize=9)
fig.tight_layout()
out = os.path.join(OUT, "fig_cg_transforms.png")
fig.savefig(out, dpi=150)
print("复合变换 T·S·R = \n", T @ S @ R)
print(f"-> {out}")
|