一、目的

1. 了解直线裁剪的基本原理和常用方法。
2. 掌握中点分割直线段裁剪算法的基本原理和步骤。
3. 使用C++、OpenGL编程实现如下内容:输入直线段的起始点和终止点坐标位置、用四边形模拟显示器的边界,利用中点分割直线段裁剪算法计算直线在模拟显示器内部的裁剪结果。

二、实验设备

编程语言:C++、OpenGL
实验环境:已安装相关编程环境的计算机1台。

三、算法原理

中点分割直线段裁剪算法对Cohen-Sutherland直线裁剪算法的第3种情况做了改进,原理是简单地把起点为P0,终点为P1的直线段等分为两段直线P0P和PP1(P为直线段中点),对每一段直线重复“简取”和“简弃”的处理,对于不能处理的直线段再继续等分下去线,直至每一段直线完全能够被“简取”或“简弃”,也就是说直至每段直线完全位于窗口之内或完全位于窗口之外,就完成了直线段的裁剪工作。
算法步骤
(1)以P1出发,检测点P2是否在窗口内,若是,即是所求点;若不转(2)
(2)检测点P1P2是否在同一外侧,若是,则不在窗口内;返回;不转(3)
(3)求出该直线段的中点P3。检测P3与P1P2的关系:
若中点P3在窗口内,用P3代替P1;重复步骤(3);
若中点P3不在窗口内,判断P3与P2的关系,
若P3、P2在同侧外面,则用P3代替P2,即丢掉P2P3段;
若不在同侧外面,则用P3代替P1,重复步骤(3)。直到满足误差条件,则该中点就是该线段落距离P1最远的可见点。
(4)重复步骤(2)-(3),求出另一个端点P2的最远可见点坐标。

四、算法实现及结果分析

