二維圖像的幾何變化
二維圖形基本幾何變換是指相對於座標原點和座標軸進行的幾何變換,包括平移(Translate)、比例(Scale)、旋轉(Rotate)、反射(Reflect)和錯切(shear)5種變換。物體變換物體變換是通過變換物體上每一個頂點實現的,因此以點的二維基本幾何變換爲例講解二維圖形基本幾何變換矩陣。
平移變換:
比例變換:
對稱變換:
旋轉變換:
錯切變換:
★複合矩陣編程實例:任一圖形關於任意的反射軸y=a+bx的反射變換。
解:(1)將座標原點平移到(0,a)處
(2)將反射軸(已平移後的直線)按順時針方向旋轉θ角,使之與x軸重合
(3)圖形關於x軸的反射變換
(4)將反射軸逆時針旋轉θ角
(5)恢復反射軸的原始位置
因此T=T₁R(-θ)T₂R(θ)T₃
具體代碼如下:
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
GLsizei winWidth = 600, winHeight = 600;/* 初始化顯示窗口大小 */
GLfloat xwcMin = 0.0, xwcMax = 250.0; /* 設置世界座標系的顯示範圍 */
GLfloat ywcMin = 0.0, ywcMax = 250.0;
class wcPt2D/* 定義二維點數據結構 */
{
public:
GLfloat x, y;
};
typedef GLfloat Matrix3x3[3][3];
Matrix3x3 matComposite; //定義複合矩陣
void init(void)
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);//設置窗口背景顏色爲白色
}
void matrix3x3SetIdentity(Matrix3x3 m) /* 構建3*3的單位矩陣 */
{
GLint i, j;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
m[i][j] = (i == j);
}
void matrix3x3PreMultiply(Matrix3x3 a, Matrix3x3 b) /* 變換矩陣a前乘矩陣b,儲存結果到b中 */
{
GLint r, c;
Matrix3x3 temp;
for (r = 0; r < 3; r++)
for (c = 0; c < 3; c++)
temp[r][c] = a[r][0] * b[0][c] + a[r][1] * b[1][c] + a[r][2] * b[2][c];
for (r = 0; r < 3; r++)
for (c = 0; c < 3; c++)
b[r][c] = temp[r][c];
}
void reflectionX()/* 關於x軸對稱變換函數*/
{
Matrix3x3 m;
matrix3x3SetIdentity(m);/* 初始化對稱矩陣爲單位矩陣 */
m[0][0] = 1;
m[1][1] = -1;
m[0][1] = 0;
m[1][0] = 0;
matrix3x3PreMultiply(m, matComposite);/* 將對稱矩陣前乘到複合矩陣matComposite中 */
}
void translate2D(GLfloat tx, GLfloat ty)/* 平移變換函數,平移量tx,ty */
{
Matrix3x3 m;
matrix3x3SetIdentity(m);/* 初始化平移矩陣爲單位矩陣 */
m[0][2] = tx;
m[1][2] = ty;
matrix3x3PreMultiply(m, matComposite);/* 將平移矩陣前乘到複合矩陣matComposite中 */
}
void rotate2D(wcPt2D pivotPt, GLfloat theta)/* 旋轉變換函數,參數爲中心點pivotPt和旋轉角度theta */
{
Matrix3x3 m;
matrix3x3SetIdentity(m);/* 初始化旋轉矩陣爲單位矩陣 */
m[0][0] = cos(theta);
m[0][1] = -sin(theta);
m[0][2] = pivotPt.x*(1 - cos(theta)) + pivotPt.y*sin(theta);
m[1][0] = sin(theta);
m[1][1] = cos(theta);
m[1][2] = pivotPt.y*(1 - cos(theta)) - pivotPt.x*sin(theta);
matrix3x3PreMultiply(m, matComposite);/* 將旋轉矩陣前乘到複合矩陣matComposite中 */
}
void transformVerts2D(GLint nVerts, wcPt2D * verts)/* 利用複合矩陣計算變換後坐標 */
{
GLint k;
GLfloat temp;
for (k = 0; k < nVerts; k++)
{
temp = matComposite[0][0] * verts[k].x + matComposite[0][1] * verts[k].y + matComposite[0][2];
verts[k].y = matComposite[1][0] * verts[k].x + matComposite[1][1] * verts[k].y + matComposite[1][2];
verts[k].x = temp;
}
}
void triangle(wcPt2D * verts) /* 三角形和直線繪製函數 */
{
GLint k;
glBegin(GL_TRIANGLES);
for (k = 0; k < 3; k++)
glVertex2f(verts[k].x, verts[k].y);
glEnd();
glBegin(GL_LINE_LOOP);
for (k = 3; k < 5; k++)
glVertex2f(verts[k].x, verts[k].y);
glEnd();
}
void displayFcn(void)
{
/* 定義三角形和直線的初始位置 */
GLint nVerts = 5;
wcPt2D verts[5] = { {40.0,14.0},{110.0,14.0},{110.0,55.0} ,{0.0,10.0},{160.0,90.0} };
wcPt2D centroidPt1;
centroidPt1.x = 0;
centroidPt1.y = 0;
wcPt2D pivotPt;
pivotPt = centroidPt1;
GLfloat tx = 0.0, ty1 = -10.0, ty2 = 10.0;
GLdouble theta = -atan((verts[4].y - verts[3].y) / (verts[4].x - verts[3].x));
GLdouble theta1 = atan((verts[4].y - verts[3].y) / (verts[4].x - verts[3].x));
glClear(GL_COLOR_BUFFER_BIT); // 清空顯示窗口
glColor3f(0.0, 0.0, 1.0); // 設置前景色爲藍色
triangle(verts); //顯示藍色三角形(變換前)
matrix3x3SetIdentity(matComposite);
/* 初始化複合矩陣爲單位矩陣 */
/* 根據變換序列重建複合矩陣 */
translate2D(tx, ty1); //變換序列1:平移變換
rotate2D(pivotPt, theta); //變換序列2:旋轉變換
reflectionX(); //變換序列3:對稱變換
rotate2D(pivotPt, theta1); //變換序列4:旋轉變換
translate2D(tx, ty2);//變換序列5:平移變換
transformVerts2D(nVerts, verts);/* 應用複合矩陣到三角形 */
glColor3f(1.0, 0.0, 0.0); //重新設置前景色爲紅色
triangle(verts); //顯示紅色三角形(變換後)
glFlush();
}
void winReshapeFcn(GLint newWidth, GLint newHeight)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(xwcMin, xwcMax, ywcMin, ywcMax);
glClear(GL_COLOR_BUFFER_BIT);
}
void main(int argc, char ** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(50, 50);
glutInitWindowSize(winWidth, winHeight);
glutCreateWindow("二維幾何變換實例-複合變換");
init();
glutDisplayFunc(displayFcn);
glutReshapeFunc(winReshapeFcn);
glutMainLoop();
}