222
This commit is contained in:
+3
-3
@@ -52,7 +52,7 @@ void init() { // 定义 OpenGL 初始化函数。
|
|||||||
glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式。
|
glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式。
|
||||||
glLoadIdentity(); // 将当前投影矩阵重置为单位矩阵。
|
glLoadIdentity(); // 将当前投影矩阵重置为单位矩阵。
|
||||||
gluOrtho2D(0.0, WIDTH, 0.0, HEIGHT); // 设置二维正交投影范围。
|
gluOrtho2D(0.0, WIDTH, 0.0, HEIGHT); // 设置二维正交投影范围。
|
||||||
} // 初始化函数结束。
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) { // 程序入口函数。
|
int main(int argc, char** argv) { // 程序入口函数。
|
||||||
glutInit(&argc, argv); // 初始化 GLUT。
|
glutInit(&argc, argv); // 初始化 GLUT。
|
||||||
@@ -63,5 +63,5 @@ int main(int argc, char** argv) { // 程序入口函数。
|
|||||||
init(); // 调用初始化函数。
|
init(); // 调用初始化函数。
|
||||||
glutDisplayFunc(display); // 注册显示回调函数。
|
glutDisplayFunc(display); // 注册显示回调函数。
|
||||||
glutMainLoop(); // 进入 GLUT 事件循环。
|
glutMainLoop(); // 进入 GLUT 事件循环。
|
||||||
return 0; // 程序正常结束。
|
return 0;
|
||||||
} // 主函数结束。
|
}
|
||||||
+56
-56
@@ -1,5 +1,4 @@
|
|||||||
#include <GL/glut.h> // 引入 OpenGL 头文件,提供窗口和绘图函数。
|
#include <GL/glut.h> // 引入 OpenGL 头文件,提供窗口和绘图函数。
|
||||||
#include <iostream> // 引入输入输出流库,便于需要时输出调试信息。
|
|
||||||
|
|
||||||
// 定义区域编码
|
// 定义区域编码
|
||||||
#define INSIDE 0 // 0000,表示点在裁剪窗口内部。
|
#define INSIDE 0 // 0000,表示点在裁剪窗口内部。
|
||||||
@@ -12,21 +11,44 @@ struct ClipWindow { // 定义用于保存裁剪窗口边界的结构体。
|
|||||||
float xmin, xmax, ymin, ymax; // 保存裁剪窗口的左、右、下、上边界。
|
float xmin, xmax, ymin, ymax; // 保存裁剪窗口的左、右、下、上边界。
|
||||||
}; // 结构体定义结束。
|
}; // 结构体定义结束。
|
||||||
|
|
||||||
ClipWindow rect; // 定义全局裁剪窗口对象。
|
struct Point { // 定义二维点结构体。
|
||||||
int x_0, y_0, x_1, y_1; // 定义线段端点坐标变量。
|
float x, y; // 保存点的横坐标和纵坐标。
|
||||||
|
}; // 点结构体定义结束。
|
||||||
|
|
||||||
int computeCode(float x, float y, ClipWindow rect) { // 根据点坐标和裁剪窗口计算区域编码。
|
ClipWindow rect; // 定义全局裁剪窗口对象。
|
||||||
|
Point lineStart = {60, 80}; // 定义原始线段起点。
|
||||||
|
Point lineEnd = {520, 360}; // 定义原始线段终点。
|
||||||
|
|
||||||
|
int computeCode(Point p, ClipWindow rect) { // 根据点坐标和裁剪窗口计算区域编码。
|
||||||
int code = INSIDE; // 初始认为点在窗口内部。
|
int code = INSIDE; // 初始认为点在窗口内部。
|
||||||
if (x < rect.xmin) code |= LEFT; // 如果点在左边界外,则添加 LEFT 标记。
|
if (p.x < rect.xmin) code |= LEFT; // 如果点在左边界外,则添加 LEFT 标记。
|
||||||
else if (x > rect.xmax) code |= RIGHT; // 如果点在右边界外,则添加 RIGHT 标记。
|
else if (p.x > rect.xmax) code |= RIGHT; // 如果点在右边界外,则添加 RIGHT 标记。
|
||||||
if (y < rect.ymin) code |= BOTTOM; // 如果点在下边界外,则添加 BOTTOM 标记。
|
if (p.y < rect.ymin) code |= BOTTOM; // 如果点在下边界外,则添加 BOTTOM 标记。
|
||||||
else if (y > rect.ymax) code |= TOP; // 如果点在上边界外,则添加 TOP 标记。
|
else if (p.y > rect.ymax) code |= TOP; // 如果点在上边界外,则添加 TOP 标记。
|
||||||
return code; // 返回最终区域编码。
|
return code; // 返回最终区域编码。
|
||||||
}
|
}
|
||||||
|
|
||||||
void cohenSutherlandClip(float& x_0, float& y_0, float& x_1, float& y_1, ClipWindow rect) { // 定义 Cohen-Sutherland 线段裁剪函数。
|
void drawLine(Point p1, Point p2, float r, float g, float b) { // 按指定颜色绘制一条线段。
|
||||||
int code1 = computeCode(x_0, y_0, rect); // 计算第一个端点的区域编码。
|
glColor3f(r, g, b); // 设置线段颜色。
|
||||||
int code2 = computeCode(x_1, y_1, rect); // 计算第二个端点的区域编码。
|
glBegin(GL_LINES); // 开始绘制线段。
|
||||||
|
glVertex2f(p1.x, p1.y); // 提交第一个端点。
|
||||||
|
glVertex2f(p2.x, p2.y); // 提交第二个端点。
|
||||||
|
glEnd(); // 结束绘制。
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawClipWindow(ClipWindow rect) { // 绘制裁剪窗口。
|
||||||
|
glColor3f(1.0f, 0.0f, 0.0f); // 设置绘制颜色为红色。
|
||||||
|
glBegin(GL_LINE_LOOP); // 开始绘制闭合线框。
|
||||||
|
glVertex2f(rect.xmin, rect.ymin); // 提交裁剪窗口左下角顶点。
|
||||||
|
glVertex2f(rect.xmax, rect.ymin); // 提交裁剪窗口右下角顶点。
|
||||||
|
glVertex2f(rect.xmax, rect.ymax); // 提交裁剪窗口右上角顶点。
|
||||||
|
glVertex2f(rect.xmin, rect.ymax); // 提交裁剪窗口左上角顶点。
|
||||||
|
glEnd(); // 结束闭合线框顶点提交。
|
||||||
|
}
|
||||||
|
|
||||||
|
void cohenSutherlandClip(Point p1, Point p2, ClipWindow rect) { // 定义 Cohen-Sutherland 线段裁剪函数。
|
||||||
|
int code1 = computeCode(p1, rect); // 计算第一个端点的区域编码。
|
||||||
|
int code2 = computeCode(p2, rect); // 计算第二个端点的区域编码。
|
||||||
bool accept = false; // 定义是否接受裁剪结果的标志,初始为 false。
|
bool accept = false; // 定义是否接受裁剪结果的标志,初始为 false。
|
||||||
|
|
||||||
while (true) { // 不断处理线段,直到确定接受或舍弃。
|
while (true) { // 不断处理线段,直到确定接受或舍弃。
|
||||||
@@ -42,7 +64,7 @@ void cohenSutherlandClip(float& x_0, float& y_0, float& x_1, float& y_1, ClipWin
|
|||||||
// 3. 线段部分在窗口内,需要求交点。
|
// 3. 线段部分在窗口内,需要求交点。
|
||||||
else { // 线段部分可见,需要把窗口外端点裁到边界上。
|
else { // 线段部分可见,需要把窗口外端点裁到边界上。
|
||||||
int code_out; // 保存当前选中的窗口外端点区域编码。
|
int code_out; // 保存当前选中的窗口外端点区域编码。
|
||||||
float x, y; // 保存线段与裁剪边界的交点坐标。
|
Point crossPoint; // 保存线段与裁剪边界的交点坐标。
|
||||||
// 选择窗口外的一个端点。
|
// 选择窗口外的一个端点。
|
||||||
if (code1 != 0) // 如果第一个端点在窗口外。
|
if (code1 != 0) // 如果第一个端点在窗口外。
|
||||||
code_out = code1; // 选择第一个端点作为待裁剪端点。
|
code_out = code1; // 选择第一个端点作为待裁剪端点。
|
||||||
@@ -50,70 +72,48 @@ void cohenSutherlandClip(float& x_0, float& y_0, float& x_1, float& y_1, ClipWin
|
|||||||
code_out = code2; // 选择第二个端点作为待裁剪端点。
|
code_out = code2; // 选择第二个端点作为待裁剪端点。
|
||||||
// 计算交点。
|
// 计算交点。
|
||||||
if (code_out & TOP) { // 如果端点在上边界外,则与上边界求交。
|
if (code_out & TOP) { // 如果端点在上边界外,则与上边界求交。
|
||||||
x = x_0 + (x_1 - x_0) * (rect.ymax - y_0) / (y_1 - y_0); // 根据直线参数方程计算交点 x 坐标。
|
crossPoint.x = p1.x + (p2.x - p1.x) * (rect.ymax - p1.y) / (p2.y - p1.y); // 根据直线参数方程计算交点 x 坐标。
|
||||||
y = rect.ymax; // 交点 y 坐标等于上边界。
|
crossPoint.y = rect.ymax; // 交点 y 坐标等于上边界。
|
||||||
} // 上边界求交结束。
|
} // 上边界求交结束。
|
||||||
else if (code_out & BOTTOM) { // 如果端点在下边界外,则与下边界求交。
|
else if (code_out & BOTTOM) { // 如果端点在下边界外,则与下边界求交。
|
||||||
x = x_0 + (x_1 - x_0) * (rect.ymin - y_0) / (y_1 - y_0); // 根据直线参数方程计算交点 x 坐标。
|
crossPoint.x = p1.x + (p2.x - p1.x) * (rect.ymin - p1.y) / (p2.y - p1.y); // 根据直线参数方程计算交点 x 坐标。
|
||||||
y = rect.ymin; // 交点 y 坐标等于下边界。
|
crossPoint.y = rect.ymin; // 交点 y 坐标等于下边界。
|
||||||
} // 下边界求交结束。
|
} // 下边界求交结束。
|
||||||
else if (code_out & RIGHT) { // 如果端点在右边界外,则与右边界求交。
|
else if (code_out & RIGHT) { // 如果端点在右边界外,则与右边界求交。
|
||||||
y = y_0 + (y_1 - y_0) * (rect.xmax - x_0) / (x_1 - x_0); // 根据直线参数方程计算交点 y 坐标。
|
crossPoint.y = p1.y + (p2.y - p1.y) * (rect.xmax - p1.x) / (p2.x - p1.x); // 根据直线参数方程计算交点 y 坐标。
|
||||||
x = rect.xmax; // 交点 x 坐标等于右边界。
|
crossPoint.x = rect.xmax; // 交点 x 坐标等于右边界。
|
||||||
} // 右边界求交结束。
|
} // 右边界求交结束。
|
||||||
else if (code_out & LEFT) { // 如果端点在左边界外,则与左边界求交。
|
else if (code_out & LEFT) { // 如果端点在左边界外,则与左边界求交。
|
||||||
y = y_0 + (y_1 - y_0) * (rect.xmin - x_0) / (x_1 - x_0); // 根据直线参数方程计算交点 y 坐标。
|
crossPoint.y = p1.y + (p2.y - p1.y) * (rect.xmin - p1.x) / (p2.x - p1.x); // 根据直线参数方程计算交点 y 坐标。
|
||||||
x = rect.xmin; // 交点 x 坐标等于左边界。
|
crossPoint.x = rect.xmin; // 交点 x 坐标等于左边界。
|
||||||
} // 左边界求交结束。
|
} // 左边界求交结束。
|
||||||
|
|
||||||
// 用交点替换原来的外部端点。
|
// 用交点替换原来的外部端点。
|
||||||
if (code_out == code1) { // 如果被裁剪的是第一个端点。
|
if (code_out == code1) { // 如果被裁剪的是第一个端点。
|
||||||
x_0 = x; y_0 = y; // 用交点更新第一个端点坐标。
|
p1 = crossPoint; // 用交点更新第一个端点坐标。
|
||||||
code1 = computeCode(x_0, y_0, rect); // 重新计算第一个端点的区域编码。
|
code1 = computeCode(p1, rect); // 重新计算第一个端点的区域编码。
|
||||||
} // 第一个端点更新结束。
|
} // 第一个端点更新结束。
|
||||||
else { // 否则被裁剪的是第二个端点。
|
else { // 否则被裁剪的是第二个端点。
|
||||||
x_1 = x; y_1 = y; // 用交点更新第二个端点坐标。
|
p2 = crossPoint; // 用交点更新第二个端点坐标。
|
||||||
code2 = computeCode(x_1, y_1, rect); // 重新计算第二个端点的区域编码。
|
code2 = computeCode(p2, rect); // 重新计算第二个端点的区域编码。
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 如果接受,则绘制裁剪后的线段(蓝色)。
|
// 如果接受,则绘制裁剪后的线段(蓝色)。
|
||||||
if (accept) { // 如果线段最终被接受。
|
if (accept) { // 如果线段最终被接受。
|
||||||
glBegin(GL_LINES); // 开始按线段方式提交顶点。
|
drawLine(p1, p2, 0.0f, 0.0f, 1.0f); // 绘制裁剪后的蓝色线段。
|
||||||
glColor3f(0.0f, 0.0f, 1.0f); // 设置绘制颜色为蓝色。
|
|
||||||
glVertex2f(x_0, y_0); // 提交裁剪后线段的起点。
|
|
||||||
glVertex2f(x_1, y_1); // 提交裁剪后线段的终点。
|
|
||||||
glEnd(); // 结束线段顶点提交。
|
|
||||||
} // 接受线段绘制结束。
|
} // 接受线段绘制结束。
|
||||||
}
|
}
|
||||||
// 显示回调函数
|
// 显示回调函数
|
||||||
void myDisplay() { // 定义窗口重绘时调用的显示函数。
|
void myDisplay() { // 定义窗口重绘时调用的显示函数。
|
||||||
glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区。
|
glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区。
|
||||||
// 空行:分隔清屏和裁剪窗口绘制。
|
|
||||||
// 1. 绘制裁剪窗口 (红色线框)。
|
|
||||||
glColor3f(1.0f, 0.0f, 0.0f); // 设置绘制颜色为红色。
|
|
||||||
glBegin(GL_LINE_LOOP); // 开始绘制闭合线框。
|
|
||||||
glVertex2f(rect.xmin, rect.ymin); // 提交裁剪窗口左下角顶点。
|
|
||||||
glVertex2f(rect.xmax, rect.ymin); // 提交裁剪窗口右下角顶点。
|
|
||||||
glVertex2f(rect.xmax, rect.ymax); // 提交裁剪窗口右上角顶点。
|
|
||||||
glVertex2f(rect.xmin, rect.ymax); // 提交裁剪窗口左上角顶点。
|
|
||||||
glEnd(); // 结束闭合线框顶点提交。
|
|
||||||
|
|
||||||
// 2. 绘制原始线段 (绿色)。
|
drawClipWindow(rect); // 绘制红色裁剪窗口。
|
||||||
int orig_x_0 = 50, orig_y_0 = 350; // 定义原始线段的第一个端点坐标。
|
drawLine(lineStart, lineEnd, 0.0f, 1.0f, 0.0f); // 绘制绿色原始线段。
|
||||||
int orig_x_1 = 550, orig_y_1 = 50; // 定义原始线段的第二个端点坐标。
|
|
||||||
|
|
||||||
glBegin(GL_LINES); // 开始按线段方式提交顶点。
|
// 执行裁剪并绘制结果 (蓝色)。
|
||||||
glColor3f(0.0f, 1.0f, 0.0f); // 设置绘制颜色为绿色。
|
|
||||||
glVertex2f(orig_x_0, orig_y_0); // 提交原始线段起点。
|
|
||||||
glVertex2f(orig_x_1, orig_y_1); // 提交原始线段终点。
|
|
||||||
glEnd(); // 结束原始线段顶点提交。
|
|
||||||
|
|
||||||
// 3. 执行裁剪并绘制结果 (蓝色)。
|
|
||||||
float cx_0 = orig_x_0, cy_0 = orig_y_0; // 将原始起点复制为浮点变量。
|
|
||||||
float cx_1 = orig_x_1, cy_1 = orig_y_1; // 将原始终点复制为浮点变量。
|
|
||||||
glLineWidth(3.0); // 设置线宽为 3 像素。
|
glLineWidth(3.0); // 设置线宽为 3 像素。
|
||||||
cohenSutherlandClip(cx_0, cy_0, cx_1, cy_1, rect); // 执行裁剪算法并绘制裁剪后的线段。
|
cohenSutherlandClip(lineStart, lineEnd, rect); // 执行裁剪算法并绘制裁剪后的线段。
|
||||||
glLineWidth(1.0); // 恢复线宽。
|
glLineWidth(1.0); // 恢复线宽。
|
||||||
|
|
||||||
glFlush(); // 强制执行所有尚未执行的 OpenGL 绘图命令。
|
glFlush(); // 强制执行所有尚未执行的 OpenGL 绘图命令。
|
||||||
@@ -122,10 +122,10 @@ void myDisplay() { // 定义窗口重绘时调用的显示函数。
|
|||||||
// 初始化设置
|
// 初始化设置
|
||||||
void Init() { // 定义初始化函数。
|
void Init() { // 定义初始化函数。
|
||||||
glShadeModel(GL_FLAT); // 设置平面着色模式。
|
glShadeModel(GL_FLAT); // 设置平面着色模式。
|
||||||
rect.xmin = 100; // 设置裁剪窗口左边界。
|
rect.xmin = 150; // 设置裁剪窗口左边界。
|
||||||
rect.xmax = 400; // 设置裁剪窗口右边界。
|
rect.xmax = 450; // 设置裁剪窗口右边界。
|
||||||
rect.ymin = 100; // 设置裁剪窗口下边界。
|
rect.ymin = 120; // 设置裁剪窗口下边界。
|
||||||
rect.ymax = 300; // 设置裁剪窗口上边界。
|
rect.ymax = 320; // 设置裁剪窗口上边界。
|
||||||
}
|
}
|
||||||
|
|
||||||
// 窗口大小调整
|
// 窗口大小调整
|
||||||
|
|||||||
Binary file not shown.
+82
-73
@@ -1,109 +1,118 @@
|
|||||||
#include <GL/glut.h> // 引入 GLUT/OpenGL 头文件,提供窗口和绘图函数。
|
#include <GL/glut.h> // 引入 GLUT 和 OpenGL 相关函数。
|
||||||
|
|
||||||
// 定义窗口宽度和高度。
|
const int WINDOW_WIDTH = 800; // 设置窗口宽度。
|
||||||
const int WIDTH = 800; // 定义窗口宽度为 800 像素。
|
const int WINDOW_HEIGHT = 600; // 设置窗口高度。
|
||||||
const int HEIGHT = 600; // 定义窗口高度为 600 像素。
|
const int CURVE_SEGMENTS = 10000; // 设置曲线分段数量,数量越大曲线越平滑。
|
||||||
|
|
||||||
struct Point { // 定义用于保存坐标点的结构体。
|
struct Vec2 { // 定义二维坐标点结构体。
|
||||||
double x; // 保存点的 x 坐标。
|
double x; // 保存点的 x 坐标。
|
||||||
double y; // 保存点的 y 坐标。
|
double y; // 保存点的 y 坐标。
|
||||||
}; // 结构体定义结束。
|
};
|
||||||
|
|
||||||
// 定义三次 Bezier 曲线的四个控制点。
|
Vec2 controlStart = { -300.0, -100.0 }; // Bezier 曲线的起点。
|
||||||
Point p0 = { -300.0, -100.0 }; // 定义第一个控制点。
|
Vec2 controlHandleA = { 0.0, 200.0 }; // 第一个控制点,用来影响曲线起始方向。
|
||||||
Point p1 = { 0.0, 200.0 }; // 定义第二个控制点。
|
Vec2 controlHandleB = { 200.0, 300.0 }; // 第二个控制点,用来影响曲线结束方向。
|
||||||
Point p2 = { 200.0, 300.0 }; // 定义第三个控制点。
|
Vec2 controlEnd = { 300.0, 100.0 }; // Bezier 曲线的终点。
|
||||||
Point p3 = { 300.0, 100.0 }; // 定义第四个控制点。
|
|
||||||
|
|
||||||
Point bezier(double t) { // 根据参数 t 计算三次 Bezier 曲线上的点。
|
Vec2 calculateBezierPoint(double t) { // 根据参数 t 计算三次 Bezier 曲线上的点。
|
||||||
double u = 1.0 - t; // 计算 1-t,便于代入 Bezier 曲线公式。
|
double inverseT = 1.0 - t; // 计算 1 - t,方便套用 Bezier 公式。
|
||||||
|
double startWeight = inverseT * inverseT * inverseT; // 起点对应的权重。
|
||||||
|
double handleAWeight = 3.0 * t * inverseT * inverseT; // 第一个控制点对应的权重。
|
||||||
|
double handleBWeight = 3.0 * t * t * inverseT; // 第二个控制点对应的权重。
|
||||||
|
double endWeight = t * t * t; // 终点对应的权重。
|
||||||
|
|
||||||
Point p; // 定义曲线上的当前点。
|
Vec2 curvePoint; // 保存当前计算出的曲线点。
|
||||||
p.x = u * u * u * p0.x + 3 * t * u * u * p1.x + 3 * t * t * u * p2.x + t * t * t * p3.x; // 根据三次 Bezier 公式计算 x 坐标。
|
curvePoint.x = startWeight * controlStart.x // 按权重累加起点的 x 坐标。
|
||||||
|
+ handleAWeight * controlHandleA.x // 按权重累加第一个控制点的 x 坐标。
|
||||||
|
+ handleBWeight * controlHandleB.x // 按权重累加第二个控制点的 x 坐标。
|
||||||
|
+ endWeight * controlEnd.x; // 按权重累加终点的 x 坐标。
|
||||||
|
curvePoint.y = startWeight * controlStart.y // 按权重累加起点的 y 坐标。
|
||||||
|
+ handleAWeight * controlHandleA.y // 按权重累加第一个控制点的 y 坐标。
|
||||||
|
+ handleBWeight * controlHandleB.y // 按权重累加第二个控制点的 y 坐标。
|
||||||
|
+ endWeight * controlEnd.y; // 按权重累加终点的 y 坐标。
|
||||||
|
|
||||||
p.y = u * u * u * p0.y + 3 * t * u * u * p1.y + 3 * t * t * u * p2.y + t * t * t * p3.y; // 根据三次 Bezier 公式计算 y 坐标。
|
return curvePoint; // 返回曲线上当前参数 t 对应的点。
|
||||||
|
|
||||||
return p; // 返回计算得到的曲线点。
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawAxis() { // 定义绘制坐标轴的函数,便于观察控制点和曲线位置。
|
void submitControlVertices() { // 将四个控制点提交给当前 OpenGL 绘制命令。
|
||||||
glColor3f(0.5f, 0.5f, 0.5f); // 设置绘制颜色为灰色。
|
glVertex2d(controlStart.x, controlStart.y); // 提交起点坐标。
|
||||||
glLineWidth(1.0f); // 设置线宽为 1 像素。
|
glVertex2d(controlHandleA.x, controlHandleA.y); // 提交第一个控制点坐标。
|
||||||
|
glVertex2d(controlHandleB.x, controlHandleB.y); // 提交第二个控制点坐标。
|
||||||
glBegin(GL_LINES); // 开始按线段方式提交顶点。
|
glVertex2d(controlEnd.x, controlEnd.y); // 提交终点坐标。
|
||||||
glVertex2d(-400.0, 0.0); // 提交 x 轴左端点。
|
|
||||||
glVertex2d( 400.0, 0.0); // 提交 x 轴右端点。
|
|
||||||
glVertex2d(0.0, -200.0); // 提交 y 轴下端点。
|
|
||||||
glVertex2d(0.0, 400.0); // 提交 y 轴上端点。
|
|
||||||
glEnd(); // 结束坐标轴顶点提交。
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawControlPolygon() { // 定义绘制控制多边形的函数。
|
void renderCoordinateAxes() { // 绘制坐标轴。
|
||||||
glColor3f(0.0f, 0.0f, 1.0f); // 设置绘制颜色为蓝色。
|
glColor3f(0.5f, 0.5f, 0.5f); // 设置坐标轴颜色为灰色。
|
||||||
glLineWidth(2.0f); // 设置线宽为 2 像素。
|
glLineWidth(1.0f); // 设置坐标轴线宽。
|
||||||
|
|
||||||
glBegin(GL_LINE_STRIP); // 开始按连续折线方式提交顶点。
|
glBegin(GL_LINES); // 开始绘制独立线段。
|
||||||
glVertex2d(p0.x, p0.y); // 提交第一个控制点。
|
glVertex2d(-400.0, 0.0); // x 轴左端点。
|
||||||
glVertex2d(p1.x, p1.y); // 提交第二个控制点。
|
glVertex2d(400.0, 0.0); // x 轴右端点。
|
||||||
glVertex2d(p2.x, p2.y); // 提交第三个控制点。
|
glVertex2d(0.0, -200.0); // y 轴下端点。
|
||||||
glVertex2d(p3.x, p3.y); // 提交第四个控制点。
|
glVertex2d(0.0, 400.0); // y 轴上端点。
|
||||||
glEnd(); // 结束控制多边形顶点提交。
|
glEnd(); // 结束坐标轴绘制。
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawBezierCurve() { // 定义绘制三次 Bezier 曲线的函数。
|
void renderControlPolygon() { // 绘制连接控制点的折线。
|
||||||
glColor3f(1.0f, 1.0f, 0.0f); // 设置绘制颜色为黄色。
|
glColor3f(0.0f, 0.0f, 1.0f); // 设置控制多边形颜色为蓝色。
|
||||||
glLineWidth(3.0f); // 设置线宽为 3 像素。
|
glLineWidth(2.0f); // 设置控制多边形线宽。
|
||||||
|
|
||||||
double dt = 1.0 / 10000.0; // 定义参数 t 每次增加的步长,步长越小曲线越平滑。
|
glBegin(GL_LINE_STRIP); // 开始绘制连续折线。
|
||||||
|
submitControlVertices(); // 按顺序提交四个控制点。
|
||||||
|
glEnd(); // 结束控制多边形绘制。
|
||||||
|
}
|
||||||
|
|
||||||
glBegin(GL_LINE_STRIP); // 开始按连续折线方式绘制曲线。
|
void renderBezierCurve() { // 绘制三次 Bezier 曲线。
|
||||||
for (double t = 0.0; t <= 1.0; t += dt) { // 从 0 到 1 逐步取点。
|
glColor3f(1.0f, 1.0f, 0.0f); // 设置曲线颜色为黄色。
|
||||||
Point p = bezier(t); // 计算当前参数对应的曲线点。
|
glLineWidth(3.0f); // 设置曲线线宽。
|
||||||
glVertex2d(p.x, p.y); // 提交当前曲线点。
|
|
||||||
|
double step = 1.0 / CURVE_SEGMENTS; // 计算每次增加的 t 步长。
|
||||||
|
|
||||||
|
glBegin(GL_LINE_STRIP); // 开始用连续折线近似绘制曲线。
|
||||||
|
for (double t = 0.0; t <= 1.0; t += step) { // 从 t=0 到 t=1 依次取点。
|
||||||
|
Vec2 curvePoint = calculateBezierPoint(t); // 计算当前 t 对应的曲线点。
|
||||||
|
glVertex2d(curvePoint.x, curvePoint.y); // 提交当前曲线点坐标。
|
||||||
}
|
}
|
||||||
glEnd(); // 结束曲线顶点提交。
|
glEnd(); // 结束曲线绘制。
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawControlPoints() { // 定义绘制控制点的函数。
|
void renderControlPoints() { // 绘制四个控制点。
|
||||||
glColor3f(1.0f, 0.0f, 0.0f); // 设置绘制颜色为红色。
|
glColor3f(1.0f, 0.0f, 0.0f); // 设置控制点颜色为红色。
|
||||||
glPointSize(8.0f); // 设置控制点大小为 8 像素。
|
glPointSize(8.0f); // 设置控制点大小。
|
||||||
|
|
||||||
glBegin(GL_POINTS); // 开始按点方式提交顶点。
|
glBegin(GL_POINTS); // 开始绘制点。
|
||||||
glVertex2d(p0.x, p0.y); // 提交第一个控制点。
|
submitControlVertices(); // 提交四个控制点的位置。
|
||||||
glVertex2d(p1.x, p1.y); // 提交第二个控制点。
|
glEnd(); // 结束控制点绘制。
|
||||||
glVertex2d(p2.x, p2.y); // 提交第三个控制点。
|
|
||||||
glVertex2d(p3.x, p3.y); // 提交第四个控制点。
|
|
||||||
glEnd(); // 结束控制点顶点提交。
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void myDisplay() { // 定义窗口重绘时调用的显示函数。
|
void displayScene() { // GLUT 显示回调函数,负责绘制整个画面。
|
||||||
glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区。
|
glClear(GL_COLOR_BUFFER_BIT); // 清空颜色缓冲区,准备重新绘制。
|
||||||
|
|
||||||
drawAxis(); // 绘制坐标轴。
|
renderCoordinateAxes(); // 绘制坐标轴。
|
||||||
drawControlPolygon(); // 绘制控制多边形。
|
renderControlPolygon(); // 绘制控制多边形。
|
||||||
drawBezierCurve(); // 绘制三次 Bezier 曲线。
|
renderBezierCurve(); // 绘制 Bezier 曲线。
|
||||||
drawControlPoints(); // 绘制控制点。
|
renderControlPoints(); // 绘制控制点。
|
||||||
|
|
||||||
glFlush(); // 强制执行所有尚未执行的 OpenGL 绘图命令。
|
glFlush(); // 强制执行前面的 OpenGL 绘图命令。
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init() { // 定义初始化函数。
|
void initializeOpenGL() { // 初始化 OpenGL 绘图环境。
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 设置背景颜色为黑色。
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 设置背景颜色为黑色。
|
||||||
glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式。
|
glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式。
|
||||||
glLoadIdentity(); // 将当前投影矩阵重置为单位矩阵。
|
glLoadIdentity(); // 重置当前投影矩阵。
|
||||||
gluOrtho2D(-400.0, 400.0, -200.0, 400.0); // 设置二维正交投影范围。
|
gluOrtho2D(-400.0, 400.0, -200.0, 400.0); // 设置二维正交投影范围。
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) { // 程序入口函数,接收命令行参数。
|
int main(int argc, char** argv) { // 程序入口函数。
|
||||||
glutInit(&argc, argv); // 初始化 GLUT。
|
glutInit(&argc, argv); // 初始化 GLUT。
|
||||||
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 设置显示模式为 RGB 颜色和单缓冲。
|
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 使用单缓冲和 RGB 颜色模式。
|
||||||
glutInitWindowSize(WIDTH, HEIGHT); // 设置窗口大小为 WIDTH x HEIGHT。
|
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); // 设置窗口大小。
|
||||||
glutInitWindowPosition(100, 100); // 设置窗口初始显示位置。
|
glutInitWindowPosition(100, 100); // 设置窗口初始位置。
|
||||||
glutCreateWindow("实验4_03毕爽爽 三次Bezier曲线"); // 创建窗口并设置标题。
|
glutCreateWindow("实验4_01毕爽爽三次 Bezier 曲线"); // 创建窗口并设置标题。
|
||||||
|
|
||||||
Init(); // 调用初始化函数。
|
initializeOpenGL(); // 初始化 OpenGL 参数。
|
||||||
glutDisplayFunc(myDisplay); // 注册显示回调函数。
|
glutDisplayFunc(displayScene); // 注册显示回调函数。
|
||||||
|
glutMainLoop(); // 进入 GLUT 主事件循环。
|
||||||
|
|
||||||
glutMainLoop(); // 进入 GLUT 事件处理主循环。
|
return 0; // 程序正常结束。
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user