一、概念

裁剪是CG中许多重要问题的基础,裁剪最典型的用途是确定场景中或画面中位于给定区域之内的部分。由于在一个典型的场景之中,需要对大量的点、线段进行裁剪,因此裁剪算法的效率十分重要。

关于裁剪有一些很常见的算法,比如说Cohen-Sutherland线段细分裁剪算法、中点分割算法、Cyrus-Beck算法、Liang-Barsky算法。这篇文章重点讲Liang-Barsky算法。剩下的那些算法有空再补。

二、Liang-Barsky算法

参考博客:

https://www.cnblogs.com/keguniang/p/9688126.html

https://blog.csdn.net/pleasecallmewhy/article/details/8393445

首先知道直线和裁剪框的位置关系,如下图:

可以看到直线可能完全在裁剪框的外面,也可能完全在裁剪框的里面,或者和裁剪框相交。

所以是裁剪的规则是这样的:

如果直线的两个端点都在窗口边界之内,如ab,则直线保留;如果直线的一个端点在窗口边界之内,另一个端点在窗口边界之外,如ef,则应从直线与边界的交点处裁剪掉边界之外的线段;如果直线的两个端点都在窗口边界之外,有两种情况:一种情况如ij,直线全部在窗口之外,应该全部裁减掉;另一种情况如gh,直线横穿窗口边界,应该保留相交的片段,裁减掉剩余的片段;

那么怎么去判断呢? 在讲述判断步骤之前我们要了解一个基础理论,那就是编码:

图中阴影部分是裁剪框,我们把这个区域分成了9份,采用了四位数标识线段的端点位于九个区域的哪个区域位置,从右往左数:

第一个位置为1-------如果线段端点位于窗口左侧第二个位置为1------如果线段端点位于窗口右侧第三个位置为1------如果线段端点为窗口下面第四个位置为1------如果线段位于窗口上面

------------------------------------------------------------------接下来是算法推导-----------------------------------------------------------------------------

如下图所示

1.我们用方程表示直线P1P2,其中t就是直线的斜率,t∈[0,1]:

裁剪区域内部可以表达为两个不等式:

把直线方程代入得到不等式:

2.把直线看成是一条有方向的线段,把窗口的四条边及其延长线分成两类:入边和出边

入边:左边界和下边界------从裁剪框外向裁剪框内

出边:右边界和上边界------从裁剪框内向裁剪框外

3.分情况讨论

①d=0,q<0,  说明直线与裁剪框平行,并且位于裁剪框的外面,直线为不可见,可抛弃,直接结束

q>=0,说明直线在它所平行的窗口边界的内部,还需进一步计算确定直线是否在窗口内、外、或者相交

②d<0,说明直线是从裁剪边界的外部延伸到内部

③d>0,   说明直线是从裁剪边界的内部延伸到外部

对于d≠0,可以利用式子计算直线与边界k的交点的参数u。对于每条直线,可以计算直线位于裁剪窗口内线段的参数d1和d2

d1的值是由那些使得直线是从外部延伸到内部的窗口边界决定。对于这些边计算ri = qi/di.

d1 = max(ri,0)

d2的值是由那些使得直线是从内部延伸到窗口边界决定

d2 = min(ri,1)

如果d1>d2,这条直线完全在窗口的外面,不可见,可抛弃,否则,根据参数u的两个值,计算出裁剪后线段的端点

如果没有看懂,可以看该博主的https://blog.csdn.net/pleasecallmewhy/article/details/8393445

所以伪代码如下:

#Liang-Barsky two-dimensional clipping algorithm
#P1 and P2 are the line end points with components x1,y1,x2,y2
#tL and tU are the lower and upper parametric limits
#xL,xR,yB,yT are the left,right,bottom and top window edgesfunction clipt(d,q,tL,tU):clipt performs trivial rejection tests and findsthe max of the lower set of parameter values and the min of the upper set of parameter valuesvisible = trueif d=0 and q<0 then #line is outside and parallel to edgevisible = falseelse if d < 0 then #looking for upper limitt = q/dif t>tU then #check for trivial invisiblevisible = falseelse if t>tL then #find the min of the maxtL = tend ifelse if d>0 then #look for the lower limitt = q/dif t<tL then #check for trivial invisiblevisible = falseelse if t<tU then #find the max of the mintU = tend ifend ifreturn visibleend functionstart the main funciton:tL=0,tU=1delatx = x2-x1if clipt(-delatx,x1-xL,tL,tU) = true then #left edgeif clipt(delatx,xR-x1,tL,tU) = true then #right edgedeltay = y2-y1if clipt(-deltay,y1-yB,tL,tU) = true then #bottom edgeif clipt(deltay,yT-y1,tL,tU) = true then #top edgeif tU<1 then x2 = x1+tU*delatxy2 = y1+tU*deltayend ifif tL>0 thenx1 = x1+tL*deltaxy1 = y1+tL*deltayend ifDraw P1,P2end ifend ifend ifend iffinish

