This commit is contained in:
2026-05-12 22:07:06 +08:00
Unverified
parent e75eed82b1
commit 99abeb27da
5 changed files with 141 additions and 132 deletions
+56 -56
View File
@@ -1,5 +1,4 @@
#include <GL/glut.h> // 引入 OpenGL 头文件,提供窗口和绘图函数。
#include <iostream> // 引入输入输出流库,便于需要时输出调试信息。
#include <GL/glut.h> // 引入 OpenGL 头文件,提供窗口和绘图函数。
// 定义区域编码
#define INSIDE 0 // 0000,表示点在裁剪窗口内部。
@@ -12,21 +11,44 @@ struct ClipWindow { // 定义用于保存裁剪窗口边界的结构体。
float xmin, xmax, ymin, ymax; // 保存裁剪窗口的左、右、下、上边界。
}; // 结构体定义结束。
ClipWindow rect; // 定义全局裁剪窗口对象
int x_0, y_0, x_1, y_1; // 定义线段端点坐标变量
struct Point { // 定义二维点结构体
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; // 初始认为点在窗口内部。
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 标记。
if (p.x < rect.xmin) code |= LEFT; // 如果点在左边界外,则添加 LEFT 标记。
else if (p.x > rect.xmax) code |= RIGHT; // 如果点在右边界外,则添加 RIGHT 标记。
if (p.y < rect.ymin) code |= BOTTOM; // 如果点在下边界外,则添加 BOTTOM 标记。
else if (p.y > rect.ymax) code |= TOP; // 如果点在上边界外,则添加 TOP 标记。
return code; // 返回最终区域编码。
}
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); // 计算第二个端点的区域编码
void drawLine(Point p1, Point p2, float r, float g, float b) { // 按指定颜色绘制一条线段
glColor3f(r, g, b); // 设置线段颜色
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。
while (true) { // 不断处理线段,直到确定接受或舍弃。
@@ -42,7 +64,7 @@ void cohenSutherlandClip(float& x_0, float& y_0, float& x_1, float& y_1, ClipWin
// 3. 线段部分在窗口内,需要求交点。
else { // 线段部分可见,需要把窗口外端点裁到边界上。
int code_out; // 保存当前选中的窗口外端点区域编码。
float x, y; // 保存线段与裁剪边界的交点坐标。
Point crossPoint; // 保存线段与裁剪边界的交点坐标。
// 选择窗口外的一个端点。
if (code1 != 0) // 如果第一个端点在窗口外。
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; // 选择第二个端点作为待裁剪端点。
// 计算交点。
if (code_out & TOP) { // 如果端点在上边界外,则与上边界求交。
x = x_0 + (x_1 - x_0) * (rect.ymax - y_0) / (y_1 - y_0); // 根据直线参数方程计算交点 x 坐标。
y = rect.ymax; // 交点 y 坐标等于上边界。
crossPoint.x = p1.x + (p2.x - p1.x) * (rect.ymax - p1.y) / (p2.y - p1.y); // 根据直线参数方程计算交点 x 坐标。
crossPoint.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 坐标等于下边界。
crossPoint.x = p1.x + (p2.x - p1.x) * (rect.ymin - p1.y) / (p2.y - p1.y); // 根据直线参数方程计算交点 x 坐标。
crossPoint.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 坐标等于右边界。
crossPoint.y = p1.y + (p2.y - p1.y) * (rect.xmax - p1.x) / (p2.x - p1.x); // 根据直线参数方程计算交点 y 坐标。
crossPoint.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 坐标等于左边界。
crossPoint.y = p1.y + (p2.y - p1.y) * (rect.xmin - p1.x) / (p2.x - p1.x); // 根据直线参数方程计算交点 y 坐标。
crossPoint.x = rect.xmin; // 交点 x 坐标等于左边界。
} // 左边界求交结束。
// 用交点替换原来的外部端点。
if (code_out == code1) { // 如果被裁剪的是第一个端点。
x_0 = x; y_0 = y; // 用交点更新第一个端点坐标。
code1 = computeCode(x_0, y_0, rect); // 重新计算第一个端点的区域编码。
p1 = crossPoint; // 用交点更新第一个端点坐标。
code1 = computeCode(p1, rect); // 重新计算第一个端点的区域编码。
} // 第一个端点更新结束。
else { // 否则被裁剪的是第二个端点。
x_1 = x; y_1 = y; // 用交点更新第二个端点坐标。
code2 = computeCode(x_1, y_1, rect); // 重新计算第二个端点的区域编码。
p2 = crossPoint; // 用交点更新第二个端点坐标。
code2 = computeCode(p2, rect); // 重新计算第二个端点的区域编码。
}
}
}
// 如果接受,则绘制裁剪后的线段(蓝色)。
if (accept) { // 如果线段最终被接受。
glBegin(GL_LINES); // 开始按线段方式提交顶点
glColor3f(0.0f, 0.0f, 1.0f); // 设置绘制颜色为蓝色。
glVertex2f(x_0, y_0); // 提交裁剪后线段的起点。
glVertex2f(x_1, y_1); // 提交裁剪后线段的终点。
glEnd(); // 结束线段顶点提交。
drawLine(p1, p2, 0.0f, 0.0f, 1.0f); // 绘制裁剪后的蓝色线段
} // 接受线段绘制结束。
}
// 显示回调函数
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; // 定义原始线段的第二个端点坐标。
drawClipWindow(rect); // 绘制红色裁剪窗口
drawLine(lineStart, lineEnd, 0.0f, 1.0f, 0.0f); // 绘制绿色原始线段
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 像素。
cohenSutherlandClip(cx_0, cy_0, cx_1, cy_1, rect); // 执行裁剪算法并绘制裁剪后的线段。
cohenSutherlandClip(lineStart, lineEnd, rect); // 执行裁剪算法并绘制裁剪后的线段。
glLineWidth(1.0); // 恢复线宽。
glFlush(); // 强制执行所有尚未执行的 OpenGL 绘图命令。
@@ -122,10 +122,10 @@ void myDisplay() { // 定义窗口重绘时调用的显示函数。
// 初始化设置
void Init() { // 定义初始化函数。
glShadeModel(GL_FLAT); // 设置平面着色模式。
rect.xmin = 100; // 设置裁剪窗口左边界。
rect.xmax = 400; // 设置裁剪窗口右边界。
rect.ymin = 100; // 设置裁剪窗口下边界。
rect.ymax = 300; // 设置裁剪窗口上边界。
rect.xmin = 150; // 设置裁剪窗口左边界。
rect.xmax = 450; // 设置裁剪窗口右边界。
rect.ymin = 120; // 设置裁剪窗口下边界。
rect.ymax = 320; // 设置裁剪窗口上边界。
}
// 窗口大小调整
BIN
View File
Binary file not shown.