9-1 二维旋转与缩放矩阵

二维旋转与缩放矩阵(2D Rotation and Scale Matrices)

二维线性变换(Linear Transformation)是通过矩阵乘法(Matrix Multiplication)对平面上的点进行变换的操作。给定一个二维点 (x, y),将其与一个 2x2 矩阵相乘即可完成变换。其中,旋转(Rotation)和缩放(Scaling)是计算机图形学(Computer Graphics)、游戏开发(Game Development)和机器人学(Robotics)中最基础的两个操作。

本文将依次介绍二维缩放矩阵、二维旋转矩阵、矩阵乘法、组合变换,并给出 C++、C、Python、Go 四种语言的完整实现。


二维缩放矩阵(Scale Matrix)

缩放矩阵用于沿坐标轴方向拉伸或压缩图形。二维缩放矩阵的形式为:

S = | sx  0 |
    | 0  sy |

其中 sx 控制 x 轴方向的缩放,sy 控制 y 轴方向的缩放。

  • 等比缩放(Uniform Scaling):当 sx = sy 时,图形在两个方向上等比例缩放。
  • 非等比缩放(Non-uniform Scaling):当 sx ≠ sy 时,图形在两个方向上缩放比例不同,可能导致变形。

对点 (x, y) 进行缩放:

| sx  0 | × | x |   | sx * x |
| 0  sy |   | y | = | sy * y |

例如,将点 (3, 2) 以 sx=2, sy=3 进行缩放:

| 2  0 | × | 3 |   | 6 |
| 0  3 |   | 2 | = | 6 |

C++ 实现

#include <iostream>
#include <iomanip>
#include <cmath>

// apply scale matrix to point (x, y)
void scale(double x, double y, double sx, double sy)
{
    double nx = sx * x;
    double ny = sy * y;
    std::cout << std::fixed << std::setprecision(2);
    std::cout << "Scale(" << x << ", " << y << ") by ("
              << sx << ", " << sy << ") -> ("
              << nx << ", " << ny << ")\n";
}

int main()
{
    // test cases
    scale(3.0, 2.0, 2.0, 3.0);
    scale(1.0, 1.0, 2.0, 2.0);
    scale(5.0, 4.0, 0.5, 0.5);
    scale(2.0, 3.0, 1.0, 1.0);
    return 0;
}

运行该程序将输出

Scale(3.00, 2.00) by (2.00, 3.00) -> (6.00, 6.00)
Scale(1.00, 1.00) by (2.00, 2.00) -> (2.00, 2.00)
Scale(5.00, 4.00) by (0.50, 0.50) -> (2.50, 2.00)
Scale(2.00, 3.00) by (1.00, 1.00) -> (2.00, 3.00)

C 实现

#include <stdio.h>

// apply scale matrix to point (x, y)
void scale(double x, double y, double sx, double sy)
{
    double nx = sx * x;
    double ny = sy * y;
    printf("Scale(%.2f, %.2f) by (%.2f, %.2f) -> (%.2f, %.2f)\n",
           x, y, sx, sy, nx, ny);
}

int main()
{
    // test cases
    scale(3.0, 2.0, 2.0, 3.0);
    scale(1.0, 1.0, 2.0, 2.0);
    scale(5.0, 4.0, 0.5, 0.5);
    scale(2.0, 3.0, 1.0, 1.0);
    return 0;
}

运行该程序将输出

Scale(3.00, 2.00) by (2.00, 3.00) -> (6.00, 6.00)
Scale(1.00, 1.00) by (2.00, 2.00) -> (2.00, 2.00)
Scale(5.00, 4.00) by (0.50, 0.50) -> (2.50, 2.00)
Scale(2.00, 3.00) by (1.00, 1.00) -> (2.00, 3.00)

Python 实现

def scale(x, y, sx, sy):
    # apply scale matrix to point (x, y)
    nx = sx * x
    ny = sy * y
    print(f"Scale({x:.2f}, {y:.2f}) by ({sx:.2f}, {sy:.2f}) -> ({nx:.2f}, {ny:.2f})")

# test cases
scale(3.0, 2.0, 2.0, 3.0)
scale(1.0, 1.0, 2.0, 2.0)
scale(5.0, 4.0, 0.5, 0.5)
scale(2.0, 3.0, 1.0, 1.0)

运行该程序将输出

Scale(3.00, 2.00) by (2.00, 3.00) -> (6.00, 6.00)
Scale(1.00, 1.00) by (2.00, 2.00) -> (2.00, 2.00)
Scale(5.00, 4.00) by (0.50, 0.50) -> (2.50, 2.00)
Scale(2.00, 3.00) by (1.00, 1.00) -> (2.00, 3.00)

Go 实现

package main

import "fmt"

// apply scale matrix to point (x, y)
func scale(x, y, sx, sy float64) {
	nx := sx * x
	ny := sy * y
	fmt.Printf("Scale(%.2f, %.2f) by (%.2f, %.2f) -> (%.2f, %.2f)\n",
		x, y, sx, sy, nx, ny)
}

func main() {
	// test cases
	scale(3.0, 2.0, 2.0, 3.0)
	scale(1.0, 1.0, 2.0, 2.0)
	scale(5.0, 4.0, 0.5, 0.5)
	scale(2.0, 3.0, 1.0, 1.0)
}

运行该程序将输出

Scale(3.00, 2.00) by (2.00, 3.00) -> (6.00, 6.00)
Scale(1.00, 1.00) by (2.00, 2.00) -> (2.00, 2.00)
Scale(5.00, 4.00) by (0.50, 0.50) -> (2.50, 2.00)
Scale(2.00, 3.00) by (1.00, 1.00) -> (2.00, 3.00)

缩放变换的实现非常直观:将 x 分量乘以 sx,y 分量乘以 sy。当 sx 和 sy 都为 1 时,点不发生变化;当它们小于 1 时,图形缩小;大于 1 时,图形放大。


二维旋转矩阵(Rotation Matrix)

旋转矩阵将点绕原点旋转指定角度。逆时针旋转角度 θ 的矩阵形式为:

R = | cosθ  -sinθ |
    | sinθ   cosθ |

这个公式可以从单位圆(Unit Circle)推导出来:将点 (1, 0) 旋转 θ 角得到 (cosθ, sinθ),将点 (0, 1) 旋转 θ 角得到 (-sinθ, cosθ),这两列向量构成了旋转矩阵。

一些特殊角度对应的旋转矩阵:

θ = 90°:  | 0 -1 |    θ = 180°: | -1  0 |    θ = 270°: |  0  1 |
          | 1  0 |               |  0 -1 |               | -1  0 |

验证示例:

  • 将点 (1, 0) 旋转 90°:(0×1 + (-1)×0, 1×1 + 0×0) = (0, 1)
  • 将点 (1, 1) 旋转 45°:(cos45°×1 + (-sin45°)×1, sin45°×1 + cos45°×1) = (0, √2)

C++ 实现

#include <iostream>
#include <iomanip>
#include <cmath>

// convert degrees to radians
double toRadians(double degrees)
{
    return degrees * M_PI / 180.0;
}

