计算机图形学12:二维图形的几何变换

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 计算机图形学12:二维图形的几何变换,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

在这里插入图片描述

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

专栏推荐

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

专栏系列文章

文章名称 文章地址
直线生成算法(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

1

]

=

T

2

D

[

x

y

1

]

=

[

a

b

p

c

d

q

l

m

s

]

[

x

y

1

]

\begin{bmatrix} x’&y’&1\\ \end{bmatrix}=T_{2D}\cdot\begin{bmatrix} x\\ y\\ 1\\ \end{bmatrix}=\begin{bmatrix} a&b&p\\ c&d&q\\ l&m&s\\ \end{bmatrix}\cdot\begin{bmatrix} x\\ y\\ 1\\ \end{bmatrix}

[xy1]=T2D
xy1
=

aclbdmpqs

xy1


二、工具函数/类代码实现

矩阵结构体及相关工具函数/类的代码实现如下:

// 一些基础的结构体定义及函数操作
struct VERTEX { int x, y; };	// 点结构

/// <summary>
/// 矩阵结构体
/// </summary>
struct Matrix {
	vector<vector<double>> matrix;
	Matrix() { // 初始化为 3 * 3 的矩阵
		matrix = vector<vector<double>>(3, vector<double>(3, 0.0));
		// 对角线元素置为1
		//matrix[0][0] = 1;
		//matrix[1][1] = 1;
		//matrix[2][2] = 1;
	}
	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;
}

三、平移变换

在这里插入图片描述

值得注意的是,无论是点、线、区,还是各种复杂图形的变换,最终都要转换到点的变换上来,比如:线的变换,我们采用中点BH算法去画线,那么我们其实不需要去变换线上的每一个点,只需要控制好起始点和中点就可以完成线的绘制。

[

x

y

1

]

=

[

1

0

T

x

0

1

T

y

0

0

1

]

[

x

y

1

]

=

[

x

+

T

x

y

+

T

y

1

]

\begin{bmatrix} x’&y’&1\\ \end{bmatrix}=\begin{bmatrix} 1&0&T_x\\ 0&1&T_y\\ 0&0&1\\ \end{bmatrix}\cdot\begin{bmatrix} x\\ y\\ 1\\ \end{bmatrix}=\cdot\begin{bmatrix} x+T_x\\ y+T_y\\ 1\\ \end{bmatrix}

[xy1]=
100010TxTy1

xy1
=

x+Txy+Ty1


平移变换OpenGL代码实现

平移变换的代码实现如下:

/// <summary>
/// 平移变换
/// </summary>
/// <param name="vertex">待平移的点</param>
/// <param name="x">横坐标平移距离</param>
/// <param name="y">纵坐标平移距离</param>
/// <returns>平移后的点</returns>
VERTEX transTransform(VERTEX vertex, int x, int y) {
	Matrix qiciVertex(3, 1); // 转化为其次坐标
	qiciVertex.matrix[0][0] = vertex.x;
	qiciVertex.matrix[1][0] = vertex.y;
	qiciVertex.matrix[2][0] = 1;
	Matrix transform;
	// 对角线元素
	transform.matrix[0][0] = 1;
	transform.matrix[1][1] = 1;
	transform.matrix[2][2] = 1;
	// 平移元素
	transform.matrix[0][2] = x;
	transform.matrix[1][2] = y;
	// 其次坐标结果
	Matrix qiciRes = dotMatrix(transform, qiciVertex);
	VERTEX res; // 顶点坐标结果
	res.x = qiciRes.matrix[0][0];
	res.y = qiciRes.matrix[1][0];
	return res;
}

四、伸缩变换

[

x

y

1

]

=

[

s

x

0

0

0

s

y

0

0

0

1

]

[

x

y

1

]

=

[

s

x

x

s

y

y

1

]

