二维坐标基本变换(平移、旋转、缩放、镜像、阵列)

诸如图像、模型等的基本变换,实际上都是点坐标的变换,通过矩阵,可以非常方便的达到这个目的。在下文仅介绍二维坐标变换原理。

首先,定义点类如下:

//定义点类,亦可表示向量
class vec2
{
public:
	float v[2];//v[0]为横坐标,v[1]为纵坐标
	vec2(){}
	~vec2(){}
	//构造函数,例vec2 p(0,0);表示构造p点坐标为(0,0)
	vec2(const float &x, const float &y){v[0] = x; v[1] = y;}
	//重载[],如vec2 p ;p[0]即表示x坐标值,p[1]表示y坐标值
	float &operator[] (int i) { return v[i]; }
	const float &operator[] (int i) const { return v[i]; }
};

注意,为了形式统一,变换矩阵应统一为3*3阶,同理,对于三维坐标变换矩阵应是4*4阶。关于矩阵的表示,实际上便是一个二维数组,其相关运算可以直接利用Eigen库,具体如何配置就不在此赘述。矩阵如何定义可参考如下,注意矩阵的初始化不应该是全部元素为0,而是对角元素为1,其余为0,即单位矩阵E.

class  Matrix2D 
{
public:
    double A[3][3];
} ; 

对于一点p_{i}表示为1*3的矩阵(x_{1},y_{1},1),则一个点集S = {p_{1},p_{2},...,p_{n}}表示为一个n*3的矩阵:

\begin{bmatrix} x_{1} &y_{1} &1 \\ x_{2} &y_{2} &1 \\ . &. &.\\ . &. &.\\ . &. &.\\ x_{n} &y_{n} &1 \end{bmatrix}

我们将这个矩阵称为原始矩阵T_{o},而后续的变换表示为这个矩阵乘以一个或多个矩阵,实则为两个二维数组的乘法与加法。

一、平移

对于平移我们需要知道一个平移的方向和平移的距离,因此可以通过一个向量表示这2个量,即

v_{t}\left(x_{v}, y_{v}\right),平移矩阵T_{t}表示为:

\left[\begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ x_{v} & y_{v} & 1 \end{array}\right]

 平移后的坐标即为T_{o}*T_{t}

二、旋转

对于旋转我们需要的是一个弧度θ,则旋转矩阵T_{r}表示为:

\left[\begin{array}{ccc} \cos \theta & \sin \theta & 0 \\ -\sin \theta & \cos \theta & 0 \\ 0 & 0 & 1 \end{array}\right]

 若只是乘上T_{r},表示的是坐标绕原点旋转,如果输入旋转中心C_{R}\left(x_{c}, y_{c}\right),应将目标点的坐标平移到旋转中心,完成旋转后再平移回来,变换矩阵应为T_{t}*T_{r}*T_{t}^{-1},即: 

 \left[\begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ x_{c} & y_{c} & 1 \end{array}\right]\left[\begin{array}{ccc} \cos \theta & \sin \theta & 0 \\ -\sin \theta & \cos \theta & 0 \\ 0 & 0 & 1 \end{array}\right]\left[\begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ -x_{c} & -y_{c} & 1 \end{array}\right]

 旋转后的坐标即为 T_{o}*T_{t} *T_{r}*T_{t}^{-1}

三、缩放

对于缩放我们需要的是一个缩放系数t,则缩放矩阵T_{z}表示为:

\left[\begin{array}{lll} t & 0 & 0 \\ 0 & t & 0 \\ 0 & 0 & 1 \end{array}\right]

若输入缩放中心C_{z}\left(x_{c}, y_{c}\right),同旋转,应先平移到缩放中心缩放完再平移回来。变换矩阵应为T_{t}*T_{z}*T_{t}^{-1},即:

\left[\begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ x_{c} & y_{c} & 1 \end{array}\right]\left[\begin{array}{lll} t & 0 & 0 \\ 0 & t & 0 \\ 0 & 0 & 1 \end{array}\right]\left[\begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ -x_{c} & -y_{c} & 1 \end{array}\right]

缩放后的坐标即为  T_{o}*T_{t}*T_{z}*T_{t}^{-1}

四、镜像

对于镜像,我们需要输入对称轴,即输入2个点p,q,但实际上计算需要的是对称轴的法向量v_{n}\left(x_{v}, y_{v}\right),通过p-q获得对称轴方向向量,再求其垂直向量即可。镜像矩阵T_{m}表示为:

\left[\begin{array}{ccc} 1-2 x_{v}{ }^{2} & -2 x_{v} y_{v} & 0 \\ -2 x_{v} y_{v} & 1-2 y_{v}{ }^{2} & 0 \\ 0 & 0 & 1 \end{array}\right]

另外就是需要一个表示对称轴位置的点,在输入的对称轴2点中随便取一点即可,表示为P_{m}\left(x_{\mathrm{m}}, y_{m}\right) ,变换矩阵为T_{t}*T_{m}*T_{t}^{-1},即:

\left[\begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ x_{\mathrm{m}} & y_{m} & 1 \end{array}\right]\left[\begin{array}{ccc} 1-2 x_{v}{ }^{2} & -2 x_{v} y_{v} & 0 \\ -2 x_{v} y_{v} & 1-2 y_{v}{ }^{2} & 0 \\ 0 & 0 & 1 \end{array}\right]\left[\begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ -x_{\mathrm{m}} & -y_{m} & 1 \end{array}\right]

镜像后的坐标即为T_{o}*T_{t}*T_{m}*T_{t}^{-1}

五、阵列

阵列可以分为环形阵列和方向阵列。

1.环形阵列

和旋转变换类似,输入阵列中心C_{R}\left(x_{c}, y_{c}\right),阵列数量N,通过不断旋转获得阵列对象,变换矩阵T_{ring}表示为:

\left[\begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ x_{c} & y_{c} & 1 \end{array}\right]\left[\begin{array}{ccc} \cos \frac{2 \pi i}{N} & \sin \frac{2 \pi i}{N} & 0 \\ -\sin \frac{2 \pi i}{N} & \cos \frac{2 \pi i}{N} & 0 \\ 0 & 0 & 1 \end{array}\right]\left[\begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ -x_{c} & -y_{c} & 1 \end{array}\right], i=1,2, \ldots, N

环形阵列的每个对象坐标为T_{o}*T_{ring}

2.方向阵列

和平移变换类似,输入2个点,表示阵列的方向,实际上我们需要的是单位方向向量v_{d}\left(x_{v}, y_{v}\right)、阵列对象之间的间距\Delta d和阵列数量N,其单位方向向量由输入的2个点相减后除以模长获得,变换矩阵T_{dir}表示为:

\left[\begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ i \cdot \Delta d \cdot x_{v} & i \cdot \Delta d \cdot y_{v} & 1 \end{array}\right], i=1,2, \ldots, N

方向阵列的每个对象坐标为T_{o}*T_{dir}。 

六、实现效果

在MFC中实现的效果如下图所示:

二维坐标基本变换(平移、旋转、缩放、镜像、阵列)_第1张图片二维坐标基本变换(平移、旋转、缩放、镜像、阵列)_第2张图片

二维坐标基本变换(平移、旋转、缩放、镜像、阵列)_第3张图片二维坐标基本变换(平移、旋转、缩放、镜像、阵列)_第4张图片

 二维坐标基本变换(平移、旋转、缩放、镜像、阵列)_第5张图片 二维坐标基本变换(平移、旋转、缩放、镜像、阵列)_第6张图片

你可能感兴趣的:(图形学相关,几何学,矩阵,c++,mfc)