// rotate point (x, y) by angle (in degrees) counterclockwise
void rotate(double x, double y, double degrees)
{
    double rad = toRadians(degrees);
    double nx = cos(rad) * x - sin(rad) * y;
    double ny = sin(rad) * x + cos(rad) * y;
    std::cout << std::fixed << std::setprecision(4);
    std::cout << "Rotate(" << x << ", " << y << ") by "
              << degrees << " deg -> ("
              << nx << ", " << ny << ")\n";
}

int main()
{
    // test with different angles
    rotate(1.0, 0.0, 30.0);
    rotate(1.0, 0.0, 45.0);
    rotate(1.0, 0.0, 90.0);
    rotate(1.0, 0.0, 180.0);
    return 0;
}

运行该程序将输出

Rotate(1.0000, 0.0000) by 30.0000 deg -> (0.8660, 0.5000)
Rotate(1.0000, 0.0000) by 45.0000 deg -> (0.7071, 0.7071)
Rotate(1.0000, 0.0000) by 90.0000 deg -> (0.0000, 1.0000)
Rotate(1.0000, 0.0000) by 180.0000 deg -> (-1.0000, 0.0000)

C 实现

#include <stdio.h>
#include <math.h>

// convert degrees to radians
double toRadians(double degrees)
{
    return degrees * M_PI / 180.0;
}

// rotate point (x, y) by angle (in degrees) counterclockwise
void rotate(double x, double y, double degrees)
{
    double rad = toRadians(degrees);
    double nx = cos(rad) * x - sin(rad) * y;
    double ny = sin(rad) * x + cos(rad) * y;
    printf("Rotate(%.4f, %.4f) by %.4f deg -> (%.4f, %.4f)\n",
           x, y, degrees, nx, ny);
}

int main()
{
    // test with different angles
    rotate(1.0, 0.0, 30.0);
    rotate(1.0, 0.0, 45.0);
    rotate(1.0, 0.0, 90.0);
    rotate(1.0, 0.0, 180.0);
    return 0;
}

运行该程序将输出

Rotate(1.0000, 0.0000) by 30.0000 deg -> (0.8660, 0.5000)
Rotate(1.0000, 0.0000) by 45.0000 deg -> (0.7071, 0.7071)
Rotate(1.0000, 0.0000) by 90.0000 deg -> (0.0000, 1.0000)
Rotate(1.0000, 0.0000) by 180.0000 deg -> (-1.0000, 0.0000)

Python 实现

import math

def rotate(x, y, degrees):
    # convert degrees to radians
    rad = math.radians(degrees)
    # rotate point (x, y) by angle counterclockwise
    nx = math.cos(rad) * x - math.sin(rad) * y
    ny = math.sin(rad) * x + math.cos(rad) * y
    print(f"Rotate({x:.4f}, {y:.4f}) by {degrees:.4f} deg -> ({nx:.4f}, {ny:.4f})")

# test with different angles
rotate(1.0, 0.0, 30.0)
rotate(1.0, 0.0, 45.0)
rotate(1.0, 0.0, 90.0)
rotate(1.0, 0.0, 180.0)

运行该程序将输出

Rotate(1.0000, 0.0000) by 30.0000 deg -> (0.8660, 0.5000)
Rotate(1.0000, 0.0000) by 45.0000 deg -> (0.7071, 0.7071)
Rotate(1.0000, 0.0000) by 90.0000 deg -> (0.0000, 1.0000)
Rotate(1.0000, 0.0000) by 180.0000 deg -> (-1.0000, 0.0000)

Go 实现

package main

import (
	"fmt"
	"math"
)

// convert degrees to radians
func toRadians(degrees float64) float64 {
	return degrees * math.Pi / 180.0
}

// rotate point (x, y) by angle (in degrees) counterclockwise
func rotate(x, y, degrees float64) {
	rad := toRadians(degrees)
	nx := math.Cos(rad)*x - math.Sin(rad)*y
	ny := math.Sin(rad)*x + math.Cos(rad)*y
	fmt.Printf("Rotate(%.4f, %.4f) by %.4f deg -> (%.4f, %.4f)\n",
		x, y, degrees, nx, ny)
}

func main() {
	// test with different angles
	rotate(1.0, 0.0, 30.0)
	rotate(1.0, 0.0, 45.0)
	rotate(1.0, 0.0, 90.0)
	rotate(1.0, 0.0, 180.0)
}

运行该程序将输出

Rotate(1.0000, 0.0000) by 30.0000 deg -> (0.8660, 0.5000)
Rotate(1.0000, 0.0000) by 45.0000 deg -> (0.7071, 0.7071)
Rotate(1.0000, 0.0000) by 90.0000 deg -> (0.0000, 1.0000)
Rotate(1.0000, 0.0000) by 180.0000 deg -> (-1.0000, 0.0000)

旋转矩阵中,角度需要从度数转换为弧度,C/C++ 使用 M_PI,Go 使用 math.Pi,Python 使用 math.pi。将点 (1, 0) 分别旋转 30°、45°、90°、180°,可以验证旋转矩阵的正确性:90° 旋转后点落在了 (0, 1) 上,180° 旋转后点落在了 (-1, 0) 上。


矩阵乘法(Matrix Multiplication)

矩阵乘法是组合变换的基础。我们先看 2x2 矩阵与 2x1 向量(Vector)的乘法,再看两个 2x2 矩阵的乘法。

2x2 矩阵乘 2x1 向量

| a  b | × | x |   | ax + by |
| c  d |   | y | = | cx + dy |

2x2 矩阵乘 2x2 矩阵

| a  b | × | e  f |   | ae + bg   af + bh |
| c  d |   | g  h | = | ce + dg   cf + dh |

逐步示例:

| 2  1 | × | 3 |   | 2*3 + 1*4 |   | 10 |
| 0  3 |   | 4 | = | 0*3 + 3*4 | = | 12 |

C++ 实现

#include <iostream>
#include <iomanip>

// 2x2 matrix type
struct Matrix2x2
{
    double m[2][2];
};

// 2x1 vector type
struct Vector2
{
    double v[2];
};

// multiply 2x2 matrix by 2x1 vector
Vector2 matVecMul(const Matrix2x2& mat, const Vector2& vec)
{
    Vector2 result;
    result.v[0] = mat.m[0][0] * vec.v[0] + mat.m[0][1] * vec.v[1];
    result.v[1] = mat.m[1][0] * vec.v[0] + mat.m[1][1] * vec.v[1];
    return result;
}

// multiply two 2x2 matrices
Matrix2x2 matMul(const Matrix2x2& a, const Matrix2x2& b)
{
    Matrix2x2 result;
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            result.m[i][j] = 0;
            for (int k = 0; k < 2; k++)
            {
                result.m[i][j] += a.m[i][k] * b.m[k][j];
            }
        }
    }
    return result;
}

// print a 2x2 matrix
void printMatrix(const Matrix2x2& mat)
{
    std::cout << std::fixed << std::setprecision(4);
    std::cout << "|" << mat.m[0][0] << "  " << mat.m[0][1] << "|\n";
    std::cout << "|" << mat.m[1][0] << "  " << mat.m[1][1] << "|\n";
}

