个人博客:www.vectormoon.net

算法背景

    Liang-Barsky算法由梁友栋和Barsky共同发表,是目前计算机图形学最经典的算法之一。他们认为线段裁剪的问题是:裁剪窗口是二维对象,而线段是一维对象,两个对象的维度不同不便比较。他们给出的解决思路是,将裁剪线段和裁剪窗口看为点集裁剪的结果是两个点集的交集。

算法思想

    Liang-Barsky算法的主要思想有两部分:

  • 用参数方程表示直线
  • 将待裁剪直线看作是一个有方向的线

用参数方程表示直线

    算法背景中提到Liang-Barsky算法的解决思路是,将裁剪线段和裁剪窗口看为点集裁剪的结果是两个点集的交集。那么裁剪线段如何转换点集呢?很显然用参数方程来表示直线。

    设待裁剪线段为P1P2P_1P_2P1​P2​,其中P1=(x1,y1),P2=(x2,y2)P_1=(x_1,y_1),P_2=(x_2,y_2)P1​=(x1​,y1​),P2​=(x2​,y2​),用参数关系u表示有下图关系:

显见有如下关系:

{x=x1+u∗(x2−x1)=x1+u∗Δx0≤u≤1;y=y1+u∗(y2−y1)=y1+u∗Δy0≤u≤1.\begin{cases}x=x_1+u*(x2-x1)=x_1+u*\Delta x & 0\leq u \leq 1;\\y=y_1+u*(y2-y1)=y_1+u*\Delta y & 0\leq u \leq 1.\end{cases}{x=x1​+u∗(x2−x1)=x1​+u∗Δxy=y1​+u∗(y2−y1)=y1​+u∗Δy​0≤u≤1;0≤u≤1.​

当u=0u=0u=0时,x=x1,y=y1x=x_1,y=y_1x=x1​,y=y1​也就是P1P_1P1​;
当u=1u=1u=1时,x=x2,y=y2x=x_2,y=y_2x=x2​,y=y2​也就是P2P_2P2​;
当u=0.5u=0.5u=0.5时,也就是该直线中点位置。

由上面三种情况可以很容易归纳出该图像的几何意义:也就是u值即可表示要裁剪线段的多少

将待裁剪直线看作是一个有方向的线

    从上面我们知道u的取值可以决定线段要裁剪的多少,那么u到底如何取值变成了现在的首要目标?

    我们将四个窗口的交边分别定义成两类边:入边出边

  • 入边:指从裁剪窗口之外进入到裁剪窗口方向的边
  • 出边:指从裁剪窗口之内延伸到窗口之外的边

    待裁剪线段和裁剪窗口必定会有四个交点(包括与裁剪窗口延长线的交点)分别设四个交点分别为c1,c2,c3,c4c_1,c_2,c_3,c_4c1​,c2​,c3​,c4​。设待裁剪直线为P1P2P_1P_2P1​P2​。则有下图:


    显见要裁剪线段为P1P_1P1​和c3c_3c3​所夹线段,所以u的选取就要从P1,c3P_1,c_3P1​,c3​所对应u1,u2u_1,u_2u1​,u2​入手,则显见有如下关系式:

u1=max(c1,c2,P1)u_1=max(c_1,c_2,P_1)u1​=max(c1​,c2​,P1​)    u1u_1u1​是两个入边和P1P_1P1​对应u值的最小值
u2=min(c3,P2,c4)u_2=min(c_3,P_2,c_4)u2​=min(c3​,P2​,c4​)    u2u_2u2​是两个出边和P2P_2P2​对应u值的最大值

u1,u2u_1,u_2u1​,u2​的值要满足u1<u2u_1<u_2u1​<u2​

    只要求出u1,u2u_1,u_2u1​,u2​就能算出裁剪线段,但是要求出u1,u2u_1,u_2u1​,u2​的话,就又出现了两个新的问题:

  • 如何算出四个交点c1,c2,c3,c4c_1,c_2,c_3,c_4c1​,c2​,c3​,c4​所对应的u值
  • 如何确定哪两个边是出边,哪两个边是入边

四个交点对应的u值

在上面用参数方程表示直线章节中,我们提出了:

{x=x1+u∗(x2−x1)=x1+u∗Δx0≤u≤1;y=y1+u∗(y2−y1)=y1+u∗Δy0≤u≤1.\begin{cases}x=x_1+u*(x2-x1)=x_1+u*\Delta x & 0\leq u \leq 1;\\y=y_1+u*(y2-y1)=y_1+u*\Delta y & 0\leq u \leq 1.\end{cases}{x=x1​+u∗(x2−x1)=x1​+u∗Δxy=y1​+u∗(y2−y1)=y1​+u∗Δy​0≤u≤1;0≤u≤1.​

    我们不妨先考虑下,在u为何值时,(x,y)(x,y)(x,y)位于裁剪窗口之内?我们设裁剪窗口的上边界为ymaxy_{max}ymax​,下边界为yminy_{min}ymin​,左边界为xminx_{min}xmin​,右边界为xmaxx_{max}xmax​,结合上式有:

{xmin≤x1+u∗Δx≤xmaxymin≤y1+u∗Δy≤ymax\begin{cases}x_{min}\leq x_1+u*\Delta x \leq x_{max}\\ y_{min}\leq y_1+u*\Delta y \leq y_{max}\end{cases}{xmin​≤x1​+u∗Δx≤xmax​ymin​≤y1​+u∗Δy≤ymax​​

可以看出当
{x1+u∗Δx=xminx1+u∗Δx=xmaxy1+u∗Δy=yminy1+u∗Δy=ymax\begin{cases}x_1+u*\Delta x=x_{min}\\ x_1+u*\Delta x=x_{max}\\y_1+u*\Delta y = y_{min}\\y_1+u*\Delta y = y_{max}\end{cases}⎩⎪⎪⎪⎨⎪⎪⎪⎧​x1​+u∗Δx=xmin​x1​+u∗Δx=xmax​y1​+u∗Δy=ymin​y1​+u∗Δy=ymax​​
时,为裁剪直线和四个边界的交点值,所以我们可以很轻松的算出四个对应的u值,此处不在赘述。

出入边的确定

上面我们只提到了不等式的四个特殊情况,不失一般性,这里我们写出不等式的所有情况:
{xmin≤x1+u∗Δx≤xmaxymin≤y1+u∗Δy≤ymax\begin{cases}x_{min}\leq x_1+u*\Delta x \leq x_{max}\\ y_{min}\leq y_1+u*\Delta y \leq y_{max}\end{cases}{xmin​≤x1​+u∗Δx≤xmax​ymin​≤y1​+u∗Δy≤ymax​​
可化简为:
{u∗(−Δx)≤x1−xminu∗Δx≤xmax−x1u∗(−Δy)≤y1−yminu∗Δy≤ymax−y1\begin{cases} u*(-\Delta x) \leq x_1 - x_{min}\\ u*\Delta x \leq x_{max} - x_1\\ u*(-\Delta y) \leq y_1 - y_{min}\\ u*\Delta y \leq y_{max} - y_1\\ \end{cases}⎩⎪⎪⎪⎨⎪⎪⎪⎧​u∗(−Δx)≤x1​−xmin​u∗Δx≤xmax​−x1​u∗(−Δy)≤y1​−ymin​u∗Δy≤ymax​−y1​​
上面四种情况可以归纳成

u∗pk≤qk,k=1,2,3,4u*p_k\leq q_k,k=1,2,3,4u∗pk​≤qk​,k=1,2,3,4

使用穷举法可知:

  • 当pk<0p_k<0pk​<0时,线段从裁剪边界延长线的外部延伸到内部,也就是入边
  • 当pk>0p_k>0pk​>0时,线段从裁剪边界延长线的内部延伸到外部,也就是出边

显见,当pk=0p_k=0pk​=0时,且qk<0q_k<0qk​<0,则线段完全在边界外;若qk≥0q_k\geq 0qk​≥0,则线段完全在边界内

代码实现

def Liang-Barsky(p_list, x_min, y_min, x_max, y_max):"""线段裁剪:param p_list: (list of list of int: [[x0, y0], [x1, y1]]) 线段的起点和终点坐标:param x_min: 裁剪窗口左上角x坐标:param y_min: 裁剪窗口左上角y坐标:param x_max: 裁剪窗口右下角x坐标:param y_max: 裁剪窗口右下角y坐标:return: (list of list of int: [[x_0, y_0], [x_1, y_1]]) 裁剪后线段的起点和终点坐标"""result = []if y_min > y_max:y_min, y_max = y_max, y_minx0, y0 = p_list[0]x1, y1 = p_list[1]p = [x0-x1, x1-x0, y0-y1, y1-y0]q = [x0-x_min, x_max-x0, y0-y_min, y_max-y0]u0, u1 = 0, 1for i in range(4):if p[i] < 0:u0 = max(u0, q[i]/p[i])elif p[i] > 0:u1 = min(u1, q[i]/p[i])elif (p[i] == 0 and q[i] < 0):result = [[0,0], [0,0]]return resultif u0 > u1:result = [[0,0], [0,0]]return resultif u0 > 0:res_x0 = int(x0 + u0*(x1-x0) + 0.5)res_y0 = int(y0 + u0*(y1-y0) + 0.5)if u1 < 1:res_x1 = int(x0 + u1*(x1-x0) + 0.5)res_y1 = int(y0 + u1*(y1-y0) + 0.5)result = [[res_x0, res_y0], [res_x1, res_y1]]return result

计算机小白也看得懂的Liang-Barsky算法相关推荐

  1. 小白一看就懂的前后端接口连接

    作为刚入职的小白,总是听前辈们说"连接口很简单的 ,一看就懂",由于鄙人实在是才疏学浅,实在是绕的头晕眼花,不知道怎么肥事.于是耐心用一下午仔细研究每一句代码,研究他们之间的联系, ...

  2. 小白都看得懂的使用Python生成随机验证码图片,以及后续优化方案

    环境:Anaconda3-2020.02 首先我们分解一下需要做什么: 生成随机的字母字符串 生成生成随机的背景色 生成随机的字体颜色 把随机的字符串用随机的颜色渲染,然后放到一块随机的背景色上面,基 ...

  3. Spring Framework框架起步,小白都看得懂(官翻版)!

    写在开头 本篇章介绍Spring框架的完整的全部技术.写这篇文章的目的是,一方面为了给初入后端开发的才子一篇入门指导,另一方面是为了自己对于基础知识的查阅. Spring不一定是最好的框架(虽然综合能 ...

  4. C语言--getchar()函数超详细解析(多维度分析,小白一看就懂!!!)

    目录 一.前言 二.什么是getchar()函数 三.getchar()函数的返回类型与机制 四.连续单个字符串 (代码演示) 五.getchar()函数其他用法,实战演练(重点) (1)按照题目写出 ...

  5. Modbus协议解析--小白一看就懂的协议

    文章目录 提问三连 1.什么是Modbus? 2.Modbus用来干什么? 3.Modbus的内容是什么? 3.1 Modbus-RTU+Modbus-ASCII 3.1.1 Modbus-RTU协议 ...

  6. 计算机的大小端存储模式(计算机小白必看!)

    目录 1.什么是大端小端 2.为什么会有大小端模式之分呢? 3.如何判断当前机器为大端字节序还是小端字节序 本文将介绍计算机存储数据时的大小端问题 1.什么是大端小端 大端(存储)模式,是指数据的低位 ...

  7. Arcgis: 利用xls文件绘制地图+细节参数调整(新手小白一看就懂)

    软件版本: 用到的地理数据库: 国家基础地理数据400万 常用链接: 地图底图(国家基础地理数据 / 在线底图 / BIGEMAP抠底图) 标准底图服务系统 全国地理信息资源目录服务系统 在线经纬度转 ...

  8. php - 超详细将 pdf 文档格式转换为图片格式,将 offce pdf 演示文稿转成图像 png / jpg(小白一看就懂的详细教程,附带完整示例源代码)

    效果图 其他教程都有点乱而且有bug,本文站在新手小白的角度比较靠谱,超详细的完整流程及详细注释代码. 本文实现了 php 将 pdf 文档转为图片(png / jpg),完整流程及示例源代码, 你可 ...

  9. 小白都看得懂的监督学习与无监督学习

    hello~一晃就十一月啦!开始写简书也半个月啦!之前对机器学习中的监督学习与无监督学习,只是有个概念,前几天学习知识的时候,又遇到了,所以打算好好记录下来. 在理解监督学习和无监督学习之前,我们先来 ...

  10. python类定义学生信息_Python学生信息管理系统(注释最详细,小白都看的懂)

    1 importos2 3 #学生系统基本功能 4 #增删查改 5 6 #如何实现该系统 7 #1.显示系统功能界面 8 #2.让用户选择功能 9 #3.判断用户选择的指定功能,然后完成相应的操作(增 ...

最新文章

  1. RONG出创新—2019年度春季学期“医工结合系列研讨会”圆满落幕
  2. OAM K8s 标准实现 Crossplane 项目进入 CNCF Sandbox
  3. Memcached 学习---(4)Memcached 连接
  4. 大数据如何助力农业发展
  5. 记一次远程协助的排错案例
  6. Spring Cloud Stream
  7. 抠图 php中文网,ps cs3怎么抠图
  8. 在推送Git之前合并多个提交[重复]
  9. SCI收录的文献类型与认证的文献类型
  10. www.etiger.vip DEVC++练习(入门)
  11. mysql 保留小数位数的一个方法
  12. 百度搜索引擎对站长越来越嚣张,已经放弃做什么百度优化咯
  13. 【listener hangs】监听hangs,导致新的连接无法连接数据库
  14. 计算机操作系统-文件管理
  15. vnpy 查询持仓量_vn.py 数据入库
  16. mysql实现postgres中pg_size_pretty函数
  17. 【商业信息】GB 11643—1999 公民身份号码
  18. 重做系统之后,如何配置java完整环境
  19. 窗口跑屏幕外面了怎么办
  20. Facebook速推帖子和Facebook广告有什么区别

热门文章

  1. 谷歌浏览器设置免跨域 Mac
  2. php性格属于哪类,狗狗性格分为6大类,你家是属哪一类?快来是看聪明型还是粘人型...
  3. 使用maven引用第三方jar包
  4. Encountered unexpected token:XXXXX
  5. 人间繁华江上明月,乃浮生一梦,惟真情长在——读沈君山《浮生再记》(并转书评)...
  6. PC机(笔记本)安装Linux系统
  7. python 对 PDF 的拆分 和合并
  8. 高德地图Amap绘制路线首尾相连问题
  9. php动态效果,jquery+php实现动态数字显示效果
  10. 使用Markdown进行计划安排(打钩)