diff --git a/lab1/1.cpp b/lab1/1.cpp index f37eb87..2d72ae8 100644 --- a/lab1/1.cpp +++ b/lab1/1.cpp @@ -1,54 +1,52 @@ -#include -using namespace std; +#include // 引入 GLUT/OpenGL 头文件,提供窗口和绘图函数。 +using namespace std; // 使用标准命名空间,方便后续直接使用标准库名称。 -// 回调函数 -void myDisplay() +// 回调函数:GLUT 在需要重绘窗口时会调用它。 +void myDisplay() // 定义绘制窗口内容的函数。 { - // 清除缓冲区 - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - // 正交模式 - glMatrixMode(GL_PROJECTION); - gluOrtho2D(0.0, 500.0, 0.0, 500.0); - glColor4f(0.0, 1.0, 0.0, 0.0); - glRectf(50.0, 50.0, 400.0, 400.0); + // 清除缓冲区前先设置清屏颜色。 + glClearColor(0.0, 0.0, 0.0, 0.0); // 设置背景清除颜色为黑色。 + glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区,刷新画布背景。 + // 设置二维正交投影模式。 + glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式。 + gluOrtho2D(0.0, 500.0, 0.0, 500.0); // 设置二维坐标范围为 x:[0,500], y:[0,500]。 + glColor4f(0.0, 1.0, 0.0, 0.0); // 设置当前绘图颜色为绿色。 + glRectf(50.0, 50.0, 400.0, 400.0); // 绘制一个左下角为(50,50)、右上角为(400,400)的矩形。 - // 划线 - glColor3f(1.0, 1.0, 0.0); - glBegin(GL_LINES); - glVertex2f(50.0, 50.0); - glVertex2f(400.0, 400.0); - glVertex2f(400.0, 50.0); - glVertex2f(50.0, 400.0); - glEnd(); + // 绘制线段。 + glColor3f(1.0, 1.0, 0.0); // 设置当前绘图颜色为黄色。 + glBegin(GL_LINES); // 开始按线段方式提交顶点。 + glVertex2f(50.0, 50.0); // 指定第一条线段的起点。 + glVertex2f(400.0, 400.0); // 指定第一条线段的终点。 + glVertex2f(400.0, 50.0); // 指定第二条线段的起点。 + glVertex2f(50.0, 400.0); // 指定第二条线段的终点。 + glEnd(); // 结束线段顶点提交。 - // 画点 - glColor3f(1.0, 0.0, 0.0); - glPointSize(20.0); - glBegin(GL_POINTS); - glVertex2f(15.0, 15.0); - glEnd(); + // 绘制点。 + glColor3f(1.0, 0.0, 0.0); // 设置当前绘图颜色为红色。 + glPointSize(20.0); // 设置点的显示大小为 20 像素。 + glBegin(GL_POINTS); // 开始按点方式提交顶点。 + glVertex2f(15.0, 15.0); // 在坐标(15,15)处绘制一个点。 + glEnd(); // 结束点顶点提交。 - // 画三角形 - glBegin(GL_TRIANGLES); - glColor3f(0.0, 0.0, 1.0); - glVertex2i(200, 300); - glVertex2i(100, 100); - glVertex2i(300, 100); - glEnd(); + // 绘制三角形。 + glBegin(GL_TRIANGLES); // 开始按三角形方式提交顶点。 + glColor3f(0.0, 0.0, 1.0); // 设置当前绘图颜色为蓝色。 + glVertex2i(200, 300); // 指定三角形第一个顶点。 + glVertex2i(100, 100); // 指定三角形第二个顶点。 + glVertex2i(300, 100); // 指定三角形第三个顶点。 + glEnd(); // 结束三角形顶点提交。 - - glFlush(); - -} + glFlush(); // 强制执行所有尚未执行的 OpenGL 绘图命令。 +} int main(int argc, char* argv[]) { - glutInit(&argc, argv); - glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); - glutInitWindowPosition(100, 100); - glutInitWindowSize(500, 500); - glutCreateWindow("The First OpenGL Program"); - glutDisplayFunc(&myDisplay); - glutMainLoop(); - return 0; + glutInit(&argc, argv); // 初始化 GLUT 库。 + glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); // 设置显示模式为 RGB 颜色和单缓冲。 + glutInitWindowPosition(100, 100); // 设置窗口左上角初始位置。 + glutInitWindowSize(500, 500); // 设置窗口初始大小为 500x500。 + glutCreateWindow("实验1_03毕爽爽的第一个OpenGL程序"); // 创建标题为指定字符串的窗口。 + glutDisplayFunc(&myDisplay); // 注册显示回调函数。 + glutMainLoop(); // 进入 GLUT 事件循环。 + return 0; } \ No newline at end of file diff --git a/lab1/1.exe b/lab1/1.exe index b90f12a..8c8de09 100644 Binary files a/lab1/1.exe and b/lab1/1.exe differ diff --git a/lab1/2.cpp b/lab1/2.cpp index 997f822..2531d4b 100644 --- a/lab1/2.cpp +++ b/lab1/2.cpp @@ -1,80 +1,80 @@ -#include -#include -#include +#include // 引入数学函数库,用于 abs 和 round 等函数。 +#include // 引入输入输出流库,用于打印坐标。 +#include // 引入 GLUT/OpenGL 头文件,提供窗口和绘图函数。 -// ڿȺ͸߶ -const int WIDTH = 640; -const int HEIGHT = 480; +// 窗口宽度和高度。 +const int WIDTH = 640; // 定义窗口宽度为 640 像素。 +const int HEIGHT = 480; // 定义窗口高度为 480 像素。 -void drawDDALine(int x1, int y1, int x2, int y2) { - float x = x1; - float y = y1; +void drawDDALine(int x1, int y1, int x2, int y2) { // 定义 DDA 直线绘制函数,参数为线段两个端点。 + float x = x1; // 用浮点变量保存当前点的 x 坐标。 + float y = y1; // 用浮点变量保存当前点的 y 坐标。 - // ֵ - int dx = x2 - x1; - int dy = y2 - y1; + // 计算差值。 + int dx = x2 - x1; // 计算终点与起点的 x 方向差值。 + int dy = y2 - y1; // 计算终点与起点的 y 方向差值。 - // ȷȡ dx dy оֵϴǸ - int steps = std::abs(dx) > std::abs(dy) ? std::abs(dx) : std::abs(dy); //Ԫʽ + // 确定步数,取 dx 和 dy 中绝对值较大的那个。 + int steps = std::abs(dx) > std::abs(dy) ? std::abs(dx) : std::abs(dy); // 三元表达式用于选择较大的绝对差值作为步数。 - // ÿһ - float xIncrement = (float)dx / steps; - float yIncrement = (float)dy / steps; + // 计算每一步的增量。 + float xIncrement = (float)dx / steps; // 计算每一步 x 坐标增加的值。 + float yIncrement = (float)dy / steps; // 计算每一步 y 坐标增加的值。 - // ʼƵ - glBegin(GL_POINTS); - glVertex2i((int)round(x), (int)round(y)); // + // 开始绘制点。 + glBegin(GL_POINTS); // 开始按点方式提交顶点。 + glVertex2i((int)round(x), (int)round(y)); // 绘制起点,并将浮点坐标四舍五入为整数坐标。 - for (int k = 0; k < steps; k++) { - x += xIncrement; - y += yIncrement; - // ȡתΪ - std::cout << (int)round(x) << ", " << (int)round(y)<<"\n"; - glVertex2i((int)round(x), (int)round(y)); - } - glEnd(); + for (int k = 0; k < steps; k++) { // 循环 steps 次,逐步生成直线上的像素点。 + x += xIncrement; // 更新当前点的 x 坐标。 + y += yIncrement; // 更新当前点的 y 坐标。 + // 将浮点坐标四舍五入取整转换为整数像素坐标。 + std::cout << (int)round(x) << ", " << (int)round(y)<<"\n"; // 在控制台输出当前绘制点的整数坐标。 + glVertex2i((int)round(x), (int)round(y)); // 将当前点作为 OpenGL 点顶点提交。 + } + glEnd(); // 结束点顶点提交。 } -// ʾص -void display() { - drawDDALine(0, 0, 50, 20); - glFlush(); -} +// 显示回调函数。 +void display() { // 定义窗口重绘时调用的显示函数。 + drawDDALine(0, 0, 50, 20); // 调用 DDA 算法绘制从(0,0)到(50,20)的直线。 + glFlush(); // 强制执行所有尚未执行的 OpenGL 绘图命令。 +} -// ʼ OpenGL +// 初始化 OpenGL 设置。 void init() { - // ñɫΪɫ - glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + // 设置背景颜色为白色。 + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // 设置清屏颜色为白色且完全不透明。 +// 空行:分隔背景设置和投影设置。 + // 设置投影矩阵为 2D 正交投影。 + glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式。 + glLoadIdentity(); // 将当前投影矩阵重置为单位矩阵。 + // 定义可视区域,左下角(0,0),右上角(WIDTH, HEIGHT)。 + gluOrtho2D(0.0, WIDTH, 0.0, HEIGHT); // 设置二维正交投影坐标范围。 +} - // ͶӰΪ 2D ͶӰ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - // ½(0,0)Ͻ(WIDTH, HEIGHT) - gluOrtho2D(0.0, WIDTH, 0.0, HEIGHT); -} +int main(int argc, char** argv) { // 程序入口函数,接收命令行参数。 + // 初始化 GLUT。 + glutInit(&argc, argv); // 初始化 GLUT 库。 -int main(int argc, char** argv) { - // ʼ GLUT - glutInit(&argc, argv); + // 设置显示模式:单缓冲、RGB 颜色模式。 + glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 设置单缓冲和 RGB 颜色模式。 - // ʾģʽ塢RGB ɫģʽ - glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); + // 设置窗口大小和位置。 + glutInitWindowSize(WIDTH, HEIGHT); // 设置窗口大小为 WIDTH x HEIGHT。 + glutInitWindowPosition(100, 100); // 设置窗口初始显示位置。 - // ôڴСλ - glutInitWindowSize(WIDTH, HEIGHT); - glutInitWindowPosition(100, 100); + // 创建窗口。 + glutCreateWindow("DDA算法"); // 创建标题为“DDA算法”的窗口。 - // - glutCreateWindow("DDA㷨"); + // 注册回调函数。 + glutDisplayFunc(display); // 注册显示回调函数。 - // עص - glutDisplayFunc(display); + // 初始化设置。 + init(); // 执行 OpenGL 初始化设置。 - // ʼ - init(); + // 进入主循环。 + glutMainLoop(); // 进入 GLUT 事件循环,等待并处理窗口事件。 - // ѭ - glutMainLoop(); - - return 0; -} \ No newline at end of file + return 0; +} \ No newline at end of file diff --git a/lab1/3.cpp b/lab1/3.cpp index f5cd8ba..3603564 100644 --- a/lab1/3.cpp +++ b/lab1/3.cpp @@ -1,86 +1,78 @@ -#include // 引入 GLUT 库,用于创建窗口和处理事件 -#include +#include // 引入 GLUT/OpenGL 头文件,用于创建窗口和绘图。 +#include // 引入输入输出流库,用于在控制台输出点坐标。 +#include // 引入通用工具库,用于 abs 函数。 -using namespace std; +const int WIDTH = 640; // 定义窗口宽度。 +const int HEIGHT = 480; // 定义窗口高度。 -// 辅助函数:根据八分对称性,绘制8个对称点 -void plotCirclePoints(int xc, int yc, int x, int y) { - glBegin(GL_POINTS); - // 第1象限 - glVertex2i(xc + x, yc + y); - glVertex2i(xc + y, yc + x); - // 第2象限 - glVertex2i(xc - y, yc + x); - glVertex2i(xc - x, yc + y); - // 第3象限 - glVertex2i(xc - x, yc - y); - glVertex2i(xc - y, yc - x); - // 第4象限 - glVertex2i(xc + y, yc - x); - glVertex2i(xc + x, yc - y); - glEnd(); -} +void drawPoint(int x, int y) { // 定义绘制单个像素点的辅助函数。 + glVertex2i(x, y); // 向 OpenGL 提交一个二维整数坐标点。 + std::cout << x << ", " << y << std::endl; // 在控制台输出当前点坐标。 +} // 绘制点函数结束。 -// 中点画圆算法主函数 -// 参数: (xc, yc) 为圆心坐标, r 为半径 -void midpointCircle(int xc, int yc, int r) { - int x = 0; - int y = r; - // 初始决策参数 d = 3 - 2r - int d = 3 - 2 * r; +void drawMidpointLine(int x1, int y1, int x2, int y2) { // 定义中点画线算法函数。 + int dx = std::abs(x2 - x1); // 计算 x 方向距离的绝对值。 + int dy = std::abs(y2 - y1); // 计算 y 方向距离的绝对值。 + int sx = (x1 < x2) ? 1 : -1; // 判断 x 坐标每次应该增加还是减少。 + int sy = (y1 < y2) ? 1 : -1; // 判断 y 坐标每次应该增加还是减少。 + int x = x1; // 初始化当前点的 x 坐标。 + int y = y1; // 初始化当前点的 y 坐标。 - // 绘制初始点 - plotCirclePoints(xc, yc, x, y); + glBegin(GL_POINTS); // 开始按点方式绘制直线。 + drawPoint(x, y); // 绘制起点。 - // 循环计算并绘制第一个八分之一圆弧,直到 x <= y - while (x <= y) { - x++; - if (d < 0) { - // 中点在圆内,选择正右方的点 (x+1, y) - d = d + 4 * x + 6; - } else { - // 中点在圆外或圆上,选择右下方的点 (x+1, y-1) - d = d + 4 * (x - y) + 10; - y--; - } - std::cout<< xc + x << ", " << yc + y << std::endl; - // 绘制由当前(x, y)决定的8个对称点 - plotCirclePoints(xc, yc, x, y); - } - glFlush(); // 强制执行所有OpenGL命令 -} + if (dx >= dy) { // 当直线斜率绝对值小于等于 1 时,以 x 为主方向递增。 + int d = 2 * dy - dx; // 初始化中点判别式。 + while (x != x2) { // 当 x 坐标尚未到达终点时继续循环。 + x += sx; // 沿 x 主方向前进一步。 + if (d > 0) { // 如果中点位置对应需要选择斜向像素。 + y += sy; // y 方向也前进一步。 + d += 2 * (dy - dx); // 更新选择斜向像素后的判别式。 + } else { // 如果中点位置对应选择水平方向像素。 + d += 2 * dy; // 更新选择水平像素后的判别式。 + } // 判别式判断结束。 + drawPoint(x, y); // 绘制当前计算出的像素点。 + } // x 主方向循环结束。 + } else { // 当直线斜率绝对值大于 1 时,以 y 为主方向递增。 + int d = 2 * dx - dy; // 初始化中点判别式。 + while (y != y2) { // 当 y 坐标尚未到达终点时继续循环。 + y += sy; // 沿 y 主方向前进一步。 + if (d > 0) { // 如果中点位置对应需要选择斜向像素。 + x += sx; // x 方向也前进一步。 + d += 2 * (dx - dy); // 更新选择斜向像素后的判别式。 + } else { // 如果中点位置对应选择竖直方向像素。 + d += 2 * dx; // 更新选择竖直像素后的判别式。 + } // 判别式判断结束。 + drawPoint(x, y); // 绘制当前计算出的像素点。 + } // y 主方向循环结束。 + } // 斜率情况判断结束。 -// --- OpenGL 设置与回调函数 --- + glEnd(); // 结束点绘制。 +} // 中点画线算法函数结束。 -// 显示回调函数 -void display() { - glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区 +void display() { // 定义显示回调函数。 + glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区。 + glColor3f(1.0f, 0.0f, 0.0f); // 设置绘图颜色为红色。 + glPointSize(3.0f); // 设置点的大小。 + drawMidpointLine(50, 50, 500, 300); // 调用中点画线算法绘制一条直线。 + glFlush(); // 强制执行所有 OpenGL 绘图命令。 +} // 显示函数结束。 - glColor3f(1.0, 0.0, 0.0); // 设置绘制颜色为红色 - glPointSize(2.0f); // 设置点的大小 +void init() { // 定义 OpenGL 初始化函数。 + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // 设置背景颜色为白色。 + glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式。 + glLoadIdentity(); // 将当前投影矩阵重置为单位矩阵。 + gluOrtho2D(0.0, WIDTH, 0.0, HEIGHT); // 设置二维正交投影范围。 +} // 初始化函数结束。 - // 调用中点画圆算法 - midpointCircle(50, 50, 30); -} - -// 初始化函数 -void init() { - glClearColor(0.0, 0.0, 0.0, 1.0); // 设置背景颜色为黑色 - glMatrixMode(GL_PROJECTION); // 设置投影矩阵 - gluOrtho2D(0.0, 500.0, 0.0, 500.0); // 定义二维正交投影,窗口坐标范围 (0,0) 到 (500,500) -} - -// --- 主函数 --- -int main(int argc, char** argv) { - glutInit(&argc, argv); // 初始化 GLUT - glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 使用单缓冲和RGB颜色模型 - glutInitWindowSize(500, 500); // 设置窗口大小 - glutInitWindowPosition(100, 100); // 设置窗口位置 - glutCreateWindow("Midpoint Circle Algorithm"); // 创建窗口并设置标题 - - init(); // 调用初始化函数 - glutDisplayFunc(display); // 注册显示回调函数 - glutMainLoop(); // 进入 GLUT 事件处理主循环 - - return 0; -} \ No newline at end of file +int main(int argc, char** argv) { // 程序入口函数。 + glutInit(&argc, argv); // 初始化 GLUT。 + glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 设置显示模式为单缓冲和 RGB。 + glutInitWindowSize(WIDTH, HEIGHT); // 设置窗口大小。 + glutInitWindowPosition(100, 100); // 设置窗口初始位置。 + glutCreateWindow("中点画线算法"); // 创建窗口并设置标题。 + init(); // 调用初始化函数。 + glutDisplayFunc(display); // 注册显示回调函数。 + glutMainLoop(); // 进入 GLUT 事件循环。 + return 0; // 程序正常结束。 +} // 主函数结束。 \ No newline at end of file diff --git a/lab1/3.exe b/lab1/3.exe index 31505c0..4bae78b 100644 Binary files a/lab1/3.exe and b/lab1/3.exe differ diff --git a/lab1/4.cpp b/lab1/4.cpp new file mode 100644 index 0000000..bb9aefe --- /dev/null +++ b/lab1/4.cpp @@ -0,0 +1,67 @@ +#include // 引入 GLUT/OpenGL 头文件,用于创建窗口和绘图。 +#include // 引入输入输出流库,用于在控制台输出点坐标。 +#include // 引入通用工具库,用于 abs 函数。 + +const int WIDTH = 640; // 定义窗口宽度。 +const int HEIGHT = 480; // 定义窗口高度。 + +void drawPoint(int x, int y) { // 定义绘制单个像素点的辅助函数。 + glVertex2i(x, y); // 向 OpenGL 提交一个二维整数坐标点。 + std::cout << x << ", " << y << std::endl; // 在控制台输出当前点坐标。 +} // 绘制点函数结束。 + +void drawBresenhamLine(int x1, int y1, int x2, int y2) { // 定义 Bresenham 直线算法函数。 + int dx = std::abs(x2 - x1); // 计算 x 方向距离的绝对值。 + int dy = std::abs(y2 - y1); // 计算 y 方向距离的绝对值。 + int sx = (x1 < x2) ? 1 : -1; // 判断 x 坐标每一步应该增加还是减少。 + int sy = (y1 < y2) ? 1 : -1; // 判断 y 坐标每一步应该增加还是减少。 + int err = dx - dy; // 初始化误差项。 + int x = x1; // 初始化当前点的 x 坐标。 + int y = y1; // 初始化当前点的 y 坐标。 + + glBegin(GL_POINTS); // 开始按点方式绘制直线。 + while (true) { // 不断生成直线上的像素点,直到到达终点。 + drawPoint(x, y); // 绘制当前点。 + if (x == x2 && y == y2) { // 判断当前点是否已经到达终点。 + break; // 到达终点后结束循环。 + } // 终点判断结束。 + + int e2 = 2 * err; // 将误差项扩大 2 倍,便于和 dx、dy 比较。 + if (e2 > -dy) { // 如果误差允许在 x 方向前进一步。 + err -= dy; // 更新 x 方向移动后的误差项。 + x += sx; // x 坐标向终点方向移动一步。 + } // x 方向判断结束。 + if (e2 < dx) { // 如果误差允许在 y 方向前进一步。 + err += dx; // 更新 y 方向移动后的误差项。 + y += sy; // y 坐标向终点方向移动一步。 + } // y 方向判断结束。 + } // 像素点生成循环结束。 + glEnd(); // 结束点绘制。 +} // Bresenham 直线算法函数结束。 + +void display() { // 定义显示回调函数。 + glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区。 + glColor3f(0.0f, 0.0f, 1.0f); // 设置绘图颜色为蓝色。 + glPointSize(3.0f); // 设置点的大小。 + drawBresenhamLine(50, 50, 500, 300); // 调用 Bresenham 算法绘制一条直线。 + glFlush(); // 强制执行所有 OpenGL 绘图命令。 +} // 显示函数结束。 + +void init() { // 定义 OpenGL 初始化函数。 + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // 设置背景颜色为白色。 + glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式。 + glLoadIdentity(); // 将当前投影矩阵重置为单位矩阵。 + gluOrtho2D(0.0, WIDTH, 0.0, HEIGHT); // 设置二维正交投影范围。 +} // 初始化函数结束。 + +int main(int argc, char** argv) { // 程序入口函数。 + glutInit(&argc, argv); // 初始化 GLUT。 + glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 设置显示模式为单缓冲和 RGB。 + glutInitWindowSize(WIDTH, HEIGHT); // 设置窗口大小。 + glutInitWindowPosition(100, 100); // 设置窗口初始位置。 + glutCreateWindow("Bresenham"); // 创建窗口并设置标题。 + init(); // 调用初始化函数。 + glutDisplayFunc(display); // 注册显示回调函数。 + glutMainLoop(); // 进入 GLUT 事件循环。 + return 0; // 程序正常结束。 +} // 主函数结束。 \ No newline at end of file diff --git a/lab1/4.exe b/lab1/4.exe new file mode 100644 index 0000000..62f813e Binary files /dev/null and b/lab1/4.exe differ diff --git a/lab1/5.cpp b/lab1/5.cpp new file mode 100644 index 0000000..b9a9c99 --- /dev/null +++ b/lab1/5.cpp @@ -0,0 +1,84 @@ +#include // 引入 GLUT/OpenGL 头文件,提供窗口和绘图函数。 +#include // 引入输入输出流库,用于输出圆上点坐标。 + +using namespace std; // 使用标准命名空间,方便直接使用标准库名称。 + +// 辅助函数:根据圆的八分对称性绘制 8 个对称点。 +void plotCirclePoints(int xc, int yc, int x, int y) { // 定义绘制圆对称点的函数。 + glBegin(GL_POINTS); // 开始按点方式提交顶点。 + // 第一象限相关对称点。 + glVertex2i(xc + x, yc + y); // 绘制相对圆心偏移为(+x,+y)的点。 + glVertex2i(xc + y, yc + x); // 绘制相对圆心偏移为(+y,+x)的点。 + // 第二象限相关对称点。 + glVertex2i(xc - y, yc + x); // 绘制相对圆心偏移为(-y,+x)的点。 + glVertex2i(xc - x, yc + y); // 绘制相对圆心偏移为(-x,+y)的点。 + // 第三象限相关对称点。 + glVertex2i(xc - x, yc - y); // 绘制相对圆心偏移为(-x,-y)的点。 + glVertex2i(xc - y, yc - x); // 绘制相对圆心偏移为(-y,-x)的点。 + // 第四象限相关对称点。 + glVertex2i(xc + y, yc - x); // 绘制相对圆心偏移为(+y,-x)的点。 + glVertex2i(xc + x, yc - y); // 绘制相对圆心偏移为(+x,-y)的点。 + glEnd(); // 结束点顶点提交。 +} // 对称点绘制函数结束。 + +// 中点画圆算法主函数。 +// 参数:(xc, yc) 为圆心坐标,r 为半径。 +void midpointCircle(int xc, int yc, int r) { // 定义中点画圆算法函数。 + int x = 0; // 初始化当前点的 x 坐标为 0。 + int y = r; // 初始化当前点的 y 坐标为半径。 + // 初始决策参数 d = 3 - 2r。 + int d = 3 - 2 * r; // 根据中点画圆算法计算初始判别式。 + + // 绘制初始点。 + plotCirclePoints(xc, yc, x, y); // 利用八分对称绘制初始的 8 个点。 + + // 循环计算并绘制第一个八分之一圆弧,直到 x <= y 不再成立。 + while (x <= y) { // 当 x 未超过 y 时继续生成圆弧点。 + x++; // x 坐标向右移动一步。 + if (d < 0) { // 判断中点在圆内时的情况。 + // 中点在圆内,选择正右方的点 (x+1, y)。 + d = d + 4 * x + 6; // 按中点画圆递推公式更新判别式。 + } else { // 处理中点在圆外或圆上的情况。 + // 中点在圆外或圆上,选择右下方的点 (x+1, y-1)。 + d = d + 4 * (x - y) + 10; // 按右下方向选择时的递推公式更新判别式。 + y--; // y 坐标向下移动一步。 + } + std::cout<< xc + x << ", " << yc + y << std::endl; // 输出当前计算得到的圆弧点坐标。 + // 绘制由当前 (x, y) 决定的 8 个对称点。 + plotCirclePoints(xc, yc, x, y); // 利用八分对称绘制当前点对应的所有对称点。 + } + glFlush(); // 强制执行所有尚未执行的 OpenGL 绘图命令。 +} + +// 显示回调函数。 +void display() { // 定义窗口重绘时调用的显示函数。 + glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区。 + + glColor3f(1.0, 0.0, 0.0); // 设置绘制颜色为红色。 + glPointSize(2.0f); // 设置绘制点的大小。 + + // 调用中点画圆算法。 + midpointCircle(0, 0, 30); // 以(0,0)为圆心、30为半径绘制圆。 +} + +// 初始化函数。 +void init() { // 定义 OpenGL 初始化函数。 + glClearColor(0.0, 0.0, 0.0, 1.0); // 设置背景颜色为黑色。 + glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式。 + gluOrtho2D(-250.0, 250.0, -250.0, 250.0); // 定义二维正交投影坐标范围为(-250,-250)到(250,250)。 +} // 初始化函数结束。 + + +int main(int argc, char** argv) { // 程序入口函数,接收命令行参数。 + glutInit(&argc, argv); // 初始化 GLUT。 + glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 使用单缓冲和 RGB 颜色模式。 + glutInitWindowSize(500, 500); // 设置窗口大小为 500x500。 + glutInitWindowPosition(100, 100); // 设置窗口初始位置。 + glutCreateWindow("中点画圆算法"); // 创建窗口并设置标题。 + + init(); // 调用初始化函数。 + glutDisplayFunc(display); // 注册显示回调函数。 + glutMainLoop(); // 进入 GLUT 事件处理主循环。 + + return 0; +} diff --git a/lab1/5.exe b/lab1/5.exe new file mode 100644 index 0000000..eaedec9 Binary files /dev/null and b/lab1/5.exe differ diff --git a/lab2/lab2.cpp b/lab2/lab2.cpp index aa48fd0..e186017 100644 --- a/lab2/lab2.cpp +++ b/lab2/lab2.cpp @@ -1,175 +1,175 @@ -#include -#include - -// --- --- -#define INSIDE 0 // 0000 -#define LEFT 1 // 0001 -#define RIGHT 2 // 0010 -#define BOTTOM 4 // 0100 -#define TOP 8 // 1000 - -// --- üڽṹ --- -struct ClipWindow { - float xmin, xmax, ymin, ymax; -}; - -// --- ȫֱ --- -ClipWindow rect; -int x_0, y_0, x_1, y_1; // ߶ζ˵ - -/** - * (x, y) - */ -int computeCode(float x, float y, ClipWindow rect) { - int code = INSIDE; - if (x < rect.xmin) code |= LEFT; - else if (x > rect.xmax) code |= RIGHT; - if (y < rect.ymin) code |= BOTTOM; - else if (y > rect.ymax) code |= TOP; - return code; -} - -/** - * Cohen-Sutherland 㷨 - * ע⣺ﴫãֱ޸ֵԵõüĽ - */ -void cohenSutherlandClip(float& x_0, float& y_0, float& x_1, float& y_1, ClipWindow rect) { - int code1 = computeCode(x_0, y_0, rect); - int code2 = computeCode(x_1, y_1, rect); - bool accept = false; - - while (true) { - // ˵㶼ڴ (0000 | 0000 == 0) - if (!(code1 | code2)) { - accept = true; - break; - } - // ˵㶼ڴڵͬһⲿ (綼ߣ0001 & 0001 != 0) λ - else if (code1 & code2) { - break; // ֱ - } - // 3. ߶βڴڣҪ󽻵 - else { - int code_out; - float x, y; - - // ѡ񴰿һ˵ - if (code1 != 0) - code_out = code1; - else - code_out = code2; - - // 㽻 - if (code_out & TOP) { - x = x_0 + (x_1 - x_0) * (rect.ymax - y_0) / (y_1 - y_0); - y = rect.ymax; - } - else if (code_out & BOTTOM) { - x = x_0 + (x_1 - x_0) * (rect.ymin - y_0) / (y_1 - y_0); - y = rect.ymin; - } - else if (code_out & RIGHT) { - y = y_0 + (y_1 - y_0) * (rect.xmax - x_0) / (x_1 - x_0); - x = rect.xmax; - } - else if (code_out & LEFT) { - y = y_0 + (y_1 - y_0) * (rect.xmin - x_0) / (x_1 - x_0); - x = rect.xmin; - } - - // ý滻ԭⲿ˵ - if (code_out == code1) { - x_0 = x; y_0 = y; - code1 = computeCode(x_0, y_0, rect); - } - else { - x_1 = x; y_1 = y; - code2 = computeCode(x_1, y_1, rect); - } - } - } - - // ܣƲü߶Σɫ - if (accept) { - glBegin(GL_LINES); - glColor3f(0.0f, 0.0f, 1.0f); // ɫ - glVertex2f(x_0, y_0); - glVertex2f(x_1, y_1); - glEnd(); - } -} - -// --- ʾص --- -void myDisplay() { - 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. ԭʼ߶ (ɫ) - // ע⣺ΪʾЧڵòüǰȱԭʼ꣬ - // ֱóʼֵơʹóʼֵơ - int orig_x_0 = 50, orig_y_0 = 350; - 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 룬Ϊ㷨ڲ޸ - 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); - cohenSutherlandClip(cx_0, cy_0, cx_1, cy_1, rect); - glLineWidth(1.0); // ָ߿ - - glFlush(); -} - -// --- ʼ --- -void Init() { - glShadeModel(GL_FLAT); - - rect.xmin = 100; - rect.xmax = 400; - rect.ymin = 100; - rect.ymax = 300; -} - -// --- ڴС --- -void myReshape(int w, int h) { - glViewport(0, 0, (GLsizei)w, (GLsizei)h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - // öάͶӰΧֵӦ - gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h); - glMatrixMode(GL_MODELVIEW); -} - -// --- --- -int main(int argc, char* argv[]) { - glutInit(&argc, argv); - glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); - glutInitWindowPosition(100, 100); - glutInitWindowSize(600, 400); - glutCreateWindow("ʵ2_03ˬˬ Cohen-Sutherland 㷨"); - - Init(); - - glutDisplayFunc(myDisplay); - glutReshapeFunc(myReshape); - - glutMainLoop(); - return 0; -} \ No newline at end of file +#include // 引入 GLUT/OpenGL 头文件,提供窗口和绘图函数。 +#include // 引入输入输出流库,便于需要时输出调试信息。 +// 空行:分隔头文件和区域编码定义。 +// --- 定义区域编码 --- +#define INSIDE 0 // 0000,表示点在裁剪窗口内部。 +#define LEFT 1 // 0001,表示点在裁剪窗口左侧。 +#define RIGHT 2 // 0010,表示点在裁剪窗口右侧。 +#define BOTTOM 4 // 0100,表示点在裁剪窗口下方。 +#define TOP 8 // 1000,表示点在裁剪窗口上方。 +// 空行:分隔宏定义和结构体定义。 +// --- 定义裁剪窗口结构 --- +struct ClipWindow { // 定义用于保存裁剪窗口边界的结构体。 + float xmin, xmax, ymin, ymax; // 保存裁剪窗口的左、右、下、上边界。 +}; // 结构体定义结束。 +// 空行:分隔结构体和全局变量。 +// --- 全局变量设置 --- +ClipWindow rect; // 定义全局裁剪窗口对象。 +int x_0, y_0, x_1, y_1; // 定义线段端点坐标变量。 +// 空行:分隔全局变量和函数说明。 +/** // 文档注释开始。 + * 计算点 (x, y) 的区域编码 // 说明 computeCode 函数的作用。 + */ // 文档注释结束。 +int computeCode(float x, float y, ClipWindow rect) { // 根据点坐标和裁剪窗口计算区域编码。 + int code = INSIDE; // 初始认为点在窗口内部。 + if (x < rect.xmin) code |= LEFT; // 如果点在左边界外,则添加 LEFT 标记。 + else if (x > rect.xmax) code |= RIGHT; // 如果点在右边界外,则添加 RIGHT 标记。 + if (y < rect.ymin) code |= BOTTOM; // 如果点在下边界外,则添加 BOTTOM 标记。 + else if (y > rect.ymax) code |= TOP; // 如果点在上边界外,则添加 TOP 标记。 + return code; // 返回最终区域编码。 +} // 区域编码函数结束。 +// 空行:分隔区域编码函数和裁剪函数说明。 +/** // 文档注释开始。 + * Cohen-Sutherland 算法核心 // 说明该函数执行 Cohen-Sutherland 线段裁剪。 + * 注意:这里传入坐标的引用,直接修改坐标值以得到裁剪后的结果 // 说明引用参数会被函数内部更新。 + */ // 文档注释结束。 +void cohenSutherlandClip(float& x_0, float& y_0, float& x_1, float& y_1, ClipWindow rect) { // 定义 Cohen-Sutherland 线段裁剪函数。 + int code1 = computeCode(x_0, y_0, rect); // 计算第一个端点的区域编码。 + int code2 = computeCode(x_1, y_1, rect); // 计算第二个端点的区域编码。 + bool accept = false; // 定义是否接受裁剪结果的标志,初始为 false。 +// 空行:分隔初始化和裁剪循环。 + while (true) { // 不断处理线段,直到确定接受或舍弃。 + // 如果两端点都在窗口内 (0000 | 0000 == 0)。 + if (!(code1 | code2)) { // 两个区域编码按位或为 0,说明整条线段在窗口内。 + accept = true; // 标记线段可以被接受。 + break; // 退出裁剪循环。 + } // 完全可见判断结束。 + // 如果两端点都在窗口的同一侧外部 (例如都在左边:0001 & 0001 != 0) 按位与运算。 + else if (code1 & code2) { // 两个区域编码按位与不为 0,说明线段完全在同一外侧。 + break; // 直接舍弃该线段并退出循环。 + } // 完全不可见判断结束。 + // 3. 线段部分在窗口内,需要求交点。 + else { // 线段部分可见,需要把窗口外端点裁到边界上。 + int code_out; // 保存当前选中的窗口外端点区域编码。 + float x, y; // 保存线段与裁剪边界的交点坐标。 +// 空行:分隔局部变量和外部端点选择。 + // 选择窗口外的一个端点。 + if (code1 != 0) // 如果第一个端点在窗口外。 + code_out = code1; // 选择第一个端点作为待裁剪端点。 + else // 否则说明第二个端点在窗口外。 + code_out = code2; // 选择第二个端点作为待裁剪端点。 +// 空行:分隔外部端点选择和交点计算。 + // 计算交点。 + if (code_out & TOP) { // 如果端点在上边界外,则与上边界求交。 + x = x_0 + (x_1 - x_0) * (rect.ymax - y_0) / (y_1 - y_0); // 根据直线参数方程计算交点 x 坐标。 + y = rect.ymax; // 交点 y 坐标等于上边界。 + } // 上边界求交结束。 + else if (code_out & BOTTOM) { // 如果端点在下边界外,则与下边界求交。 + x = x_0 + (x_1 - x_0) * (rect.ymin - y_0) / (y_1 - y_0); // 根据直线参数方程计算交点 x 坐标。 + y = rect.ymin; // 交点 y 坐标等于下边界。 + } // 下边界求交结束。 + else if (code_out & RIGHT) { // 如果端点在右边界外,则与右边界求交。 + y = y_0 + (y_1 - y_0) * (rect.xmax - x_0) / (x_1 - x_0); // 根据直线参数方程计算交点 y 坐标。 + x = rect.xmax; // 交点 x 坐标等于右边界。 + } // 右边界求交结束。 + else if (code_out & LEFT) { // 如果端点在左边界外,则与左边界求交。 + y = y_0 + (y_1 - y_0) * (rect.xmin - x_0) / (x_1 - x_0); // 根据直线参数方程计算交点 y 坐标。 + x = rect.xmin; // 交点 x 坐标等于左边界。 + } // 左边界求交结束。 +// 空行:分隔交点计算和端点替换。 + // 用交点替换原来的外部端点。 + if (code_out == code1) { // 如果被裁剪的是第一个端点。 + x_0 = x; y_0 = y; // 用交点更新第一个端点坐标。 + code1 = computeCode(x_0, y_0, rect); // 重新计算第一个端点的区域编码。 + } // 第一个端点更新结束。 + else { // 否则被裁剪的是第二个端点。 + x_1 = x; y_1 = y; // 用交点更新第二个端点坐标。 + code2 = computeCode(x_1, y_1, rect); // 重新计算第二个端点的区域编码。 + } // 第二个端点更新结束。 + } // 部分可见处理结束。 + } // 裁剪循环结束。 +// 空行:分隔裁剪循环和结果绘制。 + // 如果接受,则绘制裁剪后的线段(蓝色)。 + if (accept) { // 如果线段最终被接受。 + glBegin(GL_LINES); // 开始按线段方式提交顶点。 + glColor3f(0.0f, 0.0f, 1.0f); // 设置绘制颜色为蓝色。 + glVertex2f(x_0, y_0); // 提交裁剪后线段的起点。 + glVertex2f(x_1, y_1); // 提交裁剪后线段的终点。 + glEnd(); // 结束线段顶点提交。 + } // 接受线段绘制结束。 +} // Cohen-Sutherland 裁剪函数结束。 +// 空行:分隔裁剪函数和显示回调函数。 +// --- 显示回调函数 --- +void myDisplay() { // 定义窗口重绘时调用的显示函数。 + 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. 绘制原始线段 (绿色)。 + // 注意:为了演示效果,我们在调用裁剪函数前,先保存原始坐标, + // 或者在这里直接用初始值绘制。这里我们使用初始值绘制。 + int orig_x_0 = 50, orig_y_0 = 350; // 定义原始线段的第一个端点坐标。 + 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 变量传入,因为算法内部会修改它们。 + 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 像素。 + cohenSutherlandClip(cx_0, cy_0, cx_1, cy_1, rect); // 执行裁剪算法并绘制裁剪后的线段。 + glLineWidth(1.0); // 恢复线宽。 +// 空行:分隔裁剪结果绘制和刷新。 + glFlush(); // 强制执行所有尚未执行的 OpenGL 绘图命令。 +} // 显示回调函数结束。 +// 空行:分隔显示回调函数和初始化函数。 +// --- 初始化设置 --- +void Init() { // 定义初始化函数。 + glShadeModel(GL_FLAT); // 设置平面着色模式。 +// 空行:分隔 OpenGL 状态和裁剪窗口边界。 + rect.xmin = 100; // 设置裁剪窗口左边界。 + rect.xmax = 400; // 设置裁剪窗口右边界。 + rect.ymin = 100; // 设置裁剪窗口下边界。 + rect.ymax = 300; // 设置裁剪窗口上边界。 +} // 初始化函数结束。 +// 空行:分隔初始化函数和窗口调整函数。 +// --- 窗口大小调整 --- +void myReshape(int w, int h) { // 定义窗口尺寸变化时的回调函数。 + glViewport(0, 0, (GLsizei)w, (GLsizei)h); // 设置视口覆盖整个窗口。 + glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式。 + glLoadIdentity(); // 将当前投影矩阵重置为单位矩阵。 + // 设置二维投影范围,与坐标数值对应。 + gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h); // 根据窗口宽高设置二维正交投影范围。 + glMatrixMode(GL_MODELVIEW); // 切换回模型视图矩阵模式。 +} // 窗口大小调整回调函数结束。 +// 空行:分隔窗口调整函数和主函数。 +// --- 主函数 --- +int main(int argc, char* argv[]) { // 程序入口函数,接收命令行参数。 + glutInit(&argc, argv); // 初始化 GLUT。 + glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); // 设置显示模式为 RGB 颜色和单缓冲。 + glutInitWindowPosition(100, 100); // 设置窗口初始位置。 + glutInitWindowSize(600, 400); // 设置窗口初始大小为 600x400。 + glutCreateWindow("实验2_03毕爽爽 Cohen-Sutherland 算法"); // 创建窗口并设置标题。 +// 空行:分隔窗口创建和初始化。 + Init(); // 调用初始化函数,设置裁剪窗口。 +// 空行:分隔初始化和回调注册。 + glutDisplayFunc(myDisplay); // 注册显示回调函数。 + glutReshapeFunc(myReshape); // 注册窗口大小变化回调函数。 +// 空行:分隔回调注册和主循环。 + glutMainLoop(); // 进入 GLUT 事件处理主循环。 + return 0; // 正常结束程序。 +} // 主函数结束。