int main()
{
    // matrix-vector multiplication
    Matrix2x2 mat = {{{2.0, 1.0}, {0.0, 3.0}}};
    Vector2 vec = {{3.0, 4.0}};
    Vector2 result = matVecMul(mat, vec);

    std::cout << "Matrix-Vector multiply:\n";
    std::cout << "|" << mat.m[0][0] << "  " << mat.m[0][1] << "| x |"
              << vec.v[0] << "| = |" << result.v[0] << "|\n";
    std::cout << "|" << mat.m[1][0] << "  " << mat.m[1][1] << "|   |"
              << vec.v[1] << "|   |" << result.v[1] << "|\n\n";

    // matrix-matrix multiplication
    Matrix2x2 a = {{{1.0, 2.0}, {3.0, 4.0}}};
    Matrix2x2 b = {{{5.0, 6.0}, {7.0, 8.0}}};
    Matrix2x2 c = matMul(a, b);

    std::cout << "Matrix-Matrix multiply:\n";
    std::cout << "A x B =\n";
    printMatrix(c);

    return 0;
}

运行该程序将输出

Matrix-Vector multiply:
|2.0000  1.0000| x |3.0000| = |10.0000|
|0.0000  3.0000|   |4.0000|   |12.0000|

Matrix-Matrix multiply:
A x B =
|19.0000  22.0000|
|43.0000  50.0000|

C 实现

#include <stdio.h>

// 2x2 matrix type
typedef struct
{
    double m[2][2];
} Matrix2x2;

// 2x1 vector type
typedef struct
{
    double v[2];
} Vector2;

// multiply 2x2 matrix by 2x1 vector
Vector2 matVecMul(const Matrix2x2* mat, const Vector2* vec)
{
    Vector2 result;
    result.v[0] = mat->m[0][0] * vec->v[0] + mat->m[0][1] * vec->v[1];
    result.v[1] = mat->m[1][0] * vec->v[0] + mat->m[1][1] * vec->v[1];
    return result;
}

// multiply two 2x2 matrices
Matrix2x2 matMul(const Matrix2x2* a, const Matrix2x2* b)
{
    Matrix2x2 result;
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            result.m[i][j] = 0;
            for (int k = 0; k < 2; k++)
            {
                result.m[i][j] += a->m[i][k] * b->m[k][j];
            }
        }
    }
    return result;
}

// print a 2x2 matrix
void printMatrix(const Matrix2x2* mat)
{
    printf("|%.4f  %.4f|\n", mat->m[0][0], mat->m[0][1]);
    printf("|%.4f  %.4f|\n", mat->m[1][0], mat->m[1][1]);
}

int main()
{
    // matrix-vector multiplication
    Matrix2x2 mat = {{{2.0, 1.0}, {0.0, 3.0}}};
    Vector2 vec = {{3.0, 4.0}};
    Vector2 result = matVecMul(&mat, &vec);

    printf("Matrix-Vector multiply:\n");
    printf("|%.4f  %.4f| x |%.4f| = |%.4f|\n",
           mat.m[0][0], mat.m[0][1], vec.v[0], result.v[0]);
    printf("|%.4f  %.4f|   |%.4f|   |%.4f|\n\n",
           mat.m[1][0], mat.m[1][1], vec.v[1], result.v[1]);

    // matrix-matrix multiplication
    Matrix2x2 a = {{{1.0, 2.0}, {3.0, 4.0}}};
    Matrix2x2 b = {{{5.0, 6.0}, {7.0, 8.0}}};
    Matrix2x2 c = matMul(&a, &b);

    printf("Matrix-Matrix multiply:\n");
    printf("A x B =\n");
    printMatrix(&c);

    return 0;
}

运行该程序将输出

Matrix-Vector multiply:
|2.0000  1.0000| x |3.0000| = |10.0000|
|0.0000  3.0000|   |4.0000|   |12.0000|

Matrix-Matrix multiply:
A x B =
|19.0000  22.0000|
|43.0000  50.0000|

Python 实现

def mat_vec_mul(mat, vec):
    """multiply 2x2 matrix by 2x1 vector"""
    return [
        mat[0][0] * vec[0] + mat[0][1] * vec[1],
        mat[1][0] * vec[0] + mat[1][1] * vec[1],
    ]

def mat_mul(a, b):
    """multiply two 2x2 matrices"""
    result = [[0.0, 0.0], [0.0, 0.0]]
    for i in range(2):
        for j in range(2):
            for k in range(2):
                result[i][j] += a[i][k] * b[k][j]
    return result

def print_matrix(mat):
    """print a 2x2 matrix"""
    print(f"|{mat[0][0]:.4f}  {mat[0][1]:.4f}|")
    print(f"|{mat[1][0]:.4f}  {mat[1][1]:.4f}|")

# matrix-vector multiplication
mat = [[2.0, 1.0], [0.0, 3.0]]
vec = [3.0, 4.0]
result = mat_vec_mul(mat, vec)

print("Matrix-Vector multiply:")
print(f"|{mat[0][0]:.4f}  {mat[0][1]:.4f}| x |{vec[0]:.4f}| = |{result[0]:.4f}|")
print(f"|{mat[1][0]:.4f}  {mat[1][1]:.4f}|   |{vec[1]:.4f}|   |{result[1]:.4f}|")
print()

# matrix-matrix multiplication
a = [[1.0, 2.0], [3.0, 4.0]]
b = [[5.0, 6.0], [7.0, 8.0]]
c = mat_mul(a, b)

print("Matrix-Matrix multiply:")
print("A x B =")
print_matrix(c)

运行该程序将输出

Matrix-Vector multiply:
|2.0000  1.0000| x |3.0000| = |10.0000|
|0.0000  3.0000|   |4.0000|   |12.0000|

Matrix-Matrix multiply:
A x B =
|19.0000  22.0000|
|43.0000  50.0000|

Go 实现

package main

import "fmt"

// 2x2 matrix type
type Matrix2x2 struct {
	M [2][2]float64
}

// 2x1 vector type
type Vector2 struct {
	V [2]float64
}

// multiply 2x2 matrix by 2x1 vector
func matVecMul(mat Matrix2x2, vec Vector2) Vector2 {
	return Vector2{
		V: [2]float64{
			mat.M[0][0]*vec.V[0] + mat.M[0][1]*vec.V[1],
			mat.M[1][0]*vec.V[0] + mat.M[1][1]*vec.V[1],
		},
	}
}

// multiply two 2x2 matrices
func matMul(a, b Matrix2x2) Matrix2x2 {
	var result Matrix2x2
	for i := 0; i < 2; i++ {
		for j := 0; j < 2; j++ {
			result.M[i][j] = 0
			for k := 0; k < 2; k++ {
				result.M[i][j] += a.M[i][k] * b.M[k][j]
			}
		}
	}
	return result
}

// print a 2x2 matrix
func printMatrix(mat Matrix2x2) {
	fmt.Printf("|%.4f  %.4f|\n", mat.M[0][0], mat.M[0][1])
	fmt.Printf("|%.4f  %.4f|\n", mat.M[1][0], mat.M[1][1])
}