\begin{bmatrix} x’&y’&1\\ \end{bmatrix}=\begin{bmatrix} s_x&0&0\\ 0&s_y&0\\ 0&0&1\\ \end{bmatrix}\cdot\begin{bmatrix} x\\ y\\ 1\\ \end{bmatrix}=\cdot\begin{bmatrix} s_x\cdot x\\ s_y\cdot y\\ 1\\ \end{bmatrix}

[xy1]=
sx000sy0001

xy1
=

sxxsyy1


伸缩变换OpenGL代码实现

伸缩变换OpenGL代码实现如下:

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

/// <summary>
/// 伸缩变换
/// </summary>
/// <param name="vertex">待变换的点</param>
/// <param name="sx">x方向变换比例</param>
/// <param name="sy">y方向变换比例</param>
/// <returns>经过比例变换后的点</returns>
VERTEX scaleTransform(VERTEX vertex, double sx, double sy) {
	// 将二维点转化为齐次坐标
	Matrix qiciVertex = vertex2qici(vertex);
	Matrix transform;
	transform.matrix[0][0] = sx;
	transform.matrix[1][1] = sy;
	transform.matrix[2][2] = 1;
	Matrix qiciRes = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为点
	VERTEX res;
	res.x = qiciRes.matrix[0][0];
	res.y = qiciRes.matrix[0][1];
	return res;
}

五、旋转变化

在这里插入图片描述

[

x

y

1

]

=

[

c

o

s

θ

s

i

n

θ

0

s

i

n

θ

c

o

s

θ

0

0

0

1

]

[

x

y

1

]

=

[

x

c

o

s

θ

y

s

i

n

θ

x

s

i

n

θ

+

y

c

o

s

θ

1

]

\begin{bmatrix} x’&y’&1\\ \end{bmatrix}=\begin{bmatrix} cos\theta&-sin\theta&0\\ sin\theta&cos\theta&0\\ 0&0&1\\ \end{bmatrix}\cdot\begin{bmatrix} x\\ y\\ 1\\ \end{bmatrix}=\cdot\begin{bmatrix} x\cdot cos\theta-y\cdot sin\theta\\ x\cdot sin\theta +y\cdot cos\theta\\ 1\\ \end{bmatrix}

[xy1]=
cosθsinθ0sinθcosθ0001

xy1
=

xcosθysinθxsinθ+ycosθ1


旋转变化OpenGL代码实现

旋转变化的OpenGL代码实现如下:

/// <summary>
/// 旋转变换
/// </summary>
/// <param name="vertex">旋转变换的点</param>
/// <param name="theta">旋转的角度</param>
/// <returns>旋转后的点</returns>
VERTEX rotationTransform(VERTEX vertex, double theta) {
	// 将二维点转化为齐次坐标
	Matrix qiciVertex = vertex2qici(vertex);
	Matrix transform;
	transform.matrix[0][0] = cos(theta);
	transform.matrix[0][1] = -sin(theta);
	transform.matrix[1][0] = sin(theta);
	transform.matrix[1][1] = cos(theta);
	transform.matrix[2][2] = 1;
	Matrix qiciRes = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为点
	VERTEX res;
	res.x = qiciRes.matrix[0][0];
	res.y = qiciRes.matrix[0][1];
	return res;
}

六、对称变换

[

x

y

1

]

=

[

a

b

0

c

d

0

0

0

1

]

[

x

y

1

]

=

[

a

x

+

b

y

c

x

+

d

y

1

]

\begin{bmatrix} x’&y’&1\\ \end{bmatrix}=\begin{bmatrix} a&b&0\\ c&d&0\\ 0&0&1\\ \end{bmatrix}\cdot\begin{bmatrix} x\\ y\\ 1\\ \end{bmatrix}=\cdot\begin{bmatrix} a\cdot x+b\cdot y\\ c\cdot x +d\cdot y\\ 1\\ \end{bmatrix}

[xy1]=
ac0bd0001

xy1
=

ax+bycx+dy1

其中根据不同的变换类型,a、b、c、d被赋予不同的值,形成不同的变换矩阵,具体如下:

  • 与x轴对称

T

2

D

=