#include <GL/glut.h>
#include <cstdio>
#include<iostream>
using namespace std;
#define LEFT 1//左边界
#define RIGHT 2//右边界
#define BOTTOM 4//下边界
#define TOP 8//上边界/*int x1 = 150, y1 = 50, x2 = 50, y2 = 250, XL = 100, XR = 300, YB = 100, YT = 200;  //(x1,y1)、(x2,y2)为直线段的端点,XL为左边界,XR为右边界,YB为下边界,YT为上边界
int x1_init = 150, y1_init = 50, x2_init = 50, y2_init = 250;  //将直线段端点备份,以便画出裁剪前的直线段*/
double a1, b1, a2, b2, A1, B1, A2, B2, XL = 100, XR = 300, YB = 100, YT = 200;
double x1_init, y1_init, x2_init, y2_init;int encode(double x, double y)//按位或操作找到该点的空间区域
{int c = 0;if (x < XL) c |= LEFT;if (x > XR) c |= RIGHT;if (y < YB) c |= BOTTOM;if (y > YT) c |= TOP;return c;
}int border(double mx,double my) {int c = 0;if (abs(mx - XL) < 1) {c |= LEFT;}if (abs(mx - XR) < 1) {c |= RIGHT;}if (abs(my - YB) < 1) {c |= BOTTOM;}if (abs(my - YT) < 1) {c |= TOP;}return c;
}
bool pm(double mx, double my) {if (abs(mx - XL) < 1 || abs(mx - XR) < 1 || abs(my - YB) < 1 || abs(my - YT) < 1) {return false;}else {return true;}
}
bool Mid_LineClip1() {double mx1, my1;int code1, code2, code;A2 = a2, B2 = b2;//确保(a2,b2)不被更改code1 = encode(a1, b1);//得到该点的空间区域code2 = encode(A2, B2);mx1 = (a1 + A2) / 2;my1 = (b1 + B2) / 2;code = encode(mx1, my1);if (code1 == 0){A1 = a1, B1 = b1;return true;}else if((code1&code2)!=0){//在窗口外同一侧A1 = a1, B1 = b1;return false;}else if ((code1 & border(mx1, my1)) != 0) {//中点在边界上,若靠近点1一侧不在经过窗口a1 = mx1;b1 = my1;}else{do{mx1 = (a1 + A2) / 2;my1 = (b1 + B2) / 2;code1 = encode(a1, b1);//得到该点的空间区域code2 = encode(A2, B2);code = encode(mx1, my1);if (code == 0) {//中点在窗口内就更新点2(备份)的位置A2 = mx1;B2 = my1;code2 = encode(A2, B2);}else {if ((code & code1) != 0) {//中点在窗口外和点1同一侧就更新点1的位置a1 = mx1;b1 = my1;code1 = encode(a1, b1);}else {//中点在窗口外和点2在同一侧就更新点2的位置A2 = mx1;B2 = my1;code2 = encode(A2, B2);}}} while (pm(a1, b1));}/*if (abs(a1 - XL) < 5) {//调整误差a1 = XL;}else if(abs(a1-XR)<5){a1 = XR;}if (abs(b1 - YB) < 5) {b1 = YB;}else if(abs(b1 - YT) < 5){b1 = YT;}*/A1 = a1, B1 = b1;//保留更新的点1//cout << "a1 " << a1 << "b1 " << b1 << endl;//cout << "A2 " << A2 << "B2 " << B2 << endl;return true;
}bool Mid_LineClip2() {double mx2, my2;int code1, code2, code;code1 = encode(A1, B1);//得到该点的空间区域code2 = encode(a2, b2);mx2 = (A1 + a2) / 2;my2 = (B1 + b2) / 2;code = encode(mx2, my2);if (code2 == 0) {return true;}else if ((code2 & border(mx2, my2)) != 0) {//中点在边界上,若靠近点2一侧不在经过窗口a2 = mx2;b2 = my2;}else {do {mx2 = (A1 + a2) / 2;my2 = (B1 + b2) / 2;code1 = encode(A1, B1);//得到该点的空间区域code2 = encode(a2, b2);code = encode(mx2, my2);if (code == 0) {//中点在窗口内就更新点1的位置A1 = mx2;B1 = my2;code1 = encode(A1, B1);}else {//中点在窗口外和点2同一侧就更新点2的位置a2 = mx2;b2 = my2;code2 = encode(a2, b2);}} while (pm(a2, b2));}/*if (abs(a2 - XL) < 5) {//调整误差a2 = XL;}else if (abs(a2 - XR) < 5) {a2 = XR;}if (abs(b1 - YB) < 5) {b2 = YB;}else if (abs(a2 - XR) < 5) {b2 = YT;}*///cout << "A1 " << A1 << "B1 " << B1 << endl;//cout << "a2 " << a2 << "b2 " << b2 << endl;return true;
}void init()  //初始化函数
{glClearColor(0.0, 0.0, 0.0, 0.0);  //设置背景颜色glMatrixMode(GL_PROJECTION);       // 设置投影参数gluOrtho2D(0.0, 600.0, 0.0, 400.0); // 设置场景的大小//CS_LineClip();  //执行一次裁剪算法Mid_LineClip1();Mid_LineClip2();
}void mydisplay()  //显示函数
{//绘制方形边界glClear(GL_COLOR_BUFFER_BIT);glColor3f(1.0, 0.0, 0.0);glPointSize(2);glBegin(GL_LINE_LOOP);glVertex2i(XL, YT);glVertex2i(XL, YB);glVertex2i(XR, YB);glVertex2i(XR, YT);glEnd();glFlush();//绘制未裁剪前的线段glBegin(GL_LINES);glVertex2i(x1_init, y1_init);glVertex2i(x2_init, y2_init);glEnd();glFlush();//绘制裁剪后的线段glColor3f(1.0, 1.0, 0.0);glBegin(GL_LINES);glVertex2i(a1, b1);glVertex2i(a2, b2);glEnd();glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("Cohen-Sutherland裁剪算法");/*printf("请输入直线端点");scanf_s("%d%d%d%d", &a1, &b1, &a2, &b2);*/cout<<"请输入直线端点"<<endl;cin >> a1 >> b1 >> a2 >> b2;x1_init = a1, y1_init = b1, x2_init = a2, y2_init = b2;init();glutDisplayFunc(&mydisplay);glutMainLoop();return 0;
}

在本次实验中,我第一个遇到的问题就是变量 y1 和 C++ 标准库中的y1()函数冲突。我们可以通过改变量名或者使用c语言的标准去写,最终解决了问题。第二个遇到的问题是精度的问题,如果我们用int去对中点与边界的距离是否小于像素点时,误差会比较大。我们可以通过double去细化精度,或者通过判断该点与边界的位置关系将其位移到边界上,这样就提高了画线的精度。第三个遇到的问题就是情况分类,初次完成的代码只能成功画出某些满足条件的直线,但是当遇到直线中点位于边界的情况,就会产生错误。所以,我添加了一个border()函数用于判断靠近哪个边界。到目前为止,参与测试的直线都能够成功画出。