func main() {
	// matrix-vector multiplication
	mat := Matrix2x2{M: [2][2]float64{{2.0, 1.0}, {0.0, 3.0}}}
	vec := Vector2{V: [2]float64{3.0, 4.0}}
	result := matVecMul(mat, vec)

	fmt.Println("Matrix-Vector multiply:")
	fmt.Printf("|%.4f  %.4f| x |%.4f| = |%.4f|\n",
		mat.M[0][0], mat.M[0][1], vec.V[0], result.V[0])
	fmt.Printf("|%.4f  %.4f|   |%.4f|   |%.4f|\n\n",
		mat.M[1][0], mat.M[1][1], vec.V[1], result.V[1])

	// matrix-matrix multiplication
	a := Matrix2x2{M: [2][2]float64{{1.0, 2.0}, {3.0, 4.0}}}
	b := Matrix2x2{M: [2][2]float64{{5.0, 6.0}, {7.0, 8.0}}}
	c := matMul(a, b)

	fmt.Println("Matrix-Matrix multiply:")
	fmt.Println("A x B =")
	printMatrix(c)
}

运行该程序将输出

Matrix-Vector multiply:
|2.0000  1.0000| x |3.0000| = |10.0000|
|0.0000  3.0000|   |4.0000|   |12.0000|

Matrix-Matrix multiply:
A x B =
|19.0000  22.0000|
|43.0000  50.0000|

矩阵乘法是线性代数的核心操作。矩阵-向量乘法用于将变换应用到点上,矩阵-矩阵乘法用于组合多个变换。注意 2x2 矩阵乘法的结果仍然是 2x2 矩阵,其每个元素是对应行和列的点积(Dot Product)。


组合变换(Combining Transformations)

多个变换可以通过矩阵乘法组合为单个矩阵。但需要注意:矩阵乘法不满足交换律(Non-commutative),即 A x B ≠ B x A,因此变换的顺序至关重要。

对点 p 先缩放 S 再旋转 R 的组合为:R x S x p(从右向左应用)

对点 p 先旋转 R 再缩放 S 的组合为:S x R x p(从右向左应用)

这两种顺序会产生不同的结果。我们通过具体示例来验证:

  • 缩放 sx=2, sy=3,旋转 45°,应用到点 (1, 1)
  • 先缩放:(1, 1) -> (2, 3),再旋转 45°
  • 先旋转 45°:(1, 1) -> (0, √2),再缩放 sx=2, sy=3

C++ 实现

#include <iostream>
#include <iomanip>
#include <cmath>

// 2x2 matrix type
struct Matrix2x2
{
    double m[2][2];
};

// 2x1 vector type
struct Vector2
{
    double v[2];
};

// multiply 2x2 matrix by 2x1 vector
Vector2 matVecMul(const Matrix2x2& mat, const Vector2& vec)
{
    Vector2 result;
    result.v[0] = mat.m[0][0] * vec.v[0] + mat.m[0][1] * vec.v[1];
    result.v[1] = mat.m[1][0] * vec.v[0] + mat.m[1][1] * vec.v[1];
    return result;
}

// multiply two 2x2 matrices
Matrix2x2 matMul(const Matrix2x2& a, const Matrix2x2& b)
{
    Matrix2x2 result;
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            result.m[i][j] = 0;
            for (int k = 0; k < 2; k++)
            {
                result.m[i][j] += a.m[i][k] * b.m[k][j];
            }
        }
    }
    return result;
}

// create scale matrix
Matrix2x2 scaleMatrix(double sx, double sy)
{
    Matrix2x2 mat = {{{sx, 0}, {0, sy}}};
    return mat;
}

// create rotation matrix (angle in degrees)
Matrix2x2 rotationMatrix(double degrees)
{
    double rad = degrees * M_PI / 180.0;
    Matrix2x2 mat = {{{cos(rad), -sin(rad)}, {sin(rad), cos(rad)}}};
    return mat;
}

int main()
{
    Vector2 p = {{1.0, 1.0}};
    double sx = 2.0, sy = 3.0;
    double angle = 45.0;

    Matrix2x2 S = scaleMatrix(sx, sy);
    Matrix2x2 R = rotationMatrix(angle);

    // scale then rotate: R x S x p
    Matrix2x2 RS = matMul(R, S);
    Vector2 result1 = matVecMul(RS, p);

    // rotate then scale: S x R x p
    Matrix2x2 SR = matMul(S, R);
    Vector2 result2 = matVecMul(SR, p);

    std::cout << std::fixed << std::setprecision(4);
    std::cout << "Point: (1, 1), Scale(2, 3), Rotate(45 deg)\n\n";
    std::cout << "Scale then Rotate (R x S x p): ("
              << result1.v[0] << ", " << result1.v[1] << ")\n";
    std::cout << "Rotate then Scale (S x R x p): ("
              << result2.v[0] << ", " << result2.v[1] << ")\n";
    std::cout << "\nResults are different: order matters!\n";

    return 0;
}

运行该程序将输出

Point: (1, 1), Scale(2, 3), Rotate(45 deg)

Scale then Rotate (R x S x p): (-0.7071, 3.5355)
Rotate then Scale (S x R x p): (0.0000, 4.2426)

Results are different: order matters!

C 实现

#include <stdio.h>
#include <math.h>

// 2x2 matrix type
typedef struct
{
    double m[2][2];
} Matrix2x2;

// 2x1 vector type
typedef struct
{
    double v[2];
} Vector2;

// multiply 2x2 matrix by 2x1 vector
Vector2 matVecMul(const Matrix2x2* mat, const Vector2* vec)
{
    Vector2 result;
    result.v[0] = mat->m[0][0] * vec->v[0] + mat->m[0][1] * vec->v[1];
    result.v[1] = mat->m[1][0] * vec->v[0] + mat->m[1][1] * vec->v[1];
    return result;
}

// multiply two 2x2 matrices
Matrix2x2 matMul(const Matrix2x2* a, const Matrix2x2* b)
{
    Matrix2x2 result;
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            result.m[i][j] = 0;
            for (int k = 0; k < 2; k++)
            {
                result.m[i][j] += a->m[i][k] * b->m[k][j];
            }
        }
    }
    return result;
}

// create scale matrix
Matrix2x2 scaleMatrix(double sx, double sy)
{
    Matrix2x2 mat = {{{sx, 0}, {0, sy}}};
    return mat;
}

// create rotation matrix (angle in degrees)
Matrix2x2 rotationMatrix(double degrees)
{
    double rad = degrees * M_PI / 180.0;
    Matrix2x2 mat = {{{cos(rad), -sin(rad)}, {sin(rad), cos(rad)}}};
    return mat;
}

int main()
{
    Vector2 p = {{1.0, 1.0}};
    double sx = 2.0, sy = 3.0;
    double angle = 45.0;

    Matrix2x2 S = scaleMatrix(sx, sy);
    Matrix2x2 R = rotationMatrix(angle);

    // scale then rotate: R x S x p
    Matrix2x2 RS = matMul(&R, &S);
    Vector2 result1 = matVecMul(&RS, &p);

    // rotate then scale: S x R x p
    Matrix2x2 SR = matMul(&S, &R);
    Vector2 result2 = matVecMul(&SR, &p);

    printf("Point: (1, 1), Scale(2, 3), Rotate(45 deg)\n\n");
    printf("Scale then Rotate (R x S x p): (%.4f, %.4f)\n",
           result1.v[0], result1.v[1]);
    printf("Rotate then Scale (S x R x p): (%.4f, %.4f)\n",
           result2.v[0], result2.v[1]);
    printf("\nResults are different: order matters!\n");

    return 0;
}