[

1

0

0

0

1

0

0

0

1

]

T_{2D}=\begin{bmatrix} 1&0&0\\ 0&-1&0\\ 0&0&1\\ \end{bmatrix}

T2D=
100010001

  • 与y轴对称

T

2

D

=

[

1

0

0

0

1

0

0

0

1

]

T_{2D}=\begin{bmatrix} -1&0&0\\ 0&1&0\\ 0&0&1\\ \end{bmatrix}

T2D=
100010001

  • 与原点对称

T

2

D

=

[

1

0

0

0

1

0

0

0

1

]

T_{2D}=\begin{bmatrix} -1&0&0\\ 0&-1&0\\ 0&0&1\\ \end{bmatrix}

T2D=
100010001

  • y

    =

    x

    y=x

    y=x轴对称

T

2

D

=

[

0

1

0

1

0

0

0

0

1

]

T_{2D}=\begin{bmatrix} 0&1&0\\ 1&0&0\\ 0&0&1\\ \end{bmatrix}

T2D=
010100001

  • y

    =

    x

    y=-x

    y=x轴对称

T

2

D

=

[

0

1

0

1

0

0

0

0

1

]

T_{2D}=\begin{bmatrix} 0&-1&0\\ -1&0&0\\ 0&0&1\\ \end{bmatrix}

T2D=
010100001


对称变换OpenGL代码实现

对称变换OpenGL代码实现如下:

/// <summary>
/// 关于x轴对称
/// </summary>
/// <param name="vertex">待变换的点</param>
/// <returns>变换后的点</returns>
VERTEX symmetricTransformForx(VERTEX vertex) {
	// 将二维点转化为齐次坐标
	Matrix qiciVertex = vertex2qici(vertex);
	// 生成变换矩阵
	Matrix transform;
	transform.matrix[0][0] = 1;
	transform.matrix[1][1] = -1;
	transform.matrix[2][2] = 1;
	// 进行变换
	Matrix qiciRes = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为点
	VERTEX res;
	res.x = qiciRes.matrix[0][0];
	res.y = qiciRes.matrix[0][1];
	return res;
}

/// <summary>
/// 关于y轴对称
/// </summary>
/// <param name="vertex">待变换的点</param>
/// <returns>变换后的点</returns>
VERTEX symmetricTransformFory(VERTEX vertex) {
	// 将二维点转化为齐次坐标
	Matrix qiciVertex = vertex2qici(vertex);
	// 生成变换矩阵
	Matrix transform;
	transform.matrix[0][0] = -1;
	transform.matrix[1][1] = 1;
	transform.matrix[2][2] = 1;
	// 进行变换
	Matrix qiciRes = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为点
	VERTEX res;
	res.x = qiciRes.matrix[0][0];
	res.y = qiciRes.matrix[0][1];
	return res;
}

/// <summary>
/// 关于原点对称
/// </summary>
/// <param name="vertex">待变换的点</param>
/// <returns>变换后的点</returns>
VERTEX symmetricTransformForO(VERTEX vertex) {
	// 将二维点转化为齐次坐标
	Matrix qiciVertex = vertex2qici(vertex);
	// 生成变换矩阵
	Matrix transform;
	transform.matrix[0][0] = -1;
	transform.matrix[1][1] = -1;
	transform.matrix[2][2] = 1;
	// 进行变换
	Matrix qiciRes = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为点
	VERTEX res;
	res.x = qiciRes.matrix[0][0];
	res.y = qiciRes.matrix[0][1];
	return res;
}

/// <summary>
/// 关于y=x直线对称
/// </summary>
/// <param name="vertex">待变换的点</param>
/// <returns>变换后的点</returns>
VERTEX symmetricTransformForYEqualX(VERTEX vertex) {
	// 将二维点转化为齐次坐标
	Matrix qiciVertex = vertex2qici(vertex);
	// 生成变换矩阵
	Matrix transform;
	transform.matrix[0][1] = 1;
	transform.matrix[1][0] = 1;
	transform.matrix[2][2] = 1;
	// 进行变换
	Matrix qiciRes = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为点
	VERTEX res;
	res.x = qiciRes.matrix[0][0];
	res.y = qiciRes.matrix[0][1];
	return res;
}

