二維仿射變換筆記
1. 數學基礎
1.1 變換矩陣
二維仿射變換使用3x3的齊次坐標矩陣表示:
[a b tx]
[c d ty]
[0 0 1 ]
其中:
- [a b; c d] 是線性變換部分,表示旋轉、縮放和錯切
- [tx; ty] 是平移部分
- 最后一行 [0 0 1] 是齊次坐標的固定形式
1.2 基本變換
1.2.1 平移變換
將點沿x軸移動tx,沿y軸移動ty:
x' = x + tx
y' = y + ty
變換矩陣:
[1 0 tx]
[0 1 ty]
[0 0 1 ]
1.2.2 旋轉變換
將點繞原點旋轉角度θ:
x' = x·cosθ - y·sinθ
y' = x·sinθ + y·cosθ
變換矩陣:
[cosθ -sinθ 0]
[sinθ cosθ 0]
[0 0 1]
1.2.3 縮放變換
將點沿x軸縮放sx倍,沿y軸縮放sy倍:
x' = sx·x
y' = sy·y
變換矩陣:
[sx 0 0]
[0 sy 0]
[0 0 1]
1.2.4 錯切變換
- 沿x軸錯切:
x' = x + kx·y
y' = y
變換矩陣:
[1 kx 0]
[0 1 0]
[0 0 1]
- 沿y軸錯切:
x' = x
y' = y + ky·x
變換矩陣:
[1 0 0]
[ky 1 0]
[0 0 1]
1.2.5 反射變換
- 關于x軸反射:
x' = x
y' = -y
變換矩陣:
[1 0 0]
[0 -1 0]
[0 0 1]
- 關于y軸反射:
x' = -x
y' = y
變換矩陣:
[-1 0 0]
[0 1 0]
[0 0 1]
- 關于原點反射:
x' = -x
y' = -y
變換矩陣:
[-1 0 0]
[0 -1 0]
[0 0 1]
- 關于直線y = kx反射:
- 先將直線旋轉到x軸
- 關于x軸反射
- 再旋轉回原位置
1.3 復合變換
多個變換的組合通過矩陣乘法實現:
M = M1·M2·...·Mn
注意:變換的順序很重要,通常先縮放,再旋轉,最后平移。
1.4 逆變換
對于可逆變換,其逆變換的矩陣是原矩陣的逆:
M^(-1) = [A^(-1) -A^(-1)·t][0 1 ]
其中A是線性變換部分,t是平移部分。
2. 代碼實現
2.1 頭文件 (affine2d.h)
#ifndef AFFINE2D_H
#define AFFINE2D_H#include <cmath>
#include "point2d.h"
#include "vector2d.h"/*** @brief 二維仿射變換類* * 實現了二維平面中的各種變換,包括:* - 平移變換:將點沿指定方向移動* - 旋轉變換:將點繞原點旋轉* - 縮放變換:將點沿坐標軸縮放* - 錯切變換:將點沿坐標軸錯切* - 反射變換:關于坐標軸、原點或任意直線的反射* - 復合變換:多個變換的組合*/
class Affine2D {
public:/*** @brief 默認構造函數,創建單位變換* * 單位變換的矩陣為:* [1 0 0]* [0 1 0]* [0 0 1]*/Affine2D();/*** @brief 使用矩陣元素構造變換* @param a,b,c,d 線性變換部分的4個元素* @param tx,ty 平移部分的2個元素*/Affine2D(double a, double b, double c, double d, double tx, double ty);/*** @brief 創建平移變換* @param tx x方向平移量* @param ty y方向平移量* @return 平移變換*/static Affine2D translation(double tx, double ty);/*** @brief 創建旋轉變換* @param angle 旋轉角度(弧度)* @return 旋轉變換*/static Affine2D rotation(double angle);/*** @brief 創建縮放變換* @param sx x方向縮放因子* @param sy y方向縮放因子* @return 縮放變換* @throw std::invalid_argument 當縮放因子為0時拋出*/static Affine2D scaling(double sx, double sy);/*** @brief 創建沿x軸的錯切變換* @param kx x方向錯切因子* @return 錯切變換*/static Affine2D shearX(double kx);/*** @brief 創建沿y軸的錯切變換* @param ky y方向錯切因子* @return 錯切變換*/static Affine2D shearY(double ky);/*** @brief 創建關于x軸的反射變換* @return 反射變換*/static Affine2D reflectionX();/*** @brief 創建關于y軸的反射變換* @return 反射變換*/static Affine2D reflectionY();/*** @brief 創建關于原點的反射變換* @return 反射變換*/static Affine2D reflectionOrigin();/*** @brief 創建關于直線的反射變換* @param k 直線斜率* @return 反射變換*/static Affine2D reflection(double k);/*** @brief 變換點* @param point 要變換的點* @return 變換后的點*/Point2D transform(const Point2D& point) const;/*** @brief 變換向量* @param vector 要變換的向量* @return 變換后的向量*/Vector2D transform(const Vector2D& vector) const;/*** @brief 與另一個變換組合* @param other 另一個變換* @return 組合后的變換*/Affine2D compose(const Affine2D& other) const;/*** @brief 求逆變換* @return 逆變換* @throw std::runtime_error 當變換不可逆時拋出*/Affine2D inverse() const;// 屬性訪問器double getA() const { return a; }double getB() const { return b; }double getC() const { return c; }double getD() const { return d; }double getTx() const { return tx; }double getTy() const { return ty; }private:double a, b; // 線性變換部分的第一行double c, d; // 線性變換部分的第二行double tx, ty