计算机图形学13:三维图形的几何变换

在这里插入图片描述

作者:非妃是公主
专栏:《计算机图形学》
博客地址:https://blog.csdn.net/myf_666
个性签:顺境不惰,逆境不馁,以心制境,万事可成。——曾国藩
在这里插入图片描述

文章目录

  • 专栏推荐
  • 专栏系列文章
  • 一、三维图形的几何变换
  • 二、数据结构及工具函数定义
  • 三、平移变换
    • 1. 平移变换矩阵
    • 2. 代码实现
    • 3. 效果展示
  • 四、比例变换
    • 1. 比例变换矩阵
    • 2. 代码实现
    • 3. 效果展示
  • 五、旋转变换
    • 1. 旋转变换矩阵
    • 2. 代码实现
    • 3. 效果展示
  • 六、对称变换
    • 1. 关于坐标平面对称变换矩阵
    • 2. 关于坐标轴对称变换矩阵
    • 3. 代码实现
    • 4. 效果展示
  • 七、错切变换
    • 1. 变换矩阵
    • 2. 代码实现
    • 3. 效果展示
  • 八、相对任意参考点的复合变换
  • 九、相对任意方向的复合变换
  • the end……

专栏推荐

专栏名称专栏地址
软件工程专栏——软件工程
计算机图形学 专栏——计算机图形学
操作系统专栏——操作系统
软件测试专栏——软件测试
机器学习专栏——机器学习
数据库专栏——数据库
算法专栏——算法

专栏系列文章

文章名称文章地址
直线生成算法(DDA算法)计算机图形学01——DDA算法
中点BH算法绘制直线计算机图形学02——中点BH算法
改进的中点BH算法计算机图形学03——改进的中点BH算法
中点Bresenham画椭圆计算机图形学04——中点BH绘制椭圆
中点BH算法绘制任意斜率直线计算机图形学05——中点BH算法绘制任意斜率的直线
中点Bresenham画圆计算机图形学06——中点BH算法画圆
有效边表法的多边形扫描转换计算机图形学07——有效边表法绘制填充多边形
中点BH算法绘制抛物线 100 x = y 2 100x = y^2 100x=y2计算机图形学08——中点BH绘制抛物线
二维观察之点的裁剪计算机图形学09——二维观察之点裁剪
二维观察之线的裁剪计算机图形学10——二维观察之线裁剪
二维观察之多边形的裁剪计算机图形学11——二维观察之多边形裁剪
二维图形的几何变换计算机图形学12——二维图形几何变换
三维图形的几何变换计算机图形学13——三维图形几何变换
三维图形的投影变换计算机图形学14——三维图形投影变换

计算机图形学(英语:computer graphics,缩写为CG)是研究计算机在硬件和软件的帮助下创建计算机图形的科学学科,是计算机科学的一个分支领域,主要关注数字合成与操作视觉的图形内容。虽然这个词通常被认为是指三维图形,事实上同时包括了二维图形以及影像处理。


一、三维图形的几何变换

在这里插入图片描述
对三维图形的几何信息经过平移、比例、旋转等变换后生成新的三维图形,复杂图形的几何变换可通过变换矩阵对图形的基本元素点、线、面作用,其中对点的矩阵是基础。
其中的变换形式如下:
[ x ′ y ′ z ′ 1 ] = T 2 D ⋅ [ x y z 1 ] = [ a b c p d e f q h i j r l m n s ] ⋅ [ x y z 1 ] \begin{bmatrix} x'\\y'\\z'\\1\\ \end{bmatrix}=T_{2D}\cdot\begin{bmatrix} x\\ y\\ z\\ 1\\ \end{bmatrix}=\begin{bmatrix} a&b&c&p\\ d&e&f&q\\ h&i&j&r\\ l&m&n&s\\ \end{bmatrix}\cdot\begin{bmatrix} x\\ y\\ z\\ 1\\ \end{bmatrix} xyz1 =T2D xyz1 = adhlbeimcfjnpqrs xyz1


二、数据结构及工具函数定义

struct VERTEX3D { double x, y, z; };	// 三维空间点结构
#define PI acos(-1)
/// <summary>
/// 矩阵结构体
/// </summary>
struct Matrix {
	vector<vector<double>> matrix;
	Matrix() { // 初始化为 4 * 4 的矩阵
		matrix = vector<vector<double>>(4, vector<double>(4, 0.0));
	}
	Matrix(int m, int n) { // 初始化为 m * n 的矩阵
		matrix = vector<vector<double>>(m, vector<double>(n, 0.0));
	}
	friend ostream& operator<<(ostream& out, Matrix& m) {
		for (int i = 0; i < m.matrix.size(); i++) {
			for (int j = 0; j < m.matrix[0].size(); j++) {
				out << m.matrix[i][j] << " ";
			}
			out << endl;
		}
		return out;
	}
};