实验二 实现中点分割直线段裁剪算法相关推荐

  1. Liang-Barsky直线段裁剪算法-C++实现(计算机图形学作业)

    #include<graphics.h>//梁式直线裁剪算法的程序,由于该方法用编程实现非常简单,在介绍时稍微简略一些 void Liang_Barsky(const int& x ...

  2. 计算机图形学:Cohen-Sutherland直线段剪裁算法及梁友栋-Barsky裁剪算法(算法原理及代码实现)

    一.算法实现原理 Cohen-Sutherland直线段剪裁算法: 算法原理: (1)判断线段两端是否都落在窗口内,如果是,则线段完全可见,否则进行下一步 (2)判断线段两端是否都落在窗口外,如果是, ...

  3. 计算机图形学直线裁剪原理,计算机图形学-3.2用Liang-Barsky算法实现直线段裁剪...

    计算机图形学-3.2用Liang-Barsky算法实现直线段裁剪 计算机图形学-3.2用Liang-Barsky算法实现直线段裁剪 (1)算法设计原理 依次处理(p1,q1)(p2,q2)(p3,q3 ...

  4. 直线段检测算法(LSD:a Line Segment Detector)

    直线段检测算法(LSD:a Line Segment Detector) 1 简介 LSD是一种线段检测算法,该方法能在较短的时间内获得较高精度的直线段检测结果. LSD直线检测算法首先计算图像中所有 ...

  5. 【转】 LSD(Line Segment Detector) 直线段检测算法学习~

    论文回顾之一 一种新的直线段检测算法---LSD:a Line Segment Detector 原文地址:http://blog.csdn.net/polly_yang/article/detail ...

  6. 直线段检测算法---LSD

    直线段检测算法---LSD:a Line Segment Detector LSD的核心是像素合并于误差控制.利用合并像素来检测直线段并不是什么新鲜的方法,但是合并像素的方法通常运算量较大.LSD号称 ...

  7. 天津理工大学《操作系统》实验二,存储器的分配与回收算法实现,代码详解,保姆式注释讲解

    天津理工大学<操作系统>实验二,存储器的分配与回收算法实现,代码详解,保姆式注释讲解 实验内容 1. 本实验是模拟操作系统的主存分配,运用可变分区的存储管理算法设计主存分配和回收程序,并不 ...

  8. Python实现的直线段生成算法和圆弧生成算法

    资源下载地址:https://download.csdn.net/download/sheziqiong/86768948 资源下载地址:https://download.csdn.net/downl ...

  9. 算法实验二 【踩气球】(回溯算法)

    算法实验二 [踩气球](回溯算法) 1142.踩气球 时限:1000ms 内存限制:10000K 总时限:3000ms 描述 六一儿童节,小朋友们做踩气球游戏,气球的编号是1-100,两位小朋友各踩了 ...

最新文章

  1. Linux中listen()系统调用的backlog参数分析
  2. Eclipse Maven 编译错误 Dynamic Web Module 3.0 requires Java 1.6 or newer 解决方案
  3. 给你30秒的时间,你会用Excel制作出一个抽奖功能吗?
  4. C语言数组的一些运算*a,a+1,a+1,a+0
  5. Python机器学习及分析工具:Scipy篇
  6. 如何设计一门语言(十二)——设计可扩展的类型
  7. 对一次短路故障的分析与总结
  8. paraView做动画(终极教程)
  9. UVA 1599 Ideal Path
  10. matlab for 循环中怎么做到只取其中一个数_公益心 码客行(8)—— 循环语句
  11. TVS管选型详细流程
  12. PacketTracer简单使用】
  13. python怎么把二维数组转化一维数组,python 二维数组转一维数组
  14. 克莱姆森大学计算机排名,2020年克莱姆森大学排名TFE Times美国最佳计算机科学硕士专业排名第102...
  15. 用word字体转换来代替手写作业--最详细
  16. 二维表 转一维表 mysql_Excel二维表转换成一维表(2种方法)
  17. C++进阶_Effective_C++第三版(六) 继承与面向对象设计 Inheritance and Object-Oriented Design
  18. SQL--乱七八糟问题
  19. 蔬菜清洗污水处理(蔬菜冲洗循环用水污水处理)
  20. 苹果mac休眠快捷键_哪里不会点哪里苹果电脑应用手册

热门文章

  1. 【网络】什么是HTTPS证书?
  2. PNG字幕文件自动生成工具
  3. peewee mysql_Peewee、MySQL和INSERT忽略
  4. MOBA类和“吃鸡”游戏为什么对网络延迟要求高?
  5. Linux 内核配置项详解 myimx6
  6. AMR NB格式解析
  7. 如何查看自己的淘宝号使用多久了,淘龄怎么查?
  8. cie1931 python绘制_在cie1931颜色空间python 2.7中绘制色域
  9. 可以发送图片文件的php聊天室,基于 Swoole 开发实时在线聊天室(十四):发送图片消息...
  10. 怎么在html的表格中加筛选,excel中表头合并单元格的筛选