- 目前进度:多边形的平移、旋转、缩放
一、实验目的
- 实现线段、圆和多边形的基本2D几何变换
- 平移
- 旋转(含基准点)
- 缩放(含基准点)
二、实验环境
- Visual Studio 2019
- Windows 10
三、算法分析与设计
多边形
平移
对于多边形的各顶点添加一段平移距离,
{
x
′
=
x
+
t
x
y
′
=
y
+
t
y
\begin{cases} x'=x+tx\\ y'=y+ty \end{cases}
{x′=x+txy′=y+ty
记原多边形顶点为
P
P
P,平移后的多边形顶点为
P
′
P'
P′,平移向量为
T
T
T,则
P
=
[
x
y
]
,
P
′
=
[
x
′
y
′
]
,
T
=
[
t
x
t
y
]
P=\left[\begin{matrix} x\\y \end{matrix}\right],P'=\left[\begin{matrix} x'\\y' \end{matrix}\right],T=\left[\begin{matrix} tx\\ty \end{matrix}\right]
P=[xy],P′=[x′y′],T=[txty]
P ′ = P + T P'=P+T P′=P+T
旋转
对于多边形的各顶点,绕基准点
(
x
r
,
y
r
)
(x_r,y_r)
(xr,yr)逆时针旋转角度
θ
\theta
θ,
{
x
′
−
x
r
=
(
x
−
x
r
)
c
o
s
θ
−
(
y
−
y
r
)
s
i
n
θ
y
′
−
y
r
=
(
x
−
x
r
)
s
i
n
θ
+
(
y
−
y
r
)
c
o
s
θ
\begin{cases} x'-x_r=(x-x_r){\rm cos}\theta-(y-y_r){\rm sin}\theta \\ y'-y_r=(x-x_r){\rm sin}\theta+(y-y_r){\rm cos}\theta \end{cases}
{x′−xr=(x−xr)cosθ−(y−yr)sinθy′−yr=(x−xr)sinθ+(y−yr)cosθ
P ′ = R ⋅ P , R = [ c o s θ − s i n θ s i n θ c o s θ ] P'=R\cdot P,\quad R= \left[ \begin{matrix} {\rm cos}\theta & -{\rm sin}\theta \\ {\rm sin}\theta & {\rm cos}\theta \end{matrix} \right] P′=R⋅P,R=[cosθsinθ−sinθcosθ]
缩放
对于多边形的各顶点,保持基准点不动进行缩放,其中
s
x
,
s
y
s_x,s_y
sx,sy为
x
,
y
x,y
x,y方向的缩放比例。
{
x
′
=
x
⋅
s
x
y
′
=
y
⋅
s
y
\begin{cases} x'=x\cdot s_x \\ y'=y\cdot s_y \end{cases}
{x′=x⋅sxy′=y⋅sy
P ′ = S ⋅ P , S = [ s x 0 0 s y ] P'=S\cdot P,\quad S= \left[ \begin{matrix} s_x & 0 \\ 0 & s_y \end{matrix} \right] P′=S⋅P,S=[sx00sy]
四、实验结果
五、附录
#include<GL/glew.h>
#include <GLFW/glfw3.h>
#include<bits/stdc++.h>
#define PI acos(-1)
using namespace std;
struct wcPt2D
{
GLfloat x, y;
};
wcPt2D verts[3];
wcPt2D pivPt;
void getVerts(wcPt2D* verts)
{
verts[0].x = -0.7;
verts[0].y = 0.5;
verts[1].x = -0.5;
verts[1].y = 0.7;
verts[2].x = -0.6;
verts[2].y = 0.7;
}
/*画出原来的多边形*/
void drawOriginalPolygon(wcPt2D* verts, GLint nVerts)
{
glBegin(GL_POLYGON);
for (int k = 0; k < nVerts; k++)
{
glVertex2f(verts[k].x, verts[k].y);
}
glEnd();
}
/*平移多边形*/
void translatePolygon(wcPt2D* verts, GLint nVerts, GLfloat tx, GLfloat ty)
// (tx,ty)为平移向量
{
wcPt2D* tmp = new wcPt2D[nVerts];
for (int k = 0; k < nVerts; k++)
{
tmp[k].x = verts[k].x + tx;
tmp[k].y = verts[k].y + ty;
}
glBegin(GL_POLYGON);
for (int k = 0; k < nVerts; k++)
{
glVertex2f(tmp[k].x, tmp[k].y);
}
glEnd();
}
/*旋转多边形*/
void rotatePolygon(wcPt2D* verts, GLint nVerts, wcPt2D pivPt, GLdouble theta)
// pivPt:基准点;theta:逆时针旋转角度
{
float xr = pivPt.x;
float yr = pivPt.y;
wcPt2D* tmp = new wcPt2D[nVerts];
for (int k = 0; k < nVerts; k++)
{
tmp[k].x = xr + (verts[k].x - xr) * cos(theta) - (verts[k].y - yr) * sin(theta);
tmp[k].y = yr + (verts[k].x - xr) * sin(theta) + (verts[k].y - yr) * cos(theta);
}
glBegin(GL_POLYGON);
for (int k = 0; k < nVerts; k++)
{
glVertex2f(tmp[k].x, tmp[k].y);
}
glEnd();
}
/*缩放多边形*/
void scalePolygon(wcPt2D* verts, GLint nVerts, wcPt2D pivPt, GLfloat sx, GLfloat sy)
// pivPt:基准点
{
float xr = pivPt.x;
float yr = pivPt.y;
wcPt2D* tmp = new wcPt2D[nVerts];
for (int k = 0; k < nVerts; k++)
{
tmp[k].x = sx * verts[k].x + (1 - sx) * xr;
tmp[k].y = sy * verts[k].y + (1 - sy) * yr;
}
glBegin(GL_POLYGON);
for (int k = 0; k < nVerts; k++)
{
glVertex2f(tmp[k].x, tmp[k].y);
}
glEnd();
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK)
cout << "Error!" << endl;
// cout << glGetString(GL_VERSION) << endl;
getVerts(verts);
cout << verts[1].x << endl;
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
drawOriginalPolygon(verts,3);
translatePolygon(verts, 3, 0.5f, 0.0f);
pivPt.x = 0.0f;
pivPt.y = 0.0f;
//pivPt = verts[0];
rotatePolygon(verts, 3, pivPt, PI / 3);
scalePolygon(verts, 3, pivPt, 0.5f, 0.5f);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}