最终实现的代码如下:

#include <windows.h>
#include <GL/glut.h>
#include <math.h>
#include<stdio.h>
float xmin,xmax,ymin,ymax;void myinit(void)
{glShadeModel (GL_FLAT);glClearColor (1.0, 1.0, 1.0, 0.0);
}void myReshape(int w, int h)
{glViewport(0, 0, w, h);glMatrixMode(GL_PROJECTION);glLoadIdentity();if (w <= h) gluOrtho2D (0.0, 1.0, 0.0, 1.0*(GLfloat)h/(GLfloat)w);else gluOrtho2D (0.0, 1.0*(GLfloat)w/(GLfloat)h, 0.0, 1.0);glMatrixMode(GL_MODELVIEW);
}int Clip(float p,float q,float *tL,float *tU)
{  int flag=1;/*flag为标志变量0表示舍弃1表示可见*/ float r; if (p<0.0) { r=q/p; if (r>*tU)flag=0; else if (r>*tL) {*tL = r;/*m取进入点最大参数值*/ } } else if (p>0.0) { r=q/p; if (r<*tL)flag=0; else if (r<*tU) {*tU = r;/*n取离开点的最小值*/ } } else if (q<0 && p==0) //平行于边界而且在界外的线 flag=0; return flag;
}
void myclip()
// line clipping algorithm
{float dx, dy, x1,tL,tU, x2, y1, y2;tL = 0, tU = 1.0;printf("请输入线段的两个顶点坐标x1,y1,x2,y2:\n");scanf("%f%f%f%f",&x1,&y1,&x2,&y2);glBegin(GL_LINES); glColor4f (0.0, 0.0, 0.0, 0.0); glVertex2f(x1, y1); // line startpoint glVertex2f(x2, y2); // line endpoint glEnd(); dx=x2-x1; if (Clip(-dx, x1 - xmin, &tL, &tU))if (Clip(dx, xmax - x1, &tL, &tU)){dy=y2-y1; if (Clip(-dy, y1 - ymin, &tL, &tU))if (Clip(dy, ymax - y1, &tL, &tU)){ if (tU<1.0) { x2 = x1 + tU*dx;//通过n求得裁剪后的p2端点 y2 = y1 + tU*dy;} if (tL>0.0){ x1 = x1 + tL*dx;//通过m求得裁剪后的p1端点 y1 = y1 + tL*dy;} glBegin(GL_LINES); glColor4f (1.0, 0.0, 0.0, 1.0); glVertex2f( x1, y1); // clipped line startpoint glVertex2f( x2, y2); // clipped line endpoint glEnd();} } }void display(void){glClear(GL_COLOR_BUFFER_BIT);printf("请分别输入矩形的左右下上边界:\n");scanf("%f%f%f%f",&xmin,&xmax,&ymin,&ymax);glColor4f (1.0, 1.0, 0.0, 0.75);glBegin(GL_POLYGON);glVertex2f( xmin, ymin); // Bottom LeftglVertex2f( xmax, ymin); // Bottom LeftglVertex2f( xmax, ymax); // Bottom RightglVertex2f( xmin, ymax); // Bottom RightglEnd();myclip();glFlush();
}/*  Main Loop*  Open window with initial window size, title bar, *  RGBA display mode, and handle input events.*/
int main(int argc, char** argv)
{glutInit(&argc, argv);glutInitDisplayMode (GLUT_SINGLE | GLUT_RGBA);//define size and the relative positon of the applicaiton window on the displayglutInitWindowSize (500, 500); glutInitWindowPosition (100, 100);//init the defined window with "argv[1]" as topic showed on the top the windowglutCreateWindow (argv[0]);// opengl setupmyinit ();//define callbacksglutDisplayFunc(display); glutReshapeFunc(myReshape);//enter the loop for displayglutMainLoop();return 1;
}

在运行该代码之前需要配置opengl环境,若没有配置,请参考该博客:https://blog.csdn.net/keneyr/article/details/83626935

代码运行结果如下:

图形学初步--裁剪算法之Liang-Barsky算法相关推荐

  1. 图形学初步--------种子填充算法

    上篇博文讲到了填充算法的扫描线填充,这篇博文讲解另一大算法思路----------种子填充. 一.概念 种子填充算法假设在多边形或区域内部至少有一个像素是已知的.然后设法找到区域内所有其他像素,并对它 ...

  2. 裁剪任意直线段 liang-barshky算法 c

    一. 实验目的. 使用liang-barshky算法实现裁剪任意直线段实验工具 二. 实验工具 VC6.0 三. 实验步骤 思想:以直线的参数方程为基础: X=x1 + u(x2-x1) Y =y1 ...

  3. 计算机图形学第一次上机——中点线算法和中点圆算法

    计算机图形学第一次上机实验 课程实验报告 目录 计算机图形学第一次上机实验 课程实验报告 一.实验目的 二.实验环境 三.实验内容 1.中点线算法 2.中点圆算法 四.实验心得 附录:程序源代码 一. ...

  4. 算法(一) 算法初步

    算法(一) 算法初步 1. 十进制转为二进制(除二取余法) 简单的求值方法: 给出一个数字x,求x十进制各位相加的和 (将它转化为二进制呢?) temp=1; while(x>0){ ans+= ...

  5. 算法设计与分析——算法基础初步了解

    算法的概念 算法:一个有计算步骤构成的序列,可以将一组输入值转换成相应的输出值.或可以用例解决一个明确的问题. 问题:输入及相应输出的描述: 算法的特点:确定性.可行性.输入和输出及有穷性. 正确的算 ...

  6. 图形学基础笔记I:直线和圆的光栅算法、中点线算法、中点圆算法

    实际现代显卡支持的图元就只有点.线.三角形.这是基于这样的事实: 实际对于 3D 来说肯定全是基于三角形的 geometry - OpenGL: Is it more efficient to use ...

  7. 经典算法书籍推荐以及算法书排行【算法四库全书】

    经典算法书籍推荐以及算法书排行[算法四库全书] 作者:霞落满天   https://linuxstyle.blog.csdn.net/    https://blog.csdn.net/21aspne ...

  8. 数据挖掘算法_算法篇(01) 数据挖掘算法初探

    前言 无论是传统行业,还是互联网行业.掌握数据,就是掌握规律.当你了解了市场数据,对它进行分析,就可以得到市场规律.当你掌握了产品自身的数据,对它进行分析,就可以了解产品的用户来源.用户画像等等.所以 ...

  9. hash的算法 java_【数据结构与算法】一致性Hash算法及Java实践

    追求极致才能突破极限 一.案例背景 1.1 系统简介 首先看一下系统架构,方便解释: 页面给用户展示的功能就是,可以查看任何一台机器的某些属性(以下简称系统信息). 消息流程是,页面发起请求查看指定机 ...

  10. 最佳适应算法和最坏适应算法_算法:好,坏和丑陋

    最佳适应算法和最坏适应算法 by Evaristo Caraballo 通过Evaristo Caraballo 算法:好,坏和丑陋 (Algorithms: The Good, The Bad an ...

最新文章

  1. JavaScript 爆红后,微软为何还要开发 TypeScript?
  2. 程序员总结:帮助你早些明白一些道理
  3. 简述Linux文件系统通过i节点把文件的逻辑结构和物理结构转换的工作过程。
  4. 打工人一次性考过高项的备考指南(52.50.50)
  5. 数据科学学习课件:实用数据挖掘与人工智能
  6. 班尼机器人怎么拆_512个焊点独自焊完,武汉一高中生在机器人比赛中摘得五块奖牌...
  7. SAP Fiori Launchpad tile跳转目标的解析逻辑
  8. LeetCode 881. 救生艇(贪心,双指针)
  9. java nio 面试题_10个最高频的Java NIO面试题剖析!
  10. python工厂模式和单例模式_python之单例模式和工厂模式
  11. ARCore学习指引四剑客:原生、Unity、Unreal和WebAR
  12. android自定义鼠标指针,修改Android系统的鼠标光标
  13. 原型工具Axure:Axure的实用小技巧
  14. 硬盘录像机常见问题解答硬盘录像机故障解决
  15. C++语言里的pow函数(初学)
  16. c 语言编程规则,C语言编程之 makfile规则.doc
  17. 为什么使用PHP语言?Web开发使用的PHP优势是什么?
  18. 奥维互动地图GEE协议历史影像分析与应用
  19. 2022完整版青龙面板对接傻妞机器人
  20. net start mysql:无法启动

热门文章

  1. 保险经纪公司达信联合IBM开发区块链平台
  2. android 如何发送短信,如何在android中发送短信
  3. WDF基本对象和句柄定义
  4. websocket与下位机通过netty方式通信传输行为信息
  5. 搜狗拼音输入发-自定义短语记录
  6. docker拉取镜像报错unexpected EOF的解决方法
  7. ftp文件服务器存储空间,查看ftp服务器存储空间
  8. python 判断闰年
  9. 计算机存储器与寄存器的区别,存储器与寄存器的区别
  10. 有人说做运营死路一条,但他没搞清运营是做什么的!