Cohen Sutherland裁剪算法并使用OpenGL实践

  还是其几天写的,这是最简单的一个直线裁剪算法了吧,它针对的是一个矩形和一条线段。并且还是边与坐标轴平行的矩形。

  在实际应用上应该会经常用于屏幕对各种线段的裁剪吧。算法很简单效率也很高。

  首先是算法的两种特例:平凡接受和平凡拒绝。

(图片来自《计算机图形学(OpenGL)》第三版)

  当线段的两个端点都在矩形内部,则平凡接受,不需要裁剪。如图中的AB。而当线段的两个端点都在某条边的外边时,平凡拒绝,也不需要裁剪。如图中的CD。

  检测这两种情况的方法可以先形成两个端点的码字,如下:

那么可以得到如下的几种码字:

  如果两个点都在矩形内部,那么码字应该都是FFFF,则平凡接受,返回当前线段就好。而如果两个点的某一位都是T,则说明他们都在矩形某条边的外面,则平凡拒绝。如图3.17中的CD,对应的码字分别应是FTTF和FFTF,在第三位上都是T,他们都在矩形的右边,则平凡拒绝。

  我们运行这样的算法来裁剪一条线段:

  

  最后,代码如下:

  1 #include <GL/gl.h>
  2 #include <GL/glu.h>
  3 #include <GL/glut.h>
  4 #include <cmath>
  5 #include <iostream>
  6 using namespace std;
  7
  8 struct Point2D
  9 {
 10     float _x, _y;
 11     Point2D()
 12     {
 13         _x = 0.0f;
 14         _y = 0.0f;
 15     }
 16     Point2D(const Point2D& p)
 17     {
 18         _x = p._x;
 19         _y = p._y;
 20     }
 21     Point2D(float xx, float yy)
 22     {
 23         _x = xx;
 24         _y = yy;
 25     }
 26     Point2D& operator=(const Point2D& p)
 27     {
 28         _x = p._x;
 29         _y = p._y;
 30         return *this;
 31     }
 32     Point2D& operator+(const Point2D& p)
 33     {
 34         Point2D temp;
 35         temp._x = _x + p._x;
 36         temp._y = _y + p._y;
 37         return temp;
 38     }
 39     Point2D& operator-(const Point2D& p)
 40     {
 41         Point2D temp(_x - p._x, _y - p._y);
 42         return temp;
 43     }
 44     float operator*(const Point2D& p)
 45     {
 46         return _x * p._x + _y * p._y;
 47     }
 48
 49     float length()
 50     {
 51         return sqrtf(_x * _x + _y * _y);
 52     }
 53 };
 54
 55 struct Line2D
 56 {
 57     Point2D _start;
 58     Point2D _end;
 59     float _length;
 60
 61     Line2D() : _start(), _end()
 62     {
 63         _length = 0.0f;
 64     }
 65     Line2D(const Point2D& start, const Point2D& end) : _start(start), _end(end)
 66     {
 67     }
 68     Line2D(const Line2D& line) : _start(line._start), _end(line._end)
 69     {}
 70
 71     float length()
 72     {
 73         _length = (_end - _start).length();
 74     }
 75
 76     Line2D& operator = (const Line2D& line)
 77     {
 78         _start = line._start;
 79         _end = line._end;
 80     }
 81 };
 82
 83 struct Rect
 84 {
 85     float _left;
 86     float _right;
 87     float _up;
 88     float _down;
 89
 90     float width()
 91     {
 92         return _right - _left;
 93     }
 94     float height()
 95     {
 96         return _down - _up;
 97     }
 98 };
 99
