直线矩形视口裁剪算法 Cohen–Sutherland algorithm
来源:互联网 发布:有钱人的三观 知乎 编辑:程序博客网 时间:2024/06/05 20:41
直线矩形视口裁剪算法 Cohen–Sutherland algorithm
算法参见:
http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
算法思路
- 在二维平面中,将一个矩形的四条边无限延伸,可以将平面分割成九个区域,中心的区域就是矩形本身。
- 将每个区域给予不同的编号,为了方便使用,采用4个位来表示一个二维平面的一个区域。前2位为相对于矩形区域的上下的区域,后两位为矩形区域左右的区域。
能够明显看到左右、上下分别赋值给不同的位为1,这样计算出一个点的区域码后,就可以很方便的使用。
0101 0100 0110 0001 0000 0010 1001 1000 1010 - 一条线段的两个端点的区域码做与预算&如果不为0,说明这个线段不用显示。
- 一个线段的两个端点区域码或运算|后如果为0,说明他们都在区域内。
- 其他情况,我们需要进行裁剪。裁剪过程可以是一个递归的过程:
- 首先使一个端点的一个轴的坐标在视口的范围内,另一个坐标随之变化。
- 判断新得到的点对是否满足3、4中的条件,如果不满足重复上一步,直到满足这个条件。
C++实现(采用OpenGL 4.5绘制)
======
#include <iostream>#include <math.h>#include <stdlib.h>using namespace std;#include "vgl.h"#include "LoadShaders.h"enum VAO_IDs { Triangles, NumVAOs };enum Buffer_IDs { ArrayBuffer, NumBuffers };enum Attrib_IDS { vPosition = 1 };GLuint VAOs[NumVAOs];GLuint Buffers[NumBuffers];const GLuint NumVertices = 3;// 效率测量用开始、结束时间SYSTEMTIME tStart, tEnd;const intOUTSIDE_UP = 0x04, // 视口上方OUTSIDE_DOWN = 0x08, // 视口下方OUTSIDE_LEFT = 0x01, // 视口左方OUTSIDE_RIGHT = 0x02, // 视口右方OUTSIDE_MID = 0x00, // 视口竖直中部OUTSIDE_CENTER = 0x00; // 视口水平中// 设置视口的大小const GLfloatVIEWPORT_UP = 0.5,VIEWPORT_DOWN = -0.3,VIEWPORT_LEFT = -0.8,VIEWPORT_RIGHT = 0.5;/* * 计算一个点相对于视口的区域码。 * Ref: http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm */int calculateAreaCode(GLfloat x, GLfloat y) { int code = 0x00; if (x > VIEWPORT_RIGHT) { code |= OUTSIDE_RIGHT; } else if (x < VIEWPORT_LEFT) { code |= OUTSIDE_LEFT; } else { code |= OUTSIDE_CENTER; } if (y > VIEWPORT_UP) { code |= OUTSIDE_UP; } else if (y < VIEWPORT_DOWN) { code |= OUTSIDE_DOWN; } else { code |= OUTSIDE_MID; } return code;}/** * 对一条线段在一个矩形视口中进行裁剪,并判断其是否需要绘制。 * 如果这个线段完全在视口外,则不进行裁剪,也不进行显示; * 如果这个线段完全在视口内,不进行裁剪,进行显示; * 如果这个线段部分在视口内,则进行裁剪,进行显示。 * 裁剪算法使用Cohen-Sutherland算法。具体参见: * http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm * * @param x0ptr 端点0的横坐标指针 * @param y0ptr 端点0的纵坐标指针 * @param x1ptr 端点1的横坐标指针 * @param y1ptr 端点1的纵坐标指针 * @return 如果需要显示返回true,反之返回false */bool cohenSutherlandAlgorithm(GLfloat* x0ptr, GLfloat* y0ptr, GLfloat* x1ptr, GLfloat* y1ptr) { bool accepted = false; // 表示这个线段是否要进行显示 while (true) { GLfloat x0 = *x0ptr, y0 = *y0ptr, x1 = *x1ptr, y1 = *y1ptr; // 计算区域码 int areaCode0 = calculateAreaCode(x0, y0); int areaCode1 = calculateAreaCode(x1, y1); // 两个都在视口范围内,不进行裁剪 if (!(areaCode0 | areaCode1)) { accepted = true; break; } // 两个都不在视口范围内,且处于同一侧,不进行裁剪,丢弃 if (areaCode0 & areaCode1) { break; } // 选取其中在区域外的端点 int areaCodeOut = areaCode0 != 0 ? areaCode0 : areaCode1; GLfloat newX = 0.0, newY = 0.0; // 计算交叉点,一次至少使一个轴的坐标是在视口内的 if (areaCodeOut & OUTSIDE_UP) { newY = VIEWPORT_UP; // 在这里不会出现y0 == y1的情况 newX = (x0 - x1) / (y0 - y1) * (newY - y0) + x0; } else if (areaCodeOut & OUTSIDE_DOWN) { newY = VIEWPORT_DOWN; // 在这里不会出现y0 == y1的情况 newX = (x0 - x1) / (y0 - y1) * (newY - y0) + x0; } else if (areaCodeOut & OUTSIDE_LEFT) { newX = VIEWPORT_LEFT; // 在这里不会出现x0 == x1的情况 newY = (y0 - y1) / (x0 - x1) * (newX - x0) + y0; } else if (areaCodeOut & OUTSIDE_LEFT) { newX = VIEWPORT_RIGHT; // 在这里不会出现x0 == x1的情况 newY = (y0 - y1) / (x0 - x1) * (newX - x0) + y0; } if (areaCodeOut == areaCode0) { *x0ptr = newX; *y0ptr = newY; } else { *x1ptr = newX; *y1ptr = newY; } } return accepted;}void init(void) { glGenVertexArrays(NumVAOs, VAOs); glBindVertexArray(VAOs[Triangles]); GLfloat *points = new GLfloat[4]; // 任意输入4个数字,分别为线段端点的坐标x0, y0, x1, y1 cin >> points[0] >> points[1] >> points[2] >> points[3]; // 用 Cohen-Sutherland Algorithm 对直线进行裁剪。 cohenSutherlandAlgorithm(points, points + 1, points + 2, points + 3); glGenBuffers(NumBuffers, Buffers); glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, points, GL_STATIC_DRAW); delete[] points; ShaderInfo shaders[] { { GL_VERTEX_SHADER, "triangles.vert" }, { GL_FRAGMENT_SHADER, "triangles.frag" }, { GL_NONE, NULL } }; GLuint program = LoadShaders(shaders); glUseProgram(program); glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); glEnableVertexAttribArray(vPosition); // 设置线段宽度大小为5像素 glLineWidth(50);}void display(void) { // 效率测量 GetLocalTime(&tStart);// glViewport(100, 100, 512, 512); glClear(GL_COLOR_BUFFER_BIT); glBindVertexArray(VAOs[Triangles]); glDrawArrays(GL_LINES, 0, 2); // glFlush(); glFinish(); // 效率测量 GetLocalTime(&tEnd); cout << "Total Time: " << tEnd.wMilliseconds - tStart.wMilliseconds << endl;}int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutInitWindowSize(512, 512); glutInitContextVersion(4, 5); glutInitContextProfile(GLUT_CORE_PROFILE); glutCreateWindow(argv[0]); glewExperimental = GL_TRUE; if (glewInit()) { cerr << "Unable to initialize GLEW ... exiting" << endl; exit(EXIT_FAILURE); } init(); glutDisplayFunc(display); glutMainLoop(); return 0;}
0 0
- 直线矩形视口裁剪算法 Cohen–Sutherland algorithm
- opengl 直线裁剪Cohen-Sutherland算法
- Cohen-Sutherland直线段的裁剪算法
- Cohen-Sutherland裁剪算法
- Cohen-Sutherland裁剪算法
- 计算机图形学-直线裁剪(Cohen-Sutherland编码裁剪算法)
- Cohen-Sutherland线段裁剪算法
- Cohen-Sutherland算法线段裁剪
- Cohen-Sutherland线段裁剪算法
- Cohen-Sutherland线段裁剪算法
- Cohen-Sutherland算法裁剪线段
- [OpenGL]计算机图形学:直线裁剪算法中Cohen-Sutherland算法和Liang-Barsky算法
- Tubor C 直线裁剪算法 Cohen-Sutherland算法 (可运行代码)
- Cohen-SutherLand 裁剪算法 (vc++)
- Cohen-Sutherland线段裁剪算法
- Cohen-Sutherland 窗口裁剪线段算法
- 计算机图形学 - 线段裁剪 - Cohen Sutherland算法
- Windows游戏编程大师技巧之Cohen-Sutherland裁剪直线算法
- 是否缺少using指令或者程序集引用?
- javaweb项目部署到tomcat中
- MongoDB Replica Sets管理
- 大数分块乘法
- java 与c++ 不同点
- 直线矩形视口裁剪算法 Cohen–Sutherland algorithm
- Qt - OpenCV 连续图片生成视频
- HDU 1716 排列2
- android---surfaceview小结--(1)
- 三月随笔
- iOS UICollectionView 入门 06 添加标题view
- 1.2 系统平台——CentOS 6
- 【HDU 3642 求长方体的体积并
- 漂洋过海来看你 【dfs or 最短路】