运行该程序将输出

Point: (1, 1), Scale(2, 3), Rotate(45 deg)

Scale then Rotate (R x S x p): (-0.7071, 3.5355)
Rotate then Scale (S x R x p): (0.0000, 4.2426)

Results are different: order matters!

Python 实现

import math

def mat_vec_mul(mat, vec):
    """multiply 2x2 matrix by 2x1 vector"""
    return [
        mat[0][0] * vec[0] + mat[0][1] * vec[1],
        mat[1][0] * vec[0] + mat[1][1] * vec[1],
    ]

def mat_mul(a, b):
    """multiply two 2x2 matrices"""
    result = [[0.0, 0.0], [0.0, 0.0]]
    for i in range(2):
        for j in range(2):
            for k in range(2):
                result[i][j] += a[i][k] * b[k][j]
    return result

def scale_matrix(sx, sy):
    """create scale matrix"""
    return [[sx, 0.0], [0.0, sy]]

def rotation_matrix(degrees):
    """create rotation matrix (angle in degrees)"""
    rad = math.radians(degrees)
    return [[math.cos(rad), -math.sin(rad)],
            [math.sin(rad),  math.cos(rad)]]

p = [1.0, 1.0]
sx, sy = 2.0, 3.0
angle = 45.0

S = scale_matrix(sx, sy)
R = rotation_matrix(angle)

# scale then rotate: R x S x p
RS = mat_mul(R, S)
result1 = mat_vec_mul(RS, p)

# rotate then scale: S x R x p
SR = mat_mul(S, R)
result2 = mat_vec_mul(SR, p)

print("Point: (1, 1), Scale(2, 3), Rotate(45 deg)\n")
print(f"Scale then Rotate (R x S x p): ({result1[0]:.4f}, {result1[1]:.4f})")
print(f"Rotate then Scale (S x R x p): ({result2[0]:.4f}, {result2[1]:.4f})")
print("\nResults are different: order matters!")

运行该程序将输出

Point: (1, 1), Scale(2, 3), Rotate(45 deg)

Scale then Rotate (R x S x p): (-0.7071, 3.5355)
Rotate then Scale (S x R x p): (0.0000, 4.2426)

Results are different: order matters!

Go 实现

package main

import (
	"fmt"
	"math"
)

// 2x2 matrix type
type Matrix2x2 struct {
	M [2][2]float64
}

// 2x1 vector type
type Vector2 struct {
	V [2]float64
}

// multiply 2x2 matrix by 2x1 vector
func matVecMul(mat Matrix2x2, vec Vector2) Vector2 {
	return Vector2{
		V: [2]float64{
			mat.M[0][0]*vec.V[0] + mat.M[0][1]*vec.V[1],
			mat.M[1][0]*vec.V[0] + mat.M[1][1]*vec.V[1],
		},
	}
}

// multiply two 2x2 matrices
func matMul(a, b Matrix2x2) Matrix2x2 {
	var result Matrix2x2
	for i := 0; i < 2; i++ {
		for j := 0; j < 2; j++ {
			result.M[i][j] = 0
			for k := 0; k < 2; k++ {
				result.M[i][j] += a.M[i][k] * b.M[k][j]
			}
		}
	}
	return result
}

// create scale matrix
func scaleMatrix(sx, sy float64) Matrix2x2 {
	return Matrix2x2{M: [2][2]float64{{sx, 0}, {0, sy}}}
}

// create rotation matrix (angle in degrees)
func rotationMatrix(degrees float64) Matrix2x2 {
	rad := degrees * math.Pi / 180.0
	return Matrix2x2{M: [2][2]float64{
		{math.Cos(rad), -math.Sin(rad)},
		{math.Sin(rad), math.Cos(rad)},
	}}
}

func main() {
	p := Vector2{V: [2]float64{1.0, 1.0}}
	sx, sy := 2.0, 3.0
	angle := 45.0

	S := scaleMatrix(sx, sy)
	R := rotationMatrix(angle)

	// scale then rotate: R x S x p
	RS := matMul(R, S)
	result1 := matVecMul(RS, p)

	// rotate then scale: S x R x p
	SR := matMul(S, R)
	result2 := matVecMul(SR, p)

	fmt.Println("Point: (1, 1), Scale(2, 3), Rotate(45 deg)")
	fmt.Println()
	fmt.Printf("Scale then Rotate (R x S x p): (%.4f, %.4f)\n",
		result1.V[0], result1.V[1])
	fmt.Printf("Rotate then Scale (S x R x p): (%.4f, %.4f)\n",
		result2.V[0], result2.V[1])
	fmt.Println()
	fmt.Println("Results are different: order matters!")
}

运行该程序将输出

Point: (1, 1), Scale(2, 3), Rotate(45 deg)

Scale then Rotate (R x S x p): (-0.7071, 3.5355)
Rotate then Scale (S x R x p): (0.0000, 4.2426)

Results are different: order matters!

这个例子清楚地展示了矩阵乘法的非交换性。对点 (1, 1) 先缩放 (2, 3) 再旋转 45° 得到 (-0.7071, 3.5355),而先旋转 45° 再缩放 (2, 3) 得到 (0, 4.2426),两个结果截然不同。在图形学中,变换顺序决定了最终的视觉效果。


完整实现(Full Implementation)

下面给出包含缩放、旋转、矩阵乘法、组合变换的完整程序,并附带多个测试用例。

C++ 实现

#include <iostream>
#include <iomanip>
#include <cmath>
#include <string>

// 2x2 matrix type
struct Matrix2x2
{
    double m[2][2];
};

// 2x1 vector type
struct Vector2
{
    double v[2];
};

// multiply 2x2 matrix by 2x1 vector
Vector2 matVecMul(const Matrix2x2& mat, const Vector2& vec)
{
    Vector2 result;
    result.v[0] = mat.m[0][0] * vec.v[0] + mat.m[0][1] * vec.v[1];
    result.v[1] = mat.m[1][0] * vec.v[0] + mat.m[1][1] * vec.v[1];
    return result;
}

// multiply two 2x2 matrices
Matrix2x2 matMul(const Matrix2x2& a, const Matrix2x2& b)
{
    Matrix2x2 result;
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            result.m[i][j] = 0;
            for (int k = 0; k < 2; k++)
            {
                result.m[i][j] += a.m[i][k] * b.m[k][j];
            }
        }
    }
    return result;
}

// create identity matrix
Matrix2x2 identityMatrix()
{
    Matrix2x2 mat = {{{1, 0}, {0, 1}}};
    return mat;
}

// create scale matrix
Matrix2x2 scaleMatrix(double sx, double sy)
{
    Matrix2x2 mat = {{{sx, 0}, {0, sy}}};
    return mat;
}

// create rotation matrix (angle in degrees)
Matrix2x2 rotationMatrix(double degrees)
{
    double rad = degrees * M_PI / 180.0;
    Matrix2x2 mat = {{{cos(rad), -sin(rad)}, {sin(rad), cos(rad)}}};
    return mat;
}