100 enum CutRes
101 {
102     CR_ACCEPTED = 0,
103     CR_REFUSED = 1,
104 };
105
106 enum CSBIT
107 {
108     CB_BELOW = 0x01,//0001
109     CB_RIGHT = 0x02,//0010
110     CB_ABOVE = 0x04,//0100
111     CB_LEFT  = 0x08,//1000
112
113     CB_BELOW_INV = 0xfe,//1111 1110
114     CB_RIGHT_INV = 0xfd,//1111 1101
115     CB_ABOVE_INV = 0xfb,//1111 1011
116     CB_LEFT_INV     = 0xf7,//1111 0111
117 };
118
119 typedef unsigned char KEY;
120
121 /*Global Varibles*/
122 const int SCREEN_WIDTH = 800;
123 const int SCREEN_HEIGHT = 600;
124 Point2D g_Start;
125 Point2D g_End;
126 Line2D src;
127 Line2D dest;
128 bool acc;
129 Rect g_Rect;
130 int g_Count;
131
132 KEY GenKey(const Point2D& p, const Rect& r)
133 {
134     KEY key = 0;
135
136     if(p._y > r._down)
137     {
138         key |= CB_BELOW;
139     }
140     if(p._y < r._up)
141     {
142         key |= CB_ABOVE;
143     }
144     if(p._x < r._left)
145     {
146         key |= CB_LEFT;
147     }
148     if(p._x > r._right)
149     {
150         key |= CB_RIGHT;
151     }
152
153     return key;
154 }
155
156 void ShowKey(KEY key)
157 {
158     if(key & CB_LEFT)
159         cout << "T";
160     else
161         cout << "F";
162
163     if(key & CB_ABOVE)
164         cout << "T";
165     else
166         cout << "F";
167
168     if(key & CB_RIGHT)
169         cout << "T";
170     else
171         cout << "F";
172
173     if(key & CB_BELOW)
174         cout << "T";
175     else
176         cout << "F";
177 }
178
179 /*
180 key: TTFF
181 left above right below
182 */
183 int Cohen_Sutherland(const Line2D& src, Line2D& dest, const Rect& rect)
184 {
185     cout << "===============In Cohen_Sutherland===============\n";
186     Point2D start = src._start;
187     Point2D end = src._end;
188     KEY s, e;
189     dest = src;
190
191     for(unsigned int i = 0; i < 4; ++i)
192     {
193         cout << "\nNow Line: start(" << start._x << ", " << start._y <<") end(" << end._x << ", " << end._y << ")\n";
194
195         s = GenKey(start, rect);
196         e = GenKey(end, rect);
197         cout << "Key of Line: start ";ShowKey(s);cout << " end: ";ShowKey(e); cout << endl;
198
199         if((s == e) && (s == 0))
200         {
201             //accept, all point inside the rect
202             dest._start = start;
203             dest._end = end;
204             return CR_ACCEPTED;
205         }
206         int _b = 1 << i;
207         if((s & _b) && (e & _b))
208         {
209             //all point at same side
210             return CR_REFUSED;
211         }
212
213         switch(i)
214         {
215             case 0:
216             {
217                 //below
218                 if(s & _b)
219                 {
220                     float scale = (rect._down - end._y) / (start._y - end._y);
221                     start._x = (start._x - end._x) * scale + end._x;
222                     start._y = rect._down;
223                     cout << "Start Below Rect. Cutted: " << start._x << ", " << start._y << endl;
224                 }
225                 if(e & _b)
226                 {
227                     float scale = (rect._down - start._y) / (end._y - start._y);
228                     end._x = (end._x - start._x) * scale + start._x;
229                     end._y = rect._down;
230                     cout << "end Below Rect. Cutted: " << end._x << ", " << end._y << endl;
231                 }
232             }break;
233             case 1:
234             {
235                 //right
236                 if(s & _b)
237                 {
238                     float scale = (rect._right - end._x) / (start._x - end._x);
239                     start._x = rect._right;
240                     start._y = (start._y - end._y) * scale + end._y;
241                     cout << "start right Rect. Cutted: " << start._x << ", " << start._y << endl;
242                 }
243                 if(e & _b)
244                 {
245                     float scale = (rect._right - start._x) / (end._x - start._x);
246                     end._x = rect._right;
247                     end._y = (end._y - start._y) * scale + start._y;
248                     cout << "end right Rect. Cutted: " << end._x << ", " << end._y << endl;
249                 }
250             }break;
251             case 2:
252             {
253                 //above
254                 if(s & _b)
255                 {
256                     float scale = (rect._up - end._y) / (start._y - end._y);
257                     start._x = (start._x - end._x) * scale + end._x;
258                     start._y = rect._up;
259                     cout << "start above Rect. Cutted: " << start._x << ", " << start._y << endl;
260                 }
261                 if(e & _b)
262                 {
263                     float scale = (rect._up - start._y) / (end._y - start._y);
264                     end._x = (end._x - start._x) * scale + start._x;
265                     end._y = rect._up;
266                     cout << "end above Rect. Cutted: " << end._x << ", " << end._y << endl;
267                 }
268             }break;
269             case 3:
270             {
271                 //left
272                 if(s & _b)
273                 {
274                     float scale = (rect._left - end._x) / (start._x - end._x);
275                     start._x = rect._left;
276                     start._y = (start._y - end._y) * scale + end._y;
277                     cout << "start left Rect. Cutted: " << start._x << ", " << start._y << endl;
278                 }
279                 if(e & _b)
280                 {
281                     float scale = (rect._left - start._x) / (end._x - start._x);
282                     end._x = rect._left;
283                     end._y = (end._y - start._y) * scale + start._y;
284                     cout << "end left Rect. Cutted: " << end._x << ", " << end._y << endl;
285                 }
286             }break;
287         }
288     }
289     s = GenKey(start, rect);
290     e = GenKey(end, rect);
291
292     cout << "At Last, Key of Line: start ";ShowKey(s);cout << " end: ";ShowKey(e); cout << endl;
293     if((s == e) && (s == 0))
294     {
295         //accept, all point inside the rect
296         dest._start = start;
297         dest._end = end;
298         return CR_ACCEPTED;
299     }
300     else
301     {
302         return CR_REFUSED;
303     }
304 }
305
306 void myInit()
307 {
308     /*
309     Output Info
310     */
311
312     g_Rect._up = 100;
313     g_Rect._down = 500;
314     g_Rect._left = 100;
315     g_Rect._right = 700;
316     g_Count = 0;
317     acc = false;
318     cout << "Rect: {" << g_Rect._left << ", " << g_Rect._up << ", " << g_Rect._right << ", "<< g_Rect._down << "}\n";
319
320     glClearColor((float)0x66 / 0x100, (float)0xcc / 0x100, 1.0, 0.0);
321     glColor3f(0.0f, 0.0f, 0.0f);//Map Color Black
322     glPointSize(1.0);
323     glMatrixMode(GL_PROJECTION);
324
325     glLoadIdentity();
326     gluOrtho2D(0.0, (GLdouble)SCREEN_WIDTH, (GLdouble)SCREEN_HEIGHT, 0.0);
327     glViewport(0.0, SCREEN_WIDTH, 0.0, SCREEN_HEIGHT);
328 }
329
330 void myMouse(int button, int state, int x, int y)
331 {
332     if(button != GLUT_LEFT_BUTTON || state != GLUT_DOWN)
333         return;
334
335     cout << "MyMouse Called with " << x << ", " << y << endl;
336     switch(g_Count)
337     {
338     case 0:
339     {
340         ++g_Count;
341         g_Start._x = x;
342         g_Start._y = y;
343         src._start = g_Start;
344     }break;
345     case 1:
346     {
347         ++g_Count;
348         g_End._x = x;
349         g_End._y = y;
350         src._end = g_End;
351         acc = Cohen_Sutherland(src, dest, g_Rect);
352         if(acc)
353         {
354             cout << "Refused.\n";
355         }
356         else
357             cout << "Accept.\n";
358
359         glutPostRedisplay();
360     }break;
361     case 2:
362     {
363         g_Start._x = x;
364         g_Start._y = y;
365         src._start = g_Start;
366         g_Count = 1;
367     }break;
368     }
369 }
370
371 void myDisplay()
372 {
373     glClear(GL_COLOR_BUFFER_BIT);
374
375     //Draw Rect
376
377     glColor3f(0.0f, 0.0f, 0.0f);//Rect
378     glPointSize(2.0);
379     glBegin(GL_LINE_STRIP);
380       glVertex2d(g_Rect._left, g_Rect._up);
381       glVertex2d(g_Rect._right, g_Rect._up);
382       glVertex2d(g_Rect._right, g_Rect._down);
383       glVertex2d(g_Rect._left, g_Rect._down);
384       glVertex2d(g_Rect._left, g_Rect._up);
385     glEnd();
386
387     if(g_Count == 2)
388     {
389         //Draw Line
390         glColor3f(1.0f, 0.0f, 0.0f);//Normal Line, Red
391         glPointSize(2.0);
392         glBegin(GL_LINES);
393           glVertex2d(src._start._x, src._start._y);
394           glVertex2d(src._end._x, src._end._y);
395         cout << "\nDraw Line\n";
396         if(acc == CR_ACCEPTED)
397         {
398             //Draw Cutted Line
399             glColor3f(0.0f, 1.0f, 0.0f);//Normal Line, Green
400             glPointSize(2.0);
401               glVertex2d(dest._start._x, dest._start._y);
402               glVertex2d(dest._end._x, dest._end._y);
403             cout << "\nDraw CutLine\n";
404         }
405         glEnd();
406     }
407
408     //glutSwapBuffers();
409     glFlush();
410     //cout << "Render Over\n";
411 }
412
413 int main(int argc, char* argv[])
414 {
415     glutInit(&argc, argv);
416     //glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
417     glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
418     glutInitWindowSize(SCREEN_WIDTH, SCREEN_HEIGHT);
419     glutInitWindowPosition(0, 0);
420     glutCreateWindow("Cohen Sutherland");
421     glutDisplayFunc(myDisplay);
422     glutMouseFunc(myMouse);
423
424     myInit();
425     glutMainLoop();
426
427     return 0;
428 }

