理解Liang-Barsky裁剪算法的算法原理
0.补充知识
向量点积:结果等于0, 两向量垂直; 结果大于0, 两向量夹角小于90度; 结果小于0, 两向量夹角大于90度.
直线的参数方程:(x1, y1)和(x2, y2)两点确定的直线, 其参数方程为x = x1+u(x2-x2); y = y1+u(y2-y1)
1.前言
Liang-Barsky算法是 Cyrus-Beck 算法的特例, 我们先来简单的了解Cyrus-Beck算法, Cyrus-Beck算法本质是每次通过裁剪窗口(任意凸多边形, 文章最后会说明为什么凹多边形不行)的一条边界来确定待裁剪线段的哪部分应当被留下, 最后, 对所有应该被留下的部分取交集, 便可以求得线段应当留下的部分.举个例子, 假设多边形ABCDE, 那么我们每次使用一条边(AB, BC, …), 延长这条边和待裁剪的线段, 那么最后两条直线必定相交或平行, 如果相交, 根据交点确定哪部分被留下, 如果平行, 根据坐标确定哪部分被留下. 而Liang-Barsky算法只是将这个裁剪窗口固定为了一个平行于坐标轴的矩形, 所以Liang-Barsky算法和Cyrus-Beck算法本质是一样的, 只是Liang-Barskys算法因为拥有更多信息(裁剪窗口是一个平行与坐标轴的矩形), 可以对其中一些步骤进行简化处理.

2.对于一条边界, 具体如何确定线段应当留下的部分?

2.1符号说明
AB:边界直线, 把整个平面划分为两部分, 我们约定向量AH所在区域称为内部区域, 另一部分称为外部区域
AH:边界直线的法向量, AH=(1,0)
CD:待裁剪线段,C(x1, y1), D(x2, y2),CD的向量表示为 (x1+u(x2-x1), y1+u(y2-y1))(0<=u<=1)
E,F,G:待裁剪线段上三点
2.2判定方法
向量AH*向量AG, 结果大于0, H点处于内部区域
向量AH*向量AF, 结果等于于0, F点位于边界上
向量AH*向量AE, 结果小于0, E点处于外部区域
所以, 通过AX(X为线段CD上任意一点)与法向量AH的乘积即可判定X点位于内部区域还是外部区域
3.对于任意凸多边形边界, 如何确定线段应当留下的部分?
任意凸多边形边界和直线边界没有本质区别, 如果对于矩形上的所有边, 点X都满足属于这条边的内部区域, 那么X就在矩形的内部区域.(比如图中的IG部分)

4.Liang-Barsky的算法流程以及算法中的p和q
4.1算法流程