/// <summary>
/// 矩阵相乘
/// </summary>
/// <param name="m1">矩阵相乘的第一个矩阵</param>
/// <param name="m2">矩阵相乘的第二个矩阵</param>
/// <returns></returns>
Matrix dotMatrix(Matrix m1, Matrix m2) {
	Matrix res;
	for (int i = 0; i < m1.matrix.size(); i++) {
		for (int j = 0; j < m2.matrix[0].size(); j++) {
			for (int k = 0; k < m1.matrix[0].size(); k++) {
				res.matrix[i][j] += m1.matrix[i][k] * m2.matrix[k][j];
			}
		}
	}
	return res;
}

/// <summary>
/// 将点转化为其次坐标
/// </summary>
/// <param name="vertex">点</param>
/// <returns>齐次坐标</returns>
Matrix vertex3D2qici(VERTEX3D vertex3D) {
	Matrix qiciVertex(4, 1);
	qiciVertex.matrix[0][0] = vertex3D.x;
	qiciVertex.matrix[1][0] = vertex3D.y;
	qiciVertex.matrix[2][0] = vertex3D.z;
	qiciVertex.matrix[3][0] = 1;
	return qiciVertex;
}

三、平移变换

1. 平移变换矩阵

T t = [ 1 0 0 t x 0 1 0 t y 0 0 1 t z 0 0 0 1 ]   T_{t}=\begin{bmatrix} 1&0&0&t_x\\ 0&1&0&t_y\\ 0&0&1&t_z\\ 0&0&0&1\\ \end{bmatrix}\ Tt= 100001000010txtytz1  

2. 代码实现