Cohen_Sutherland_with_GL

  程序最上面是一些数据结构的定义,包括Point2D、Line2D、Rect等。

  然后码字我选择使用unsigned char类型的低四位,从高往低分别代表矩形的左、上、右、下。枚举类型CSBIT用来方便我进行位操作。

  算法核心函数是Cohen_Sutherland函数,接受一条直线和一个矩形为参数,一条直线作为输出并返回是否拒绝。GenKey函数和showKey分别用来生成码字和以友好的方式显示码字。

  其他则是OpenGL的东西了。程序运行后会有一个预先设定好的矩形,然后可以不断的通过鼠标点击选取起点和终点产生一条线段,并用之前的矩形进行裁剪。

  运行效果:

时间: 2024-08-05 07:02:43

Cohen Sutherland裁剪算法并使用OpenGL实践的相关文章

Cyrus-Beck裁剪算法及OpenGL实践

恩..接着就是Cyrus-Beck算法.这个算法比之前的Cohen-Sutherland算法厉害,处理任意凸多边形对线段的裁剪.自然,这个算法也比Cohen-Sutherland算法复杂不少. 首先,是线段与多边形相交的情况: 我们把定义向量c = (C - A),而线段AC是射线A + ct的一部分.那么t取0和1就是线段AC.我们将射线与多边形的每条边求出相交时的t.取tin = max(0, tin),tout = max(tout, 1).最终会获得一个区间[tin,tout]就是经多边