以AB边为例, X为CD上任意一点, 矩形边界的左右上下边界分别为XL, XR, YT, YB
因为向量AH*向量AX>=0时, X点在AB的内部区域
所以我们现在求解这个不等式:
向量AH*向量AX>=0
向量AH*(向量OX-向量OA)>=0;
由CD的向量表示式可知
(1,0)*(x1+u(x2-x1)-XL, y1+u(y2-y1)-YA)>=0;(我们不用关心YA的具体值, 请不要在此纠结)
x1+u(x2-x1)-XL>=0;
假设x2-x1>0(图中是大于0, 但是对于任意直线, 可能大于0, 小于0, 等于0)
则u>=(XL-x1)/(x2-x1)时, 点X在直线AB的内部区域
假设x1-x2<0
则u<=(XL-x1)/(X2-X1)时, 点X在直线AB的内部区域
如果x2-x1=0,则简单判断x1和XL的大小, 如果x1<XL, 舍去, 否则保留
本步执行完后, 我们得到一个关于u的不等式
同理对矩形另外三条边做如上处理, 我们得到另外3个不等式
我们现在观察一下这四个不等式
因为AB边和IJ边的法向量x坐标值为-1和1
那么如果AB边算出的不等式是u>=(XL-x1)/(x2-x1), 则IJ边算出来一定是u<=(XR-x1)/(x2-x1)(因为IJ边计算时仅仅是把XL换成XR, 1换成-1, 不理解请自己按照上述步骤计算一下), 我们可以发现, 互相平行的两条边算出来的不等式一个是>=那么另一个一定是<=(其实就是一维裁剪, 确定线段的上限和下限).
那么对4条边分别进行如上处理, 会得到u<=ans1, u<=ans2, u>=ans3, u>=ans4这4个不等式
ans1,ans2为u可能的上限, ans3,ans4为u可能的下限
又因为参数方程实际上是表示一条直线, 而我们需要裁剪的是一条线段, 所以u应当在0和1之间
于是
令umax = min(ans1, ans2, 1);//因为是取交集, 所以我们应在可能的上限中取最小的那个
umin = max(ans3, ans4, 0);
如果umax<umin则没有线段位于裁剪窗口的内部
否则将参数u带进参数方程, 求得裁剪之后线段的两个端点
最后利用端点画出裁剪结果即可
4.2算法中的p和q
L, R, T, B是对应边上的一点
(1,0)*(x1+u(x2-x1)-XL, YL) >=0;
(-1,0)*(x1+u(x2-x1)-XR, YR) >=0;
(0,1)*(XB, y1+u(y2-y1)-YB) >=0;
(0,-1)*(XT, y1+u(y2-y1)-YT) >=0;
令p1 = -(x2 - x1); p2 = -p1
p3 = -(y2 - y1); p4 = -p3
上面的不等式变为
x1+u*p2-XL>=0;
-x1+u*p1+XR>=0;
y1+u*p4-YB>=0;
-y1+u*p3+YT>=0;
移项
u*p2>=XL-x1;
u*p1>=x1-XR;
u*p4>=YB-y1;
u*p3>=y1-YT;
同时乘上-1(为了让不等式组看起来有序)
u*p1<=x1-XL;
u*p2<=XR-x1;
u*p3<=y1-YB;
u*p4<=YT-y1;
令q1 = x1-XL;
...
q4 = YT-y1;
假设p1<0, p3<0
u>=q1/p1
u>=q3/p3
u<=...
u<=...
不等式取交集即可得到u的范围, 可以看到p和q并没有明显的物理意义, 请不要纠结于此
5.Liang-Barsky的c++代码实现
void LiangBarsky(int x1, int y1, int x2, int y2, int XL, int XR, int YT, int YB)
{
int ansx1, ansx2, ansy1, ansy2;
//三种类型
//平行于y轴
)
{
if (x1<XL || x1>XR)
{
return;
}
else
{
int ymin = max(YB, min(y1, y2));
int ymax = min(YT, max(y1, y2));
if (ymin <= ymax)
{
ansx1 = ansx2 = x1;
ansy1 = ymin;
ansy2 = ymax;
}
else
{
return;
}
}
}
//平行于x轴
)
{
if (y1<YB || y1>YT)
{
return;
}
else
{
int xmin = max(XL, min(x1, x2));
int xmax = min(XR, max(x1, x2));
if (xmin <= xmax)
{
ansy1 = ansy2 = y1;
ansx1 = xmin;
ansx2 = xmax;
}
else
{
return;
}
}
}
//不平行于坐标轴
else
{
float p1, p2, p3, p4;
float q1, q2, q3, q4;
p1 = -(x2 - x1);
p2 = -p1;
p3 = -(y2 - y1);
p4 = -p3;
q1 = x1 - XL;
q2 = XR - x1;
q3 = y1 - YB;
q4 = YT - y1;
float u1, u2, u3, u4;
u1 = q1 / p1;
u2 = q2 / p2;
u3 = q3 / p3;
u4 = q4 / p4;
float umin, umax;
)
{
)
{
umin = max(, max(u1, u3));
umax = min(, min(u2, u4));
}
else
{
umin = max(, max(u1, u4));
umax = min(, min(u2, u3));
}
}
else
{
)
{
umin = max(, max(u2, u3));
umax = min(, min(u1, u4));
}
else
{
umin = max(, max(u2, u4));
umax = min(, min(u1, u3));
}
}
if (umin <= umax)
{
ansx1 = x1 + umin * (x2 - x1);
ansx2 = x1 + umax * (x2 - x1);
ansy1 = y1 + umin * (y2 - y1);
ansy2 = y1 + umax * (y2 - y1);
}
else
return;
}
//调用函数重绘直线
YourDrawFunc();
return;
}
6.教材上的算法流程和解题实例
相信有了上面的基础, 再回头看书上对于Liang-Barsky算法的讲解, 就不会一头雾水了.
相关内容在这篇博文中已经写的很清楚了, 故本文不在赘述.
[计算机图形学经典算法] Liang-Barsky(梁友栋-Barsky) 算法 (附Matlab代码): https://blog.csdn.net/soulmeetliang/article/details/79185603
7.从Liang-Barsky算法到Cyrus-Beck算法
7.1为什么凹多边形无法使用Cyrus-Beck算法?

因为凹多边形的边界不一定保证把平面区域分成多边形内部和外部两个区域
7.2Cyrus-Beck算法如何求得边界法向量?
Liang-Barsky算法因为裁剪窗口得特殊性, 每条边界得法向量我们作为已知量来处理. Cyrus-Beck中需要自己确定法向量, 思路如下: 根据边界(假定为AB)确定垂直于边界的法向量(a1, a2), 任取多边形除了本次边界上两点之外的任意一点P, 计算向量AP(BP)*a1, 大于0取a1, 否则取a2
7.3u的上下限对应关系
Liang-Barsky算法中, 我们知道平行的两条边一条提供上限则另一条提供下限. 对于更一般的凸多边形裁剪窗口, 则是与线段延长线相交的两条边界延长线对应的边界. 从不等式来看, xi+u*(xj-xi)中的(xj-xi)决定了得到u的上限还是下限, 可以据此实现上下限的区分.
8.参考资料
[计算机图形学经典算法] Liang-Barsky(梁友栋-Barsky) 算法 (附Matlab代码): https://blog.csdn.net/soulmeetliang/article/details/79185603
理解梁友栋-Barsky裁剪算法: https://blog.csdn.net/Daisy__Ben/article/details/51941608
梁友栋-Barsky算法原理: http://www.voidcn.com/article/p-niexnvwo-rv.html
理解Liang-Barsky裁剪算法的算法原理的更多相关文章
- 深入理解SVM,详解SMO算法
今天是机器学习专题第35篇文章,我们继续SVM模型的原理,今天我们来讲解的是SMO算法. 公式回顾 在之前的文章当中我们对硬间隔以及软间隔问题都进行了分析和公式推导,我们发现软间隔和硬间隔的形式非常接 ...
- C#常用8种排序算法实现以及原理简介
public static class SortExtention { #region 冒泡排序 /* * 已知一组无序数据a[1].a[2].--a[n],需将其按升序排列.首先比较a[1]与a[2 ...
- iOS高效裁剪图片圆角算法
项目有个需求:裁剪图片,针对头像,下面是要求: 大家可以看到这张图片的圆角已经去除,下面说说我在项目利用了两种方式实现此裁剪以及查看技术文档发现更高效裁剪方式,下面一一讲解:看下来大约需要15-20分 ...
- 强化学习策略梯度方法之: REINFORCE 算法(从原理到代码实现)
强化学习策略梯度方法之: REINFORCE 算法 (从原理到代码实现) 2018-04-01 15:15:42 最近在看policy gradient algorithm, 其中一种比较经典的 ...
- 深入理解java虚拟机【垃圾回收算法】
Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...
- 【机器学习】k-近邻算法以及算法实例
机器学习中常常要用到分类算法,在诸多的分类算法中有一种算法名为k-近邻算法,也称为kNN算法. 一.kNN算法的工作原理 二.适用情况 三.算法实例及讲解 ---1.收集数据 ---2.准备数据 -- ...
- 值得花费一周研究的算法 -- KMP算法(indexOf)
KMP算法是由三个科学家(kmp分别是他们名字的首字母)创造出来的一种字符串匹配算法. 所解决的问题: 求文本字符串text内寻找第一次出现字符串s的下标,若未出现返回-1. 例如 text : &q ...
- 最短路径算法-Dijkstra算法的应用之单词转换(词梯问题)(转)
一,问题描述 在英文单词表中,有一些单词非常相似,它们可以通过只变换一个字符而得到另一个单词.比如:hive-->five:wine-->line:line-->nine:nine- ...
- 重新想象 Windows 8 Store Apps (31) - 加密解密: 哈希算法, 对称算法
原文:重新想象 Windows 8 Store Apps (31) - 加密解密: 哈希算法, 对称算法 [源码下载] 重新想象 Windows 8 Store Apps (31) - 加密解密: 哈 ...
随机推荐
- 洗礼灵魂,修炼python(9)--灵性的字符串
python几大核心之——字符串 1.什么是字符串 其实前面说到数据类型时说过了,就是带有引号的参数,“”引号内的一切东西就是字符串,字符串又叫文本. 2.创建字符串的两种方式: 3.字符串的方法: ...
- 安装VisualSVN Server 报"Service 'VisualSVN Server' failed to start. Please check VisualSVN Server log in Event Viewer for more details"错误.原因是启动"VisualSVN Server"失败
安装VisualSVN Server 报"Service 'VisualSVN Server' failed to start. Please check VisualSVN Server ...
- UF清log
set rowcount 20000delete from UFSystem..ua_logset rowcount 0 truncate table ua_log_bak20111201 trunc ...
- python之字符串的常用操作(转)
1. 字符串的操作 字符串的连接操作 符号: + 格式:str1 + str2 例如:str1 = 'I Love' str2 = 'You!' print(str1 + str2) >> ...
- HTML 中点击<a>标签,页面跳转执行过程
HTML链接使用的是<a>标签 点击超链接,后台的执行大致如下: <a href="https://www.baidu.com">超链接</a> ...
- jQ 移动端返回顶部代码整理
//返回顶部 $('#btn-scroll').on('touchend',function(){ var T = $(window).scrollTop(); var t = setInterval ...
- 用requests爬取一个招聘网站
import requestsimport re session = requests.session()第一步:访问登陆页,拿到X_Anti_Forge_Token,X_Anti_Forge_Cod ...
- centos7下安装docker(12docker网络)
docker 网络荣覆盖范围可分为:单个host上的容器网络和跨多个host的网络 docker 安装时会自动在host上创建三个网络,我们可以使用docker network ls查看到 1.non ...
- 2257: [Jsoi2009]瓶子和燃料
题意:给你n个数字,然后让你选出k个,这k个数字进行任意组合,问得到的最小结果是多少? 数学知识: 分析:根据题意得出数学公式: 那么,如何在n个之中选出k个呢?其实不用选,因为直接计算各个因子,然后 ...
- JS进阶之---基本数据类型,引用类型,内存空间
一.内存空间: 为了便于理解,我们暂且先将Js的内存分为栈内存和堆内存. JavaScript具有垃圾自动回收机制,内存的分配与回收都完全实现了自动管理.所以我们在开发时一般会忽视内存空间的问题.但是 ...