机械版CG 实验4 裁剪

1.实验目的:

了解二维图形裁剪的原理(点的裁剪、直线的裁剪、多边形的裁剪),利用VC+OpenGL实现直线的裁剪算法。

2.实验内容:

(1) 理解直线裁剪的原理(Cohen-Surtherland算法)

(2) 利用VC+OpenGL实现直线的编码裁剪算法,在屏幕上用一个封闭矩形裁剪任意一条直线。

(3) 调试、编译、修改程序。

3.实验原理:

编码裁剪算法的主要思想是:对于每条线段,分为三种情况处理。(1)若线段完全在窗口之内,则显示该线段,称为“取”;(2)若线段明显在窗口之外,则丢弃该线段,称为“弃”;(3)若线段既不满足“取”的条件,也不满足“舍”的条件,则把线段分割为两段。其中一段完全在窗口之外,可弃之;对另一段则重复上述处理。

算法中,为了快速判断一条直线段与矩形窗口的位置关系,采用了如图所示的空间划分和编码方案。延长窗口的四条边界,把未经裁剪的图形区域分为九个区,每个区有一个四位二进制的编码,从左到右各位依次表示上、下、右、左。例如,区号0101,左起第二位1表示该区在窗口的下方;右起第一位的1表示该区在窗口的左方。整个区号表示该区在窗口的左下方。

裁剪一条线段时,先求出两端点所在的区号code1和code2,若code1 = 0且code2 = 0,则说明线段的两个端点均在窗口内,那么整条线段必在窗口内,应取之;若code1和code2经按位与运算的结果不为0,则说明两个端点同在窗口的上方、下方、左方或右方。这种情况下,对线段的处理是弃之。如果上述两种条件都不成立,则按第三种情况处理。求出线段与窗口某边的交点,在交点处把线段一分为二,其中必有一段完全在窗口外,可弃之,对另一段则重复上述处理。

4.实验代码:

#include <GL/glut.h>

#include <stdio.h>

#define LEFT_EDGE   1 //代表0001

#define RIGHT_EDGE 2         //代表0010

#define BOTTOM_EDGE 4       //代表0100

#define TOP_EDGE    8         //代表1000

bool bInput, accept, bDraw;

struct Rectangle

{

         float xmin,xmax,ymin,ymax;

};

Rectangle rect;

struct Point {    int x, y;};

Point pt[2];

void LineGL(Point pt0, Point pt1)

{

         glBegin (GL_LINES);

         glColor3f (1.0f, 0.0f, 0.0f);   glVertex2f (pt0.x,pt0.y);

         glColor3f (0.0f, 1.0f, 0.0f);   glVertex2f (pt1.x,pt1.y); 

         glEnd ();

}

void PointGL(Point pt)

{

         glPointSize(2);

         glBegin (GL_POINTS);

         glColor3f (1.0f, 0.0f, 0.0f);   glVertex2f (pt.x,pt.y);

         glEnd ();

}

int CompCode(Point pt,Rectangle rect)

{

         int code=0x00;

         if(pt.y<rect.ymin)

                   code=code|BOTTOM_EDGE;

         if(pt.y>rect.ymax)

                   code=code|TOP_EDGE;

         if(pt.x>rect.xmax)

                   code=code|RIGHT_EDGE;

         if(pt.x<rect.xmin)

                   code=code|LEFT_EDGE;

         return code;

}

void cohensutherlandlineclip(Rectangle rect, Point &pt0, Point &pt1)

{

         int &x0 = pt0.x;

         int &y0 = pt0.y;

         int &x1 = pt1.x;

         int &y1 = pt1.y;

         bool done = false;

         float x,y;

         int code0,code1, codeout;

         code0 = CompCode(pt0,rect);

         code1 = CompCode(pt1,rect);

         do{

                   if(!(code0 | code1))

                   {

                            accept=true;

                            done=true;

                   }

                   else if(code0 & code1)

                   {

                            done = true;

                   }

                   else

                   {  

                            if(code0!=0)

                                     codeout = code0;

                            else

                                     codeout = code1;

                            if(codeout&LEFT_EDGE){

                                     y=y0+(y1-y0)*(rect.xmin-x0)/(x1-x0);

                                     x=(float)rect.xmin;

                            }

                            else if(codeout&RIGHT_EDGE){

                                     y=y0+(y1-y0)*(rect.xmax-x0)/(x1-x0);

                                     x=(float)rect.xmax;

                            }

                            else if(codeout&BOTTOM_EDGE){

                                     x=x0+(x1-x0)*(rect.ymin-y0)/(y1-y0);

                                     y=(float)rect.ymin;

                            }

                            else if(codeout&TOP_EDGE){

                                     x=x0+(x1-x0)*(rect.ymax-y0)/(y1-y0);

                                     y=(float)rect.ymax;

                            }

                            if(codeout == code0)

                            {

                                     x0=x;y0=y;

                                     code0 = CompCode(pt0,rect);

                            }

                            else

                            {

                                     x1=x;y1=y;

                                     code1 = CompCode(pt1,rect);

                            }

                   }

         }while(!done);

}

void myDisplay()

{

         glClear(GL_COLOR_BUFFER_BIT);

         glColor3f (1.0f, 0.0f, 0.0f);

         glRectf(rect.xmin,rect.ymin,rect.xmax,rect.ymax);

         if(accept)         

         {

                   if(bDraw)

                   {

                            LineGL(pt[0],pt[1]);

                   }

                  else

                            PointGL(pt[0]);

         }

         glFlush();

}

void Init()