[计算机图形学 with OpenGL] Chapter8 习题8.12 NLN二维线段裁剪算法实现

Nicholl-Lee-Nicholl二维线段裁剪算法相对于Cohen-Sutherland和Liang-Barsky算法来说,在求交点之前进行了线段端点相对于几个区域的判断,可以确切的知道要求交点的边的信息. 此方法只在二维空间裁剪时使用,C-S和L-B裁剪方法则可应用到三维空间. 算法步骤: 1 先使用C-S裁剪算法的区域码判断方法,去除一部分在裁剪区域外面的线段.显示在完全在裁剪区域内的线段.其他不能判断的情况,采用NLN算法进行裁剪. 2 p1和p2若有一点在区域内,必要时交换端点以确保

清华版CG 实验4 编码裁剪算法

1.实验目的: 了解二维图形裁剪的原理(点的裁剪.直线的裁剪.多边形的裁剪),利用VC+OpenGL实现直线的裁剪算法. 2.实验内容: (1) 理解直线裁剪的原理(Cohen-Surtherland算法.梁友栋算法) (2) 利用VC+OpenGL实现直线的编码裁剪算法,在屏幕上用一个封闭矩形裁剪任意一条直线. (3) 调试.编译.修改程序. (4) 尝试实现梁友栋裁剪算法. 3.实验原理: 编码裁剪算法中,为了快速判断一条直线段与矩形窗口的位置关系,采用了如图A.4所示的空间划分和编码方案.

