二维旋转
通过指定一个旋转轴(rotation axis)和一个旋转角度(rotation angle),可以进行一次旋转(rotation)变换。在将对象的所有顶点按指定角度绕指定旋转轴旋转后,该对象的所有点都旋转到新位置。
一个对象的二维旋转通过在xy平面上沿圆路径将对象重定位来实现。此时,我们将对象绕与xy平面垂直的旋转轴(与z轴平行)旋转。三维旋转的参数有旋转角θ和称为旋转点(rotation point或pivot point )的位置( x r , y r ),对象绕该点旋转(如下图)。基准点是旋转轴与xy平面的交点。正角度θ定义绕基准点的逆时针旋转(如下图),而负角度将对象沿顺时针方向旋转。
为了简化该基本方法的叙述,我们首先确定当基准点为坐标原点时点位置P进行旋转的变换方程。原始点和变换后点位置的角度和坐标关系如图所示。其中,r是点到原点的固定距离,角Φ是点的原始角度位置与水平线的夹角,θ是旋转角。应用标准的三角等式,我们可以利用角度θ和Φ将转换后的坐标表示为方程1:
在极坐标系中,点的原始坐标为方程2:
将方程2代人方程1中,我们就得到相对于原点,将位置(x, y)的点旋转θ角的变换方程3:
因为列向量表达式表示坐标位置为:
那么旋转方程的矩阵形式为方程4:
其中,旋转矩阵为
列向量表达式中坐标位置P的列向量是标准的数学表示。然而,早期的图形系统有时用行向量表示坐标位置,这会改变执行旋转时矩阵相乘的次序。但现在,OpenGL, Java, PHIGS和GKS都按标准列向量方式表示。
方程2中给出了绕任意基准点旋转一个点的例子。利用图中的三角关系,可以将方程3规范化为绕任意指定的旋转位置(
x
r
, y
r
))旋转的点的变换方程5:
这个通用旋转方程不同于方程3,该方程包含了一个加项以及在坐标值上的多重系数。因此,通过其中的元素包含方程5中的加项(平移项)的列向量矩阵加法,就可以修改矩阵方程4,使其包括基准点坐标。然而,还有更好的方法可以形成这样的矩阵公式,在4.2节
我们将讨论表达变换公式的更一致的方法。
类似于平移,旋转是一种不变形地移动对象的刚体变换,对象上的所有点旋转相同的角度。线段的旋转可以通过将旋转方程5用于每个线段端点,并重新绘制新端点间的线段而得到。多边形的旋转则是将每个顶点旋转指定的旋转角,并使用新的顶点来生成多边形而实现旋转。曲线的旋转通过定位定义的点并重新绘制曲线而完成。例如圆或椭圆,可以通过将中心位置沿指定旋转角对着的弧移动而绕非中心轴旋转。椭圆可通过旋转其长轴和短轴来实现绕其中心位置的旋转。
通过指定一个旋转轴(rotation axis)和一个旋转角度(rotation angle),可以进行一次旋转(rotation)变换。在将对象的所有顶点按指定角度绕指定旋转轴旋转后,该对象的所有点都旋转到新位置。
一个对象的二维旋转通过在xy平面上沿圆路径将对象重定位来实现。此时,我们将对象绕与xy平面垂直的旋转轴(与z轴平行)旋转。三维旋转的参数有旋转角θ和称为旋转点(rotation point或pivot point )的位置( x r , y r ),对象绕该点旋转(如下图)。基准点是旋转轴与xy平面的交点。正角度θ定义绕基准点的逆时针旋转(如下图),而负角度将对象沿顺时针方向旋转。
为了简化该基本方法的叙述,我们首先确定当基准点为坐标原点时点位置P进行旋转的变换方程。原始点和变换后点位置的角度和坐标关系如图所示。其中,r是点到原点的固定距离,角Φ是点的原始角度位置与水平线的夹角,θ是旋转角。应用标准的三角等式,我们可以利用角度θ和Φ将转换后的坐标表示为方程1:
在极坐标系中,点的原始坐标为方程2:
将方程2代人方程1中,我们就得到相对于原点,将位置(x, y)的点旋转θ角的变换方程3:
其中,旋转矩阵为
这个通用旋转方程不同于方程3,该方程包含了一个加项以及在坐标值上的多重系数。因此,通过其中的元素包含方程5中的加项(平移项)的列向量矩阵加法,就可以修改矩阵方程4,使其包括基准点坐标。然而,还有更好的方法可以形成这样的矩阵公式,在4.2节
我们将讨论表达变换公式的更一致的方法。
类似于平移,旋转是一种不变形地移动对象的刚体变换,对象上的所有点旋转相同的角度。线段的旋转可以通过将旋转方程5用于每个线段端点,并重新绘制新端点间的线段而得到。多边形的旋转则是将每个顶点旋转指定的旋转角,并使用新的顶点来生成多边形而实现旋转。曲线的旋转通过定位定义的点并重新绘制曲线而完成。例如圆或椭圆,可以通过将中心位置沿指定旋转角对着的弧移动而绕非中心轴旋转。椭圆可通过旋转其长轴和短轴来实现绕其中心位置的旋转。
在下列程序示例中,一个多边形绕指定的世界坐标系中的基准点旋转。旋转过程的输入参数是原始的多边形顶点、基准点坐标和用弧度表示的旋转角θ,多边形用OpenGL子程序重新生成。
class wcPt2D {
public:
GLfloat x, y;
};
void rotatePolyon (wcPt2D * verts, GLint nVerts, wcPt2D pivPt, GLdouble theta)
{
wcPt2D * vertsRot;
GLint k;
for (k = 0; k < nVerts; k++){
vertsRot [k].x = pivPt.x + (verts [k].x - pivPt.x) * cos(theta) - (verts [k].y - pivPt.y) * sin(theta);
vertsRot [k].y = pivPt.y + (verts [k].x - pivPt.x) * sin(theta) + (verts [k].y - pivPt.y) * cos(theta);
}
glBegin {GL_POLYGON};
for(k = 0; k < nVerts; k++)
glVertex2f (vertsRot [k].x, vertsRot [k].y);
glEnd();
}