/// <summary>
/// 三维坐标平移变换
/// </summary>
/// <param name="vertex3D">待平移地三维点</param>
/// <param name="x">x方向平移距离</param>
/// <param name="y">y方向平移距离</param>
/// <param name="z">z方向平移距离</param>
/// <returns>平移后的三维点坐标</returns>
VERTEX3D transTransform3D(VERTEX3D vertex3D, int x, int y, int z) {
	Matrix qiciVertex= vertex3D2qici(vertex3D);  // 转化为其次坐标

	Matrix transform;		 // 变换矩阵
	transform.matrix[0][0] = 1;
	transform.matrix[1][1] = 1;
	transform.matrix[2][2] = 1;
	transform.matrix[3][3] = 1;
	
	// 设置各方向平移距离
	transform.matrix[0][3] = x;
	transform.matrix[1][3] = y;
	transform.matrix[2][3] = z;

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

3. 效果展示

测试代码如下:

void testTransTransform() {
	VERTEX3D vertex3D = { 0,1,0 };
	VERTEX3D res = transTransform3D(vertex3D, 1, -1, 1);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

点(0,1,0)在x,y,z三个方向上分别平移(1,-1,1)个单位后,坐标为(1,0,1),如下图所示:

在这里插入图片描述


四、比例变换

1. 比例变换矩阵

T t = [ a 0 0 0 0 e 0 0 0 0 j 0 0 0 0 1 ]   T_{t}=\begin{bmatrix} a&0&0&0\\ 0&e&0&0\\ 0&0&j&0\\ 0&0&0&1\\ \end{bmatrix}\ Tt= a0000e0000j00001  

2. 代码实现

/// <summary>
/// 三维坐标比例变换
/// </summary>
/// <param name="vertex3D">待变换的三维点</param>
/// <param name="x">x方向变换比例</param>
/// <param name="y">y方向变换比例</param>
/// <param name="z">z方向变换比例</param>
/// <returns>比例变换后的三维点坐标</returns>
VERTEX3D scaleTransform3D(VERTEX3D vertex3D, double scaleX, int scaleY, int scaleZ) {
	Matrix qiciVertex = vertex3D2qici(vertex3D); // 转化为其次坐标

	Matrix transform;		 // 变换矩阵
	transform.matrix[0][0] = scaleX;
	transform.matrix[1][1] = scaleY;
	transform.matrix[2][2] = scaleZ;
	transform.matrix[3][3] = 1;

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

3. 效果展示

测试代码如下:

void testScaleTransform3D() {
	VERTEX3D vertex3D = { 1,1,2 };
	VERTEX3D res = scaleTransform3D(vertex3D, 5, -2, 3);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

在这里插入图片描述


五、旋转变换

在这里插入图片描述


1. 旋转变换矩阵

旋转变换分为x、y、z三个方向上的旋转,遵循右手定则,拇指指向坐标轴的方向,手指的方向为正方向。
绕X轴旋转变换矩阵:
T R X = [ 1 0 0 0 0 c o s θ − s i n θ 0 0 s i n θ c o s θ 0 0 0 0 1 ]   T_{RX}=\begin{bmatrix} 1&0&0&0\\ 0&cos\theta&-sin\theta&0\\ 0&sin\theta&cos\theta&0\\ 0&0&0&1\\ \end{bmatrix}\ TRX= 10000cosθsinθ00sinθcosθ00001  

绕Y轴旋转变换矩阵:

T R Y = [ c o s θ 0 s i n θ 0 0 1 0 0 − s i n θ 0 c o s θ 0 0 0 0 1 ]   T_{RY}=\begin{bmatrix} cos\theta&0&sin\theta&0\\ 0&1&0&0\\ -sin\theta&0&cos\theta&0\\ 0&0&0&1\\ \end{bmatrix}\ TRY= cosθ0sinθ00100sinθ0cosθ00001  

绕Z轴旋转变换矩阵:

T R Z = [ c o s θ − s i n θ 0 0 s i n θ c o s θ 0 0 0 0 1 0 0 0 0 1 ]   T_{RZ}=\begin{bmatrix} cos\theta&-sin\theta&0&0\\ sin\theta&cos\theta&0&0\\ 0&0&1&0\\ 0&0&0&1\\ \end{bmatrix}\ TRZ= cosθsinθ00sinθcosθ0000100001  


2. 代码实现

VERTEX3D rotationForXTransform3D(VERTEX3D vertex3D, double theta) {
	Matrix qiciVertex(4, 1); // 转化为其次坐标
	qiciVertex.matrix[0][0] = vertex3D.x;
	qiciVertex.matrix[1][0] = vertex3D.y;
	qiciVertex.matrix[2][0] = vertex3D.z;
	qiciVertex.matrix[3][0] = 1;

	Matrix transform;		 // 变换矩阵
	transform.matrix[0][0] = 1;
	transform.matrix[1][1] = cos(2 * PI * theta / 360);
	transform.matrix[2][2] = cos(2 * PI * theta / 360);
	transform.matrix[3][3] = 1;

	transform.matrix[1][2] = -sin(2 * PI * theta / 360);
	transform.matrix[2][1] = sin(2 * PI * theta / 360);

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

VERTEX3D rotationForYTransform3D(VERTEX3D vertex3D, double theta) {
	Matrix qiciVertex(4, 1); // 转化为其次坐标
	qiciVertex.matrix[0][0] = vertex3D.x;
	qiciVertex.matrix[1][0] = vertex3D.y;
	qiciVertex.matrix[2][0] = vertex3D.z;
	qiciVertex.matrix[3][0] = 1;

	Matrix transform;		 // 变换矩阵
	transform.matrix[0][0] = cos(2 * PI * theta / 360);
	transform.matrix[1][1] = 1;
	transform.matrix[2][2] = cos(2 * PI * theta / 360);
	transform.matrix[3][3] = 1;

	transform.matrix[0][2] = sin(2 * PI * theta / 360);
	transform.matrix[2][0] = -sin(2 * PI * theta / 360);

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

VERTEX3D rotationForZTransform3D(VERTEX3D vertex3D, double theta) {
	Matrix qiciVertex(4, 1); // 转化为其次坐标
	qiciVertex.matrix[0][0] = vertex3D.x;
	qiciVertex.matrix[1][0] = vertex3D.y;
	qiciVertex.matrix[2][0] = vertex3D.z;
	qiciVertex.matrix[3][0] = 1;

	Matrix transform;		 // 变换矩阵
	transform.matrix[0][0] = cos(2 * PI * theta / 360);
	transform.matrix[1][1] = cos(2 * PI * theta / 360);
	transform.matrix[2][2] = 1;
	transform.matrix[3][3] = 1;

	transform.matrix[0][1] = -sin(2 * PI * theta / 360);
	transform.matrix[1][0] = sin(2 * PI * theta / 360);

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

3. 效果展示

测试代码如下:

void testRotationForXTransform3D() {
	VERTEX3D vertex3D = { 1,1,1 };
	VERTEX3D res = rotationForXTransform3D(vertex3D, 135);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

void testRotationForYTransform3D() {
	VERTEX3D vertex3D = { 1,1,1 };
	VERTEX3D res = rotationForYTransform3D(vertex3D, 135);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

void testRotationForZTransform3D() {
	VERTEX3D vertex3D = { 1,1,1 };
	VERTEX3D res = rotationForZTransform3D(vertex3D, 135);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

三个测试代码分别表示沿x,y,z轴旋转135度。

在这里插入图片描述


六、对称变换

对称变换包括关于xoy、yoz、zox三个平面对称,还包括,关于x轴、y轴、z轴对称,变换矩阵分别如下:


1. 关于坐标平面对称变换矩阵

关于xoy平面对称,因此x、y坐标不变,z坐标变为相反数(-z):
T F x y = [ 1 0 0 0 0 1 0 0 0 0 − 1 0 0 0 0 1 ]   T_{Fxy}=\begin{bmatrix} 1&0&0&0\\ 0&1&0&0\\ 0&0&-1&0\\ 0&0&0&1\\ \end{bmatrix}\ TFxy= 1000010000100001  
同理可得,关于yoz平面对称:
T F y z = [ − 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 ]   T_{Fyz}=\begin{bmatrix} -1&0&0&0\\ 0&1&0&0\\ 0&0&1&0\\ 0&0&0&1\\ \end{bmatrix}\ TFyz= 1000010000100001  
关于zox平面对称:
T F z x = [ 1 0 0 0 0 − 1 0 0 0 0 1 0 0 0 0 1 ]   T_{Fzx}=\begin{bmatrix} 1&0&0&0\\ 0&-1&0&0\\ 0&0&1&0\\ 0&0&0&1\\ \end{bmatrix}\ TFzx= 1000010000100001  


2. 关于坐标轴对称变换矩阵

关于x轴对称,因此x坐标不变,y、z坐标变为相反数(-y、-z):
T F x = [ 1 0 0 0 0 − 1 0 0 0 0 − 1 0 0 0 0 1 ]   T_{Fx}=\begin{bmatrix} 1&0&0&0\\ 0&-1&0&0\\ 0&0&-1&0\\ 0&0&0&1\\ \end{bmatrix}\ TFx= 1000010000100001  
同理可得,关于y轴对称:
T F y = [ − 1 0 0 0 0 1 0 0 0 0 − 1 0 0 0 0 1 ]   T_{Fy}=\begin{bmatrix} -1&0&0&0\\ 0&1&0&0\\ 0&0&-1&0\\ 0&0&0&1\\ \end{bmatrix}\ TFy= 1000010000100001  
关于z轴对称:
T F z = [ − 1 0 0 0 0 − 1 0 0 0 0 1 0 0 0 0 1 ]   T_{Fz}=\begin{bmatrix} -1&0&0&0\\ 0&-1&0&0\\ 0&0&1&0\\ 0&0&0&1\\ \end{bmatrix}\ TFz= 1000010000100001  


3. 代码实现

/// <summary>
/// x轴镜像/对称变换
/// </summary>
/// <param name="vertex3D">待变换的三维点</param>
/// <returns>比例变换后的三维点坐标</returns>
VERTEX3D symmetryForXTransform3D(VERTEX3D vertex3D) {
	Matrix qiciVertex = vertex3D2qici(vertex3D); // 转化为其次坐标

	Matrix transform;		 // 变换矩阵
	transform.matrix[0][0] = 1;
	transform.matrix[1][1] = -1;
	transform.matrix[2][2] = -1;
	transform.matrix[3][3] = 1;

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

/// <summary>
/// y轴镜像/对称变换
/// </summary>
/// <param name="vertex3D">待变换的三维点</param>
/// <returns>比例变换后的三维点坐标</returns>
VERTEX3D symmetryForYTransform3D(VERTEX3D vertex3D) {
	Matrix qiciVertex = vertex3D2qici(vertex3D); // 转化为其次坐标

	Matrix transform;		 // 变换矩阵
	transform.matrix[0][0] = -1;
	transform.matrix[1][1] = 1;
	transform.matrix[2][2] = -1;
	transform.matrix[3][3] = 1;

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

/// <summary>
/// z轴镜像/对称变换
/// </summary>
/// <param name="vertex3D">待变换的三维点</param>
/// <returns>比例变换后的三维点坐标</returns>
VERTEX3D symmetryForZTransform3D(VERTEX3D vertex3D) {
	Matrix qiciVertex = vertex3D2qici(vertex3D); // 转化为其次坐标

	Matrix transform;		 // 变换矩阵
	transform.matrix[0][0] = -1;
	transform.matrix[1][1] = -1;
	transform.matrix[2][2] = 1;
	transform.matrix[3][3] = 1;

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

/// <summary>
/// XOY轴镜像/对称变换
/// </summary>
/// <param name="vertex3D">待变换的三维点</param>
/// <returns>比例变换后的三维点坐标</returns>
VERTEX3D symmetryForXOYTransform3D(VERTEX3D vertex3D) {
	Matrix qiciVertex = vertex3D2qici(vertex3D); // 转化为其次坐标

	Matrix transform;		 // 变换矩阵
	transform.matrix[0][0] = 1;
	transform.matrix[1][1] = 1;
	transform.matrix[2][2] = -1;
	transform.matrix[3][3] = 1;

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

/// <summary>
/// YOZ轴镜像/对称变换
/// </summary>
/// <param name="vertex3D">待变换的三维点</param>
/// <returns>比例变换后的三维点坐标</returns>
VERTEX3D symmetryForYOZTransform3D(VERTEX3D vertex3D) {
	Matrix qiciVertex = vertex3D2qici(vertex3D); // 转化为其次坐标

	Matrix transform;		 // 变换矩阵
	transform.matrix[0][0] = -1;
	transform.matrix[1][1] = 1;
	transform.matrix[2][2] = 1;
	transform.matrix[3][3] = 1;

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

/// <summary>
/// ZOX轴镜像/对称变换
/// </summary>
/// <param name="vertex3D">待变换的三维点</param>
/// <returns>比例变换后的三维点坐标</returns>
VERTEX3D symmetryForZOXTransform3D(VERTEX3D vertex3D) {
	Matrix qiciVertex = vertex3D2qici(vertex3D); // 转化为其次坐标

	Matrix transform;		 // 变换矩阵
	transform.matrix[0][0] = 1;
	transform.matrix[1][1] = -1;
	transform.matrix[2][2] = 1;
	transform.matrix[3][3] = 1;

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

4. 效果展示

坐标点(4,3,2)关于坐标平面、坐标轴对称的结果如下:
在这里插入图片描述
测试代码如下:

void testSymmetryForXTransform3D() {
	VERTEX3D vertex3D = { 4,3,2 };
	VERTEX3D res = symmetryForXTransform3D(vertex3D);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

void testSymmetryForYTransform3D() {
	VERTEX3D vertex3D = { 4,3,2 };
	VERTEX3D res = symmetryForYTransform3D(vertex3D);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

void testSymmetryForZTransform3D() {
	VERTEX3D vertex3D = { 4,3,2 };
	VERTEX3D res = symmetryForZTransform3D(vertex3D);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

void testSymmetryForXOYTransform3D() {
	VERTEX3D vertex3D = { 4,3,2 };
	VERTEX3D res = symmetryForXOYTransform3D(vertex3D);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

void testSymmetryForYOZTransform3D() {
	VERTEX3D vertex3D = { 4,3,2 };
	VERTEX3D res = symmetryForYOZTransform3D(vertex3D);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

void testSymmetryForZOXTransform3D() {
	VERTEX3D vertex3D = { 4,3,2 };
	VERTEX3D res = symmetryForZOXTransform3D(vertex3D);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

七、错切变换

错切变换同样分为3种,分别为x、y、z三个方向进行变换。具体变换矩阵如下:


1. 变换矩阵

关于x方向错切,y、z坐标不会发生变换,x坐标发生变化的幅度会收到y、z坐标大小的影响,y、z越大,发生变换的程度也越大。
T S H x = [ 1 b c 0 0 1 0 0 0 0 1 0 0 0 0 1 ]   T_{SHx}=\begin{bmatrix} 1&b&c&0\\ 0&1&0&0\\ 0&0&1&0\\ 0&0&0&1\\ \end{bmatrix}\ TSHx= 1000b100c0100001  

T S H y = [ 1 0 0 0 d 1 f 0 0 0 1 0 0 0 0 1 ]   T_{SHy}=\begin{bmatrix} 1&0&0&0\\ d&1&f&0\\ 0&0&1&0\\ 0&0&0&1\\ \end{bmatrix}\ TSHy= 1d0001000f100001  

T S H z = [ 1 0 0 0 0 1 0 0 g h 1 0 0 0 0 1 ]   T_{SHz}=\begin{bmatrix} 1&0&0&0\\ 0&1&0&0\\ g&h&1&0\\ 0&0&0&1\\ \end{bmatrix}\ TSHz= 10g001h000100001  


2. 代码实现

/// <summary>
/// X方向错切变换
/// </summary>
/// <param name="vertex3D">待变换的点</param>
/// <param name="miscutY">Y方向错切量</param>
/// <param name="miscutZ">Z方向错切量</param>
/// <returns>变换后的点</returns>
VERTEX3D miscutForXTransform3D(VERTEX3D vertex3D, double miscutY, double miscutZ) {
	Matrix qiciVertex = vertex3D2qici(vertex3D); // 转化为其次坐标

	Matrix transform;		 // 平移变换矩阵
	transform.matrix[0][0] = 1;
	transform.matrix[1][1] = 1;
	transform.matrix[2][2] = 1;
	transform.matrix[3][3] = 1;

	// 错切量
	transform.matrix[0][1] = miscutY;
	transform.matrix[0][2] = miscutZ;

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

/// <summary>
/// Y方向错切变换
/// </summary>
/// <param name="vertex3D">待变换的点</param>
/// <param name="miscutX">X方向错切量</param>
/// <param name="miscutZ">Z方向错切量</param>
/// <returns>变换后的点</returns>
VERTEX3D miscutForYTransform3D(VERTEX3D vertex3D, double miscutX, double miscutZ) {
	Matrix qiciVertex = vertex3D2qici(vertex3D); // 转化为其次坐标

	Matrix transform;		 // 平移变换矩阵
	transform.matrix[0][0] = 1;
	transform.matrix[1][1] = 1;
	transform.matrix[2][2] = 1;
	transform.matrix[3][3] = 1;

	// 错切量
	transform.matrix[1][0] = miscutX;
	transform.matrix[1][2] = miscutZ;

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

/// <summary>
/// Z方向错切变换
/// </summary>
/// <param name="vertex3D">待变换的点</param>
/// <param name="miscutX">X方向错切量</param>
/// <param name="miscutY">Y方向错切量</param>
/// <returns>变换后的点</returns>
VERTEX3D miscutForZTransform3D(VERTEX3D vertex3D, double miscutX, double miscutY) {
	Matrix qiciVertex = vertex3D2qici(vertex3D); // 转化为其次坐标

	Matrix transform;		 // 平移变换矩阵
	transform.matrix[0][0] = 1;
	transform.matrix[1][1] = 1;
	transform.matrix[2][2] = 1;
	transform.matrix[3][3] = 1;

	// 错切量
	transform.matrix[2][0] = miscutX;
	transform.matrix[2][1] = miscutY;

	// 进行变换得到齐次坐标结果
	Matrix qicires = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为三维点坐标
	VERTEX3D res;
	res.x = qicires.matrix[0][0];
	res.y = qicires.matrix[1][0];
	res.z = qicires.matrix[2][0];
	return res;
}

void testMiscutTransform3D() {
	VERTEX3D vertex3D = { 4,3,2 };
	VERTEX3D res = miscutForZTransform3D(vertex3D, 2, 2);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

3. 效果展示

在这里插入图片描述

测试代码如下:

void testMiscutTransform3D() {
	VERTEX3D vertex3D = { 4,3,2 };
	VERTEX3D res = miscutForXTransform3D(vertex3D, 2, 2);
	cout << res.x << " " << res.y << " " << res.z << endl;
	res = miscutForYTransform3D(vertex3D, 2, 2);
	cout << res.x << " " << res.y << " " << res.z << endl;
	res = miscutForZTransform3D(vertex3D, 2, 2);
	cout << res.x << " " << res.y << " " << res.z << endl;
}

八、相对任意参考点的复合变换

相对于参考点F(xf,yf,zf)作比例、旋转、错切等变换的过程分为以下三步:
(1)将参考点F移至坐标原点;
(2)针对原点进行三维几何变换;
(3)进行反平移。


九、相对任意方向的复合变换

针对任意方向轴的变换的五个步骤:
①使任意方向轴的起点与坐标原点重合,此时进行平移变换。
②使方向轴与某一坐标轴重合,此时需进行旋转变换,且旋转变换可能不止一次。
③针对该坐标轴完成变换。
④用逆旋转变换使方向轴回到其原始方向。
⑤用逆平移变换使方向轴回到其原始位置。
在这里插入图片描述


the end……

三维图形的几何变换到这里就要结束啦~~到此既是缘分,欢迎您的点赞评论收藏关注我,不迷路,我们下期再见!!

😘😘😘 我是Cherries,一位计算机科班在校大学生,写博客用来记录自己平时的所思所想!
💞💞💞 内容繁杂,又才疏学浅,难免存在错误,欢迎各位大佬的批评指正!
👋👋👋 我们相互交流,共同进步!

:本文由非妃是公主发布于https://blog.csdn.net/myf_666,转载请务必标明原文链接:https://blog.csdn.net/myf_666/article/details/129847063

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/6314.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MongoDB综述【入门指南】

写这篇博客,正好是2023年4月5日15:29:31,是清明节,放假一天,我坐在我的小小租房室内,思考着没思考到啥,哈哈哈,感觉好着急啊!看完了一本《城南旧事》,但是就是不踏实,好吧~我来写一篇最近在学的一个技术 为了更优秀的自己~奥利给!! 首先,我们从最初级小白开始(因为自己也是小白…

卷麻了,00后测试用例写的比我还好,简直无地自容.....

前言 作为一个测试新人&#xff0c;刚开始接触测试&#xff0c;对于怎么写测试用例很头疼&#xff0c;无法接触需求&#xff0c;只能根据站在用户的角度去做测试&#xff0c;但是这样情况会导致不能全方位的测试APP&#xff0c;这种情况就需要一份测试用例了&#xff0c;但是不…

倾斜实景三维建模与BIM模型处理技术

倾斜实景三维建模与BIM模型处理技术 一、研究背景 ➢ 倾斜模型 ✓ 真实纹理&#xff0c;高分辨率 ✓ 真实坐标&#xff0c;高空间精度 ✓ 快速建模&#xff0c;低建模成本 ➢ BIM设计 BIM 技术作为建筑施工行业中的新技术&#xff0c;存在于建筑的全生命周期&#xff0c;服务…

机器学习算法:K近邻(k-nearest neighbors)初探

KNN的介绍和应用 KNN&#xff08;K-Nearest Neighbor&#xff09;算法是一种基于实例的学习算法&#xff0c;也是一种常见的分类算法。 如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别&#xff0c;则该样本也属于这个类别。 示例 &…

Python 3 基本数据类型,包含示例演示(初学友好)

嗨害大家好鸭~ 我是芝士❤ 有好好学习python吗&#xff1f; Python学习资料电子书 点击此处跳转文末名片获取 Python3 基本数据类型 Python 中的变量不需要声明。每个变量在使用前都必须赋值&#xff0c;变量赋值以后该变量才会被创建。 在 Python 中&#xff0c;变量就是变量…

MATLAB 求解定积分和不定积分

本文主要介绍如何通过matlab 去求解常见的定积分和不定积分的结果&#xff0c;使用matlab 内置函数 int。 语法&#xff1a; Fint(表达式&#xff0c;变量&#xff0c;变量上下限) 目录 例子1 单变量不定积分 例子2 多变量不定积分 例子3 单变量定积分 例子4 定积分近似求…

软件测试高频出现面试题-2(实用)

每日面试1、自我介绍2、简单介绍最近项目你是如何开展测试工作的呢&#xff1f;3、描述在这个项目里面你主要负责哪些模块的测试&#xff1f;选中一个业务复杂的讲述你是如何测试的呢&#xff1f;1、自我介绍 主要可以从三个方面准备&#xff1a;我的基础信息&#xff0c;我的…

OBCP第八章 OB运维、监控与异常处理-常见异常处理

问题排查概述&#xff1a;数据库连接问题排查 在遇到连接问题时&#xff0c;需要清楚整个系统的架构&#xff0c;对整个连接链路进行排查。通常情况下应用连接到数据库的完整链路是从应用服务器到 OBProxy 再到 OB 集群&#xff0c;此外还可能涉及负载均衡、DNS 解析、网络等。…

49天精通Java,第24天,Java链表、散列表、HashSet、TreeSet

目录一、链表二、散列表三、HashSet四、TreeSet五、TreeSet常用方法大家好&#xff0c;我是哪吒。 一、链表 从数组中间删除一个元素开销很大&#xff0c;其原因是向数组中插入元素时&#xff0c;此元素之后的所有元素都要向后端移动&#xff0c;删除时也是&#xff0c;数组中…

大厂面试篇--2023软件测试八股文最全文档,有它直接大杀四方

前言 已经到了金三银四的黄金招聘季节了&#xff0c;还在准备面试跳槽涨薪的小伙伴们可以看看本篇文章哟&#xff0c;这里呢笔者就不多说废话了直接上干货&#xff01;答案已整理好&#xff0c;文末拿去即可&#xff01;非常好用&#xff01; 一、字节跳动测试面经篇 1、在搜…

【KNN算法详解(用法,优缺点,适用场景)及应用】

KNN算法介绍 KNN&#xff08;K Near Neighbor&#xff09;&#xff1a;k个最近的邻居&#xff0c;即每个样本都可以用它最接近的k个邻居来代表。KNN算法属于监督学习方式的分类算法&#xff0c;我的理解就是计算某给点到每个点的距离作为相似度的反馈。 简单来讲&#xff0c;…

【工具】Maven

文章目录0.Maven安装&#xff08;不使用IDEA内置&#xff09;1.Maven的作用2.Maven核心概念3.maven目录结构4.仓库5.pom文件5.1 坐标 gav5.2.packaging5.3.依赖5.4.配置属性5.5.build6.Maven生命周期7.junit 单元测试8.插件9.IDEA构建Maven10.创建javase项目11.web工程12.依赖的…

【Linux】初识动静态库/动静态链接

文章目录动静态库的基本原理认识动静态库动静态库的特性手动安装静态库动静态库的基本原理 首先&#xff0c;文件和头文件最终变成一个可执行程序需要经历以下四个步骤&#xff1a; 1&#xff09;预处理&#xff1a;预处理所要完成的有&#xff0c;头文件展开、去注释、宏替换…

【HTML系列】第四章 · 列表和表格

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…

【艾特淘】淘宝做爆款的目的是什么?怎么做?

其实在淘宝上面也有很多卖家都想要去打造属于自己店铺的爆款商品。 但是又不知道淘宝做爆款商品的目的是什么&#xff0c;也不知道爆款商品到底应该要怎么做&#xff0c;我马上就来给各位卖家介绍。 我们打造爆款是为了让我们通过爆款赚钱&#xff0c;通过爆款引来的流量带动其…

计算机| 关于CPU的12个知识点(图文详解)

CPU是什么&#xff1f; CPU与计算机的关系就相当于大脑和人的关系&#xff0c;它是一种小型的计算机芯片&#xff0c;通常嵌入在电脑的主板上。 CPU的构建是通过在单个计算机芯片上放置数十亿个微型晶体管来实现。 这些晶体管使它能够执行运行存储在系统内存中的程序所需的计…

JS手写浅拷贝与深拷贝

目录 1、引言 2、深拷贝与浅拷贝介绍 2.1、概念 2.2、实现方式 3、手写代码 1、引言 要了解浅拷贝与深拷贝&#xff0c;首先要知道 堆 和 栈 的概念 堆栈&#xff1a; 就是存放数据的地方&#xff08;不管是定义的数字、字符串、对象还是数组、函数等等&#xff0c;都会在…

学习HM微博项目第10天

步骤&#xff1a;发微博12-表情键盘06-点击表情 -> 发微博13-表情键盘07-插入表情和封装textView -> 发微博14-表情键盘08-长按表情 -> 发微博15-表情键盘09-最近表情 -> 发微博16-表情键盘10-最近表情完善 发微博12-表情键盘06-点击表情 APP的演示动画&#xff…

完全自学C(干货) —— 预处理详解

目录 一&#xff0c;预定义符号 二&#xff0c;#define #define定义的标识符 #define定义宏 # ## 带副作用的宏参数 宏和函数的对比 #undef 三&#xff0c;命令行定义 四&#xff0c;条件编译 五&#xff0c;文件包含 #include 六&#xff0c;其他预处理指令 一&…

搞的谁还不会爬福利美女跳舞视频一样,用我这个方法非常简单。

大家好啊&#xff01;经常听别人说爬虫玩的好&#xff0c;*****&#xff01;其实没有这么恐怖&#xff0c;爬虫你一般都是采集公开的信息&#xff0c;所以不会像网络传言那样&#xff0c;大家只要遵守协议&#xff0c;不会出问题的。 话说学编程语言的应该都是男孩子哈&#xf…