// print matrix
void printMatrix(const std::string& name, const Matrix2x2& mat)
{
    std::cout << name << ":\n";
    std::cout << std::fixed << std::setprecision(4);
    std::cout << "  | " << mat.m[0][0] << "  " << mat.m[0][1] << " |\n";
    std::cout << "  | " << mat.m[1][0] << "  " << mat.m[1][1] << " |\n";
}

// print vector
void printVec(const std::string& name, const Vector2& vec)
{
    std::cout << std::fixed << std::setprecision(4);
    std::cout << name << ": (" << vec.v[0] << ", " << vec.v[1] << ")\n";
}

int main()
{
    std::cout << "=== 2D Rotation and Scale Matrix Demo ===\n\n";

    // --- Scale tests ---
    std::cout << "--- Scale Tests ---\n";
    Vector2 p1 = {{3.0, 2.0}};
    Matrix2x2 S1 = scaleMatrix(2.0, 3.0);
    printVec("Original point", p1);
    printMatrix("Scale(2, 3)", S1);
    printVec("Scaled", matVecMul(S1, p1));
    std::cout << "\n";

    // --- Rotation tests ---
    std::cout << "--- Rotation Tests ---\n";
    Vector2 p2 = {{1.0, 0.0}};
    double angles[] = {30.0, 45.0, 90.0, 180.0};
    for (double angle : angles)
    {
        Matrix2x2 R = rotationMatrix(angle);
        Vector2 result = matVecMul(R, p2);
        std::cout << std::fixed << std::setprecision(4);
        std::cout << "Rotate(1,0) by " << angle << " deg -> ("
                  << result.v[0] << ", " << result.v[1] << ")\n";
    }
    std::cout << "\n";

    // --- Combined transform tests ---
    std::cout << "--- Combined Transform Tests ---\n";
    Vector2 p3 = {{1.0, 1.0}};
    Matrix2x2 S2 = scaleMatrix(2.0, 3.0);
    Matrix2x2 R2 = rotationMatrix(45.0);

    // scale then rotate
    Matrix2x2 RS = matMul(R2, S2);
    Vector2 resultScaleFirst = matVecMul(RS, p3);
    printVec("Scale(2,3) then Rotate(45)", resultScaleFirst);

    // rotate then scale
    Matrix2x2 SR = matMul(S2, R2);
    Vector2 resultRotFirst = matVecMul(SR, p3);
    printVec("Rotate(45) then Scale(2,3)", resultRotFirst);

    std::cout << "\n";

    // --- Matrix multiply demonstration ---
    std::cout << "--- Matrix Multiply ---\n";
    Matrix2x2 A = {{{1.0, 2.0}, {3.0, 4.0}}};
    Matrix2x2 B = {{{5.0, 6.0}, {7.0, 8.0}}};
    Matrix2x2 AB = matMul(A, B);
    Matrix2x2 BA = matMul(B, A);
    printMatrix("A x B", AB);
    std::cout << "\n";
    printMatrix("B x A", BA);
    std::cout << "\nA x B != B x A (non-commutative)\n";

    return 0;
}

运行该程序将输出

=== 2D Rotation and Scale Matrix Demo ===

--- Scale Tests ---
Original point: (3.0000, 2.0000)
Scale(2, 3):
  | 2.0000  0.0000 |
  | 0.0000  3.0000 |
Scaled: (6.0000, 6.0000)

--- Rotation Tests ---
Rotate(1,0) by 30.0000 deg -> (0.8660, 0.5000)
Rotate(1,0) by 45.0000 deg -> (0.7071, 0.7071)
Rotate(1,0) by 90.0000 deg -> (0.0000, 1.0000)
Rotate(1,0) by 180.0000 deg -> (-1.0000, 0.0000)

--- Combined Transform Tests ---
Scale(2,3) then Rotate(45): (-0.7071, 3.5355)
Rotate(45) then Scale(2,3): (0.0000, 4.2426)

--- Matrix Multiply ---
A x B:
  | 19.0000  22.0000 |
  | 43.0000  50.0000 |

B x A:
  | 23.0000  34.0000 |
  | 31.0000  46.0000 |

A x B != B x A (non-commutative)

C 实现

#include <stdio.h>
#include <math.h>

// 2x2 matrix type
typedef struct
{
    double m[2][2];
} Matrix2x2;

// 2x1 vector type
typedef struct
{
    double v[2];
} Vector2;

// multiply 2x2 matrix by 2x1 vector
Vector2 matVecMul(const Matrix2x2* mat, const Vector2* vec)
{
    Vector2 result;
    result.v[0] = mat->m[0][0] * vec->v[0] + mat->m[0][1] * vec->v[1];
    result.v[1] = mat->m[1][0] * vec->v[0] + mat->m[1][1] * vec->v[1];
    return result;
}

// multiply two 2x2 matrices
Matrix2x2 matMul(const Matrix2x2* a, const Matrix2x2* b)
{
    Matrix2x2 result;
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            result.m[i][j] = 0;
            for (int k = 0; k < 2; k++)
            {
                result.m[i][j] += a->m[i][k] * b->m[k][j];
            }
        }
    }
    return result;
}

// create identity matrix
Matrix2x2 identityMatrix(void)
{
    Matrix2x2 mat = {{{1, 0}, {0, 1}}};
    return mat;
}

// create scale matrix
Matrix2x2 scaleMatrix(double sx, double sy)
{
    Matrix2x2 mat = {{{sx, 0}, {0, sy}}};
    return mat;
}

// create rotation matrix (angle in degrees)
Matrix2x2 rotationMatrix(double degrees)
{
    double rad = degrees * M_PI / 180.0;
    Matrix2x2 mat = {{{cos(rad), -sin(rad)}, {sin(rad), cos(rad)}}};
    return mat;
}