CGA裁剪算法之Sutherland-Hodgman多边形裁剪算法

CGA裁剪算法之Sutherland-Hodgman多边形裁剪算法 Sutherland-Hodgman算法也叫逐边裁剪法,该算法是萨瑟兰德(I.E.Sutherland)和霍德曼(Hodgman)在1974年提出的. 这种算法采用了分割处理.逐边裁剪的方法.这一算法,适合任何凸多边形窗口对任何“凸或者凹,或者平面或者非平面”多边形的裁剪处理. 逐边逐次裁剪特点:逐边是分别用裁剪平面的边界来处理,且裁剪各个边界的处理顺序无关紧要.逐次是每次的裁剪边界对多边形的每条边处理是依次进行的,有顺序要求.

矩形裁剪算法_python3最终版

环境准备: Python版本是3.5.1.使用pip命令:pip install pyopengl 安装pyopengl模块 另外注意需要将opengl文件(打开文件链接,也可自行百度)复制到系统盘System32(32位系统)或SysWOW64(64位系统)目录下,不然可能或报错.我今天在学校实验室碰到了此问题,错误信息好像是glutInit函数不能使用之类的. 说明: 老师的要求是实现键盘输入和鼠标点击两种交互方式,没法子,只好封装一下函数,方便调用了. 代码: #encoding='utf

矩形裁剪算法_pyopengl

环境准备: Python版本是3.5.1.使用pip命令:pip install pyopengl 安装pyopengl模块. 图形学期末设计,不知道用opengl或webgl做什么炫酷的效果,只好做算法了,悲剧的写了500多行,缺点是裁剪算法未封装成函数. 代码如下: #encoding='utf-8' #python3.5.1 #author by 张政伟 2016/6/16 #矩形裁剪算法 from OpenGL.GLUT import * from OpenGL.GL import *

裁剪算法——多边形裁剪/文字裁剪

五.多边形裁剪 多边形裁剪算法的输出应该是裁剪后的多边形边界的[定点序列]! 5.1Sutherland-Hodgeman多边形裁剪-->[分而治之]基本思想:将多边形边界作为一个整体,每次用窗口的一条边对要裁剪的多边形和中间结果多边形进行裁剪.把平面分为两个区域:包含有窗口区域的一个域称为可见侧:不包含窗口区域的域为不可见侧.裁剪得到的结果多边形的顶点有两部分组成:    (1)落在可见一侧的原多边形顶点:    (2)多边形的边与裁剪窗口边界的交点. 根据多边形每一边与窗口所形成的位置关系,

郑捷《机器学习算法原理与编程实践》学习笔记(第六章 神经网络初步)6.3 自组织特征映射神经网路(SMO)

具体原理网址:http://wenku.baidu.com/link?url=zSDn1fRKXlfafc_tbofxw1mTaY0LgtH4GWHqs5rl8w2l5I4GF35PmiO43Cnz3YeFrrkGsXgnFmqoKGGaCrylnBgx4cZC3vymiRYvC4d3DF3 自组织特征映射神经网络(Self-Organizing Feature Map.也称Kohonen映射),简称为SMO网络,主要用于解决模式识别类的问题.SMO网络属于无监督学习算法,与之前的Kmeans算

《机器学习算法原理与编程实践》学习笔记(二)

(上接第一章) 1.2 对象.矩阵与矢量化编程 1.2.1对象与维度(略) 1.2.2初识矩阵(略) 1.2.3矢量化编程与GPU运算(略) 1.2.4理解数学公式与NumPy矩阵运算 1.矩阵的初始化 #coding:utf-8 import numpy as np #导入NumPy包 #创建3*5的全0矩阵和全1的矩阵 myZero = np.zeros([3,5])#3*5的全0矩阵 print myZero myZero = np.ones([3,5])##3*5的全1矩阵 print