/// <summary>
/// 关于y=-x直线对称
/// </summary>
/// <param name="vertex">待变换的点</param>
/// <returns>变换后的点</returns>
VERTEX symmetricTransformForYNegativeEqualX(VERTEX vertex) {
	// 将二维点转化为齐次坐标
	Matrix qiciVertex = vertex2qici(vertex);
	// 生成变换矩阵
	Matrix transform;
	transform.matrix[0][1] = -1;
	transform.matrix[1][0] = -1;
	transform.matrix[2][2] = 1;
	// 进行变换
	Matrix qiciRes = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为点
	VERTEX res;
	res.x = qiciRes.matrix[0][0];
	res.y = qiciRes.matrix[0][1];
	return res;
}

七、错切变换

在这里插入图片描述

[

x

y

1

]

=

[

1

b

0

c

1

0

0

0

1

]

[

x

y

1

]

=

[

x

+

b

y

c

x

+

y

1

]

\begin{bmatrix} x’&y’&1\\ \end{bmatrix}=\begin{bmatrix} 1&b&0\\ c&1&0\\ 0&0&1\\ \end{bmatrix}\cdot\begin{bmatrix} x\\ y\\ 1\\ \end{bmatrix}=\cdot\begin{bmatrix} x+b\cdot y\\ c\cdot x +y\\ 1\\ \end{bmatrix}

[xy1]=
1c0b10001

xy1
=

x+bycx+y1


错切变换OpenGL代码实现

错切变换OpenGL代码实现如下:

/// <summary>
/// 错切变换
/// </summary>
/// <param name="vertex">待变换的点</param>
/// <param name="misXCut">X方向上错切的比例</param>
/// <param name="misYCut">Y方向上错切的比例</param>
/// <returns>变换后的点</returns>
VERTEX miscutTransform(VERTEX vertex, double misXCut, double misYCut) {
	// 将二维点转化为齐次坐标
	Matrix qiciVertex = vertex2qici(vertex);
	// 生成变换矩阵
	Matrix transform;
	transform.matrix[0][1] = misXCut;
	transform.matrix[1][0] = misYCut;
	transform.matrix[0][0] = 1;
	transform.matrix[1][1] = 1;
	transform.matrix[2][2] = 1;
	// 进行变换
	Matrix qiciRes = dotMatrix(transform, qiciVertex);
	// 将齐次坐标转化为点
	VERTEX res;
	res.x = qiciRes.matrix[0][0];
	res.y = qiciRes.matrix[0][1];
	return res;
}

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

相对某个参考点(xF,yF)作二维几何变换,其变换过程为:(分解成基本的几何变换)

  1. 平移(-xF,-yF) 。
  2. 针对原点进行二维几何变换。
  3. 反平移(+xF,+yF) 。

进行一个平移和反平移,转换成相对于原点的变换,来实现。


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

相对任意方向作二维几何变换,其变换的过程是:

  1. 旋转变换;
  2. 针对坐标轴进行二维几何变换;
  3. 反向旋转

旋转、反旋转,转化为相对于原点的变换。


十、坐标系之间的变换

在这里插入图片描述

[

x

y

1

]

=

T

R

T

T

[

x

y

1

]

=

[

x

+

b

y

c

x

+

y

1

]

\begin{bmatrix} x’&y’&1\\ \end{bmatrix}=T_{R}\cdot T_{T}\cdot\begin{bmatrix} x\\ y\\ 1\\ \end{bmatrix}=\cdot\begin{bmatrix} x+b\cdot y\\ c\cdot x +y\\ 1\\ \end{bmatrix}

[xy1]=TRTT
xy1
=

x+bycx+y1

即先进行平移变换,再进行旋转变换即可。


the end……

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/130472.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!