int main()
{
    printf("=== 2D Rotation and Scale Matrix Demo ===\n\n");

    // --- Scale tests ---
    printf("--- Scale Tests ---\n");
    Vector2 p1 = {{3.0, 2.0}};
    Matrix2x2 S1 = scaleMatrix(2.0, 3.0);
    printf("Original point: (%.4f, %.4f)\n", p1.v[0], p1.v[1]);
    printf("Scale(2, 3):\n");
    printf("  | %.4f  %.4f |\n", S1.m[0][0], S1.m[0][1]);
    printf("  | %.4f  %.4f |\n", S1.m[1][0], S1.m[1][1]);
    Vector2 scaled = matVecMul(&S1, &p1);
    printf("Scaled: (%.4f, %.4f)\n\n", scaled.v[0], scaled.v[1]);

    // --- Rotation tests ---
    printf("--- Rotation Tests ---\n");
    Vector2 p2 = {{1.0, 0.0}};
    double angles[] = {30.0, 45.0, 90.0, 180.0};
    int numAngles = sizeof(angles) / sizeof(angles[0]);
    for (int i = 0; i < numAngles; i++)
    {
        Matrix2x2 R = rotationMatrix(angles[i]);
        Vector2 result = matVecMul(&R, &p2);
        printf("Rotate(1,0) by %.4f deg -> (%.4f, %.4f)\n",
               angles[i], result.v[0], result.v[1]);
    }
    printf("\n");

    // --- Combined transform tests ---
    printf("--- Combined Transform Tests ---\n");
    Vector2 p3 = {{1.0, 1.0}};
    Matrix2x2 S2 = scaleMatrix(2.0, 3.0);
    Matrix2x2 R2 = rotationMatrix(45.0);

    Matrix2x2 RS = matMul(&R2, &S2);
    Vector2 resultScaleFirst = matVecMul(&RS, &p3);
    printf("Scale(2,3) then Rotate(45): (%.4f, %.4f)\n",
           resultScaleFirst.v[0], resultScaleFirst.v[1]);

    Matrix2x2 SR = matMul(&S2, &R2);
    Vector2 resultRotFirst = matVecMul(&SR, &p3);
    printf("Rotate(45) then Scale(2,3): (%.4f, %.4f)\n\n",
           resultRotFirst.v[0], resultRotFirst.v[1]);

    // --- Matrix multiply demonstration ---
    printf("--- Matrix Multiply ---\n");
    Matrix2x2 A = {{{1.0, 2.0}, {3.0, 4.0}}};
    Matrix2x2 B = {{{5.0, 6.0}, {7.0, 8.0}}};
    Matrix2x2 AB = matMul(&A, &B);
    Matrix2x2 BA = matMul(&B, &A);
    printf("A x B:\n");
    printf("  | %.4f  %.4f |\n", AB.m[0][0], AB.m[0][1]);
    printf("  | %.4f  %.4f |\n", AB.m[1][0], AB.m[1][1]);
    printf("\nB x A:\n");
    printf("  | %.4f  %.4f |\n", BA.m[0][0], BA.m[0][1]);
    printf("  | %.4f  %.4f |\n", BA.m[1][0], BA.m[1][1]);
    printf("\nA x B != B x A (non-commutative)\n");

    return 0;
}

运行该程序将输出

=== 2D Rotation and Scale Matrix Demo ===

--- Scale Tests ---
Original point: (3.0000, 2.0000)
Scale(2, 3):
  | 2.0000  0.0000 |
  | 0.0000  3.0000 |
Scaled: (6.0000, 6.0000)

--- Rotation Tests ---
Rotate(1,0) by 30.0000 deg -> (0.8660, 0.5000)
Rotate(1,0) by 45.0000 deg -> (0.7071, 0.7071)
Rotate(1,0) by 90.0000 deg -> (0.0000, 1.0000)
Rotate(1,0) by 180.0000 deg -> (-1.0000, 0.0000)

--- Combined Transform Tests ---
Scale(2,3) then Rotate(45): (-0.7071, 3.5355)
Rotate(45) then Scale(2,3): (0.0000, 4.2426)

--- Matrix Multiply ---
A x B:
  | 19.0000  22.0000 |
  | 43.0000  50.0000 |

B x A:
  | 23.0000  34.0000 |
  | 31.0000  46.0000 |

A x B != B x A (non-commutative)

Python 实现

import math

def mat_vec_mul(mat, vec):
    """multiply 2x2 matrix by 2x1 vector"""
    return [
        mat[0][0] * vec[0] + mat[0][1] * vec[1],
        mat[1][0] * vec[0] + mat[1][1] * vec[1],
    ]

def mat_mul(a, b):
    """multiply two 2x2 matrices"""
    result = [[0.0, 0.0], [0.0, 0.0]]
    for i in range(2):
        for j in range(2):
            for k in range(2):
                result[i][j] += a[i][k] * b[k][j]
    return result

def scale_matrix(sx, sy):
    """create scale matrix"""
    return [[sx, 0.0], [0.0, sy]]

def rotation_matrix(degrees):
    """create rotation matrix (angle in degrees)"""
    rad = math.radians(degrees)
    return [[math.cos(rad), -math.sin(rad)],
            [math.sin(rad),  math.cos(rad)]]

def print_vec(name, vec):
    print(f"{name}: ({vec[0]:.4f}, {vec[1]:.4f})")

print("=== 2D Rotation and Scale Matrix Demo ===\n")

# --- Scale tests ---
print("--- Scale Tests ---")
p1 = [3.0, 2.0]
S1 = scale_matrix(2.0, 3.0)
print_vec("Original point", p1)
print(f"Scaled: ({S1[0][0]:.4f}, {S1[0][1]:.4f})")
print(f"        ({S1[1][0]:.4f}, {S1[1][1]:.4f})")
scaled = mat_vec_mul(S1, p1)
print_vec("Result", scaled)
print()

# --- Rotation tests ---
print("--- Rotation Tests ---")
p2 = [1.0, 0.0]
for angle in [30.0, 45.0, 90.0, 180.0]:
    R = rotation_matrix(angle)
    result = mat_vec_mul(R, p2)
    print(f"Rotate(1,0) by {angle:.4f} deg -> ({result[0]:.4f}, {result[1]:.4f})")
print()

# --- Combined transform tests ---
print("--- Combined Transform Tests ---")
p3 = [1.0, 1.0]
S2 = scale_matrix(2.0, 3.0)
R2 = rotation_matrix(45.0)

RS = mat_mul(R2, S2)
result_scale_first = mat_vec_mul(RS, p3)
print_vec("Scale(2,3) then Rotate(45)", result_scale_first)

SR = mat_mul(S2, R2)
result_rot_first = mat_vec_mul(SR, p3)
print_vec("Rotate(45) then Scale(2,3)", result_rot_first)
print()

# --- Matrix multiply demonstration ---
print("--- Matrix Multiply ---")
A = [[1.0, 2.0], [3.0, 4.0]]
B = [[5.0, 6.0], [7.0, 8.0]]
AB = mat_mul(A, B)
BA = mat_mul(B, A)
print(f"A x B: | {AB[0][0]:.4f}  {AB[0][1]:.4f} |")
print(f"       | {AB[1][0]:.4f}  {AB[1][1]:.4f} |")
print()
print(f"B x A: | {BA[0][0]:.4f}  {BA[0][1]:.4f} |")
print(f"       | {BA[1][0]:.4f}  {BA[1][1]:.4f} |")
print()
print("A x B != B x A (non-commutative)")

运行该程序将输出

=== 2D Rotation and Scale Matrix Demo ===

--- Scale Tests ---
Original point: (3.0000, 2.0000)
Scaled: (2.0000, 0.0000)
        (0.0000, 3.0000)
Result: (6.0000, 6.0000)

--- Rotation Tests ---
Rotate(1,0) by 30.0000 deg -> (0.8660, 0.5000)
Rotate(1,0) by 45.0000 deg -> (0.7071, 0.7071)
Rotate(1,0) by 90.0000 deg -> (0.0000, 1.0000)
Rotate(1,0) by 180.0000 deg -> (-1.0000, 0.0000)

--- Combined Transform Tests ---
Scale(2,3) then Rotate(45): (-0.7071, 3.5355)
Rotate(45) then Scale(2,3): (0.0000, 4.2426)

--- Matrix Multiply ---
A x B: | 19.0000  22.0000 |
       | 43.0000  50.0000 |

B x A: | 23.0000  34.0000 |
       | 31.0000  46.0000 |

A x B != B x A (non-commutative)

Go 实现

package main

import (
	"fmt"
	"math"
)

// 2x2 matrix type
type Matrix2x2 struct {
	M [2][2]float64
}

// 2x1 vector type
type Vector2 struct {
	V [2]float64
}

// multiply 2x2 matrix by 2x1 vector
func matVecMul(mat Matrix2x2, vec Vector2) Vector2 {
	return Vector2{
		V: [2]float64{
			mat.M[0][0]*vec.V[0] + mat.M[0][1]*vec.V[1],
			mat.M[1][0]*vec.V[0] + mat.M[1][1]*vec.V[1],
		},
	}
}

// multiply two 2x2 matrices
func matMul(a, b Matrix2x2) Matrix2x2 {
	var result Matrix2x2
	for i := 0; i < 2; i++ {
		for j := 0; j < 2; j++ {
			result.M[i][j] = 0
			for k := 0; k < 2; k++ {
				result.M[i][j] += a.M[i][k] * b.M[k][j]
			}
		}
	}
	return result
}

// create scale matrix
func scaleMatrix(sx, sy float64) Matrix2x2 {
	return Matrix2x2{M: [2][2]float64{{sx, 0}, {0, sy}}}
}

// create rotation matrix (angle in degrees)
func rotationMatrix(degrees float64) Matrix2x2 {
	rad := degrees * math.Pi / 180.0
	return Matrix2x2{M: [2][2]float64{
		{math.Cos(rad), -math.Sin(rad)},
		{math.Sin(rad), math.Cos(rad)},
	}}
}

// print vector
func printVec(name string, vec Vector2) {
	fmt.Printf("%s: (%.4f, %.4f)\n", name, vec.V[0], vec.V[1])
}

func main() {
	fmt.Println("=== 2D Rotation and Scale Matrix Demo ===")
	fmt.Println()

	// --- Scale tests ---
	fmt.Println("--- Scale Tests ---")
	p1 := Vector2{V: [2]float64{3.0, 2.0}}
	S1 := scaleMatrix(2.0, 3.0)
	printVec("Original point", p1)
	fmt.Printf("Scale(2, 3):\n")
	fmt.Printf("  | %.4f  %.4f |\n", S1.M[0][0], S1.M[0][1])
	fmt.Printf("  | %.4f  %.4f |\n", S1.M[1][0], S1.M[1][1])
	scaled := matVecMul(S1, p1)
	printVec("Scaled", scaled)
	fmt.Println()

	// --- Rotation tests ---
	fmt.Println("--- Rotation Tests ---")
	p2 := Vector2{V: [2]float64{1.0, 0.0}}
	angles := []float64{30.0, 45.0, 90.0, 180.0}
	for _, angle := range angles {
		R := rotationMatrix(angle)
		result := matVecMul(R, p2)
		fmt.Printf("Rotate(1,0) by %.4f deg -> (%.4f, %.4f)\n",
			angle, result.V[0], result.V[1])
	}
	fmt.Println()

	// --- Combined transform tests ---
	fmt.Println("--- Combined Transform Tests ---")
	p3 := Vector2{V: [2]float64{1.0, 1.0}}
	S2 := scaleMatrix(2.0, 3.0)
	R2 := rotationMatrix(45.0)

	RS := matMul(R2, S2)
	resultScaleFirst := matVecMul(RS, p3)
	printVec("Scale(2,3) then Rotate(45)", resultScaleFirst)

	SR := matMul(S2, R2)
	resultRotFirst := matVecMul(SR, p3)
	printVec("Rotate(45) then Scale(2,3)", resultRotFirst)
	fmt.Println()

	// --- Matrix multiply demonstration ---
	fmt.Println("--- Matrix Multiply ---")
	A := Matrix2x2{M: [2][2]float64{{1.0, 2.0}, {3.0, 4.0}}}
	B := Matrix2x2{M: [2][2]float64{{5.0, 6.0}, {7.0, 8.0}}}
	AB := matMul(A, B)
	BA := matMul(B, A)
	fmt.Println("A x B:")
	fmt.Printf("  | %.4f  %.4f |\n", AB.M[0][0], AB.M[0][1])
	fmt.Printf("  | %.4f  %.4f |\n", AB.M[1][0], AB.M[1][1])
	fmt.Println()
	fmt.Println("B x A:")
	fmt.Printf("  | %.4f  %.4f |\n", BA.M[0][0], BA.M[0][1])
	fmt.Printf("  | %.4f  %.4f |\n", BA.M[1][0], BA.M[1][1])
	fmt.Println()
	fmt.Println("A x B != B x A (non-commutative)")
}

运行该程序将输出

=== 2D Rotation and Scale Matrix Demo ===

--- Scale Tests ---
Original point: (3.0000, 2.0000)
Scale(2, 3):
  | 2.0000  0.0000 |
  | 0.0000  3.0000 |
Scaled: (6.0000, 6.0000)

--- Rotation Tests ---
Rotate(1,0) by 30.0000 deg -> (0.8660, 0.5000)
Rotate(1,0) by 45.0000 deg -> (0.7071, 0.7071)
Rotate(1,0) by 90.0000 deg -> (0.0000, 1.0000)
Rotate(1,0) by 180.0000 deg -> (-1.0000, 0.0000)

--- Combined Transform Tests ---
Scale(2,3) then Rotate(45): (-0.7071, 3.5355)
Rotate(45) then Scale(2,3): (0.0000, 4.2426)

--- Matrix Multiply ---
A x B:
  | 19.0000  22.0000 |
  | 43.0000  50.0000 |

B x A:
  | 23.0000  34.0000 |
  | 31.0000  46.0000 |

A x B != B x A (non-commutative)

二维旋转与缩放矩阵的性质(Properties)

理解旋转和缩放矩阵的数学性质有助于深入掌握线性变换。

旋转矩阵的性质

  • 正交矩阵(Orthogonal Matrix):旋转矩阵 R 满足 R^T = R^-1,即转置等于逆矩阵。这意味着 R x R^T = I(单位矩阵)。
  • 行列式(Determinant):det(R) = cos^2(θ) + sin^2(θ) = 1。行列式为 1 表示旋转不改变面积,只改变方向。
  • 保距性(Isometry):旋转保持点之间的距离不变,即旋转前后任意两点的距离相同。

缩放矩阵的性质

  • 行列式:det(S) = sx × sy。当 sx 和 sy 都大于 1 时,面积放大;都小于 1 时,面积缩小。若 det(S) < 0,说明发生了翻转。
  • 对角矩阵(Diagonal Matrix):缩放矩阵是对角矩阵,只有主对角线上有非零元素。

组合变换的性质

  • 封闭性(Closure):任意多个旋转和缩放的组合,最终都可以表示为单个 2x2 矩阵。这是因为矩阵乘法的结果仍然是矩阵。
  • 非交换性(Non-commutativity):一般而言 A x B ≠ B x A,变换的顺序会影响最终结果。
  • 结合律(Associativity):(A x B) x C = A x (B x C),因此在组合多个变换时可以灵活地分组。

局限性

2x2 矩阵无法表示平移变换(Translation)。平移需要加上一个偏移向量,即 p' = M x p + t。为了将平移也纳入矩阵运算体系,需要引入齐次坐标(Homogeneous Coordinates),将 2D 点表示为 (x, y, 1),使用 3x3 矩阵来统一表示旋转、缩放和平移。这是计算机图形学中更高级的主题。

posted @ 2026-04-17 08:39  游翔  阅读(24)  评论(0)    收藏  举报