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 矩阵来统一表示旋转、缩放和平移。这是计算机图形学中更高级的主题。

浙公网安备 33010602011771号