{

         glClearColor(0.0, 0.0, 0.0, 0.0);

         glShadeModel(GL_FLAT);

         rect.xmin=100;

         rect.xmax=300;

         rect.ymin=100;

         rect.ymax=300;

         accept = true;

         bInput = false;

         printf("Press Left Mouse Button to Draw two Point to create a line!"nPress key 'c' to Clip!"n");

}

void Reshape(int w, int h)

{

         glViewport(0, 0, (GLsizei) w, (GLsizei) h);

         glMatrixMode(GL_PROJECTION);

         glLoadIdentity();

         gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);

}

void keyboard(unsigned char key, int x, int y)

{

         switch (key)

         {

         case 'c':

                   cohensutherlandlineclip(rect, pt[0],pt[1]);     

                   glutPostRedisplay();

                   break;

         default:

                   break;

         }

}

void mouse(int button, int state, int x, int y) //鼠标处理回调函数

{

         switch (button)

         {

         case GLUT_LEFT_BUTTON://鼠标左键

                   if (state == GLUT_DOWN)//按下

                   {

                            if (bInput == false)

                            {

                                     pt[0].x = x;

                                     pt[0].y = 480 - y;

                                     bInput = true;

                                     bDraw = false;

                                     accept = true;

                                     glutPostRedisplay();//

                            }

                            else

                            {

                                     pt[1].x = x;

                                     pt[1].y = 480 - y;

                                     bDraw = true;

                                     bInput = false;

                                     glutPostRedisplay();//

                            }       

                   }

                   break;

         default:

                   break;

         }

}

int main(int argc, char *argv[]) {  glutInit(&argc, argv);  glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);  glutInitWindowPosition(100, 100);  glutInitWindowSize(640, 480);  glutCreateWindow("Hello World!");

 Init();  glutDisplayFunc(myDisplay);  glutReshapeFunc(Reshape);  glutKeyboardFunc(keyboard);  glutMouseFunc(mouse); // 注册鼠标处理函数  glutMainLoop();  return 0; }

代码注释:

(1)程序增加了鼠标功能,在窗口内不同位置点击左键可生成一条直线;

(2)实现鼠标函数mouse(int button, int state, int x, int y):处理鼠标click事件的函数。一般有4个参数:第一个参数表明哪个鼠标键被按下或松开,这个变量可以是下面的三个值中的一个:

GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON

第二个参数表明,函数被调用发生时,鼠标的状态,也就是是被按下,或松开,可能取值如下:

GLUT_DOWN, GLUT_UP

当函数被调用时,state的值是GLUT_DOWN,那么程序可能会假定将会有个GLUT_UP事件,甚至鼠标移动到窗口外面,也如此。然而,如果程序调用glutMouseFunc传递NULL作为参数,那么GLUT将不会改变鼠标的状态。 

剩下的两个参数(x,y)提供了鼠标当前的窗口坐标(以左上角为原点)。

更多详细介绍请参考:http://blog.csdn.net/nauty_li/archive/2008/03/29/2227163.aspx

(3)为确保程序运行正确请不要用鼠标拖动改变窗口的大小。 

(4)附MFC代码示例:/Files/opengl/LineClip_GDI.rar

5.实验思考题

请分别给出直线的三种不同位置情况,测试实验代码是否存在问题,有的话请调试改正。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏生信小驿站

Python数据处理从零开始----第四章(可视化)(2)目录正文

=========================================================

1032
来自专栏GIS讲堂

说说地图中的聚类

虽然Openlayers4会有自带的聚类效果,但是有些时候是不能满足我们的业务场景的,本文结合一些业务场景,讲讲地图中的聚类展示。

1363
来自专栏Java帮帮-微信公众号-技术文章全总结

【Java案例】余弦函数

案例描述 在屏幕上画出余弦函数cos(x)曲线,如图1.6所示。 ? 图1.6 余弦函数cos(x)曲线 案例分析 连续的曲线是由点组成的,点与点之间距离比较...

5256
来自专栏漫漫深度学习路

tensorflow自定义op:梯度

tensorflow自定义op,梯度 tensorflow 是 自动微分的,但是如果你不给它定义微分方程的话,它啥也干不了 在使用 tensorflow 的时...

7647
来自专栏每日一篇技术文章

OpenGLES_实战04_教你绘制球体

写这篇文章主要给初学者一个绘制球体的思路,苹果给我们封装的类,帮助我们简化了不少代码,如果纯OpenGL 做这样一个练习代码量还是挺多的。

2301
来自专栏xingoo, 一个梦想做发明家的程序员

在Java Web中使用Spark MLlib训练的模型

模型下载到本地,重新命名为xml。 可以看到默认四个特征分别叫做feild_0,field_1...目标为target

1822
来自专栏从流域到海域

Python 切片(Slice)

在实际开发中,经常遇到下面的需求:在线性表(数组)中提取若干个元素的操作,提取规则有很多,比如说提取前5个、提取后5个、提取奇数/偶数位元素等等。 ...

24410
来自专栏章鱼的慢慢技术路

Direct3D 11 Tutorial 7:Texture Mapping and Constant Buffers_Direct3D 11 教程7:纹理映射和常量缓冲区

在上一个教程中,我们为项目引入了照明。 现在我们将通过向我们的立方体添加纹理来构建它。 此外,我们将介绍常量缓冲区的概念,并解释如何使用缓冲区通过最小化带宽使用...

1034
来自专栏xingoo, 一个梦想做发明家的程序员

[翻译]CURAND Libaray--Host API--(2)

2.3 返回值 所有的CURAND host端的函数返回值都是curandStatus_t.如果调用没有错误,则返回成功,即返回值为CURAND_STATUS_...

23610
来自专栏有困难要上,没有困难创造困难也要上!

Simditor修改缩进为首行缩进

3568

扫码关注云+社区

领取腾讯云代金券