扫描线算法完全解析

自从今年春天选修了计算机图形学课程,这朵乌云就在头顶盘旋不散。始终弄不明白计算机图形学到底在研究什么,所谓的Imaging、Modeling、Rendering和Animation各自又是什么意思。总觉得课上讲的实在太过抽象,实践的经历太少,到最后也不过是囫囵吞枣,不知其味。

我们如何在计算机程序中存储几何图形呢?比如多边形?最容易想到的方法就是保存多边形的顶点坐标。只要按顺序保存了多边形各个顶点的坐标,这个多边形就唯一确定了。另一方面,显示器是如何显示几何图形的呢?显示设备通常提供一个帧缓冲存储器(俗称显存),可以把它当做二维数组,该数组存储的值与屏幕上显示的每一像素的颜色一一对应。那么问题来了,如何把程序中的几何图形转换成显存中的几何图形?这就是扫描线算法的用途。

总结下来:扫描线算法把几何图形在计算机中的顶点表示法转换成点阵表示法。需要注意的是转换成点阵表示法后其实是对多边形进行了填充,而不是只有轮廓。

由于多边形千变万化,要想填充多边形内部的所有像素,需要找到一种合适的规则,能够沿着一个方向,一个像素不漏地把多边形内部填满,同时不污染多边形外部。于是我们发明了一条水平方向的扫描线,它从y=0开始,判断与多边形的交点,这些交点把扫描线分成了若干段,我们需要判断哪些段在多边形内部,哪些段在多边形外部,然后把内部的部分着色,完成后,令y=y+1,即扫描线上移一格,重复之前的操作,直到扫描线不再与多边形的任何部分相交。

举例说明,下图所示为多边形P1P2P3P4P5P6,而且同时画出了扫描线扫描过程中经过的四个位置y=1、y=2、y=6和y=7。

扫描线算法的难点在于如何判断扫描线被多边形分割后哪些部分在多边形内部,哪些部分在多边形外部。

让我们仔细观察上图,答案就在图中。对于未经过顶点的扫描线,如y=6,总是与多边形有偶数个交点,而且位于多边形内部的片段和位于多边形外部的片段交替存在。对于经过了顶点的扫描线,如y=1、y=2和y=7,与多边形的交点既可能是偶数,也可能是奇数。但是如果我们进一步划分,这些经过了顶点的扫描线有些经过了极值顶点,如y=1和y=7,它们的交点个数是奇数;而有些经过了非极值顶点,如y=2,它们的交点个数是偶数。这样的话,不如做一个特殊处理,把所有极值顶点当成两个点,就可以保证扫描线与多边形的交点总是偶数。

当然,把交点个数凑成偶数是有意义的,凑成偶数后就可以把这些交点从左到右两两配对,配对成功的两个点之间的像素全部着色。例如,上图的扫描线y=6与多边形的交点序列是ABCD,从左到右两两配对为AB和CD,然后将AB之间着色,CD之间着色。

基本思想就是这样,其实很容易理解。不过用代码实现起来并不那么容易,需要考虑很多细节。

首先需要提醒的是,扫描线算法的基本思想很简单,但不同的实现方式会有很大的效率差异。因此,如何设计数据结构及算法才能使扫描线算法以最快的速度完成,才是接下来我们需要面对的问题。

从以下几个方面考虑:

问题1:如何计算当前扫描线与多边形的交点?

直观做法:根据多边形的顶点求出各个边的方程,然后将扫描线的纵坐标代入方程求出横坐标,搞定!

遗憾的是,这需要对每条扫描线遍历所有边,性能肯定是吃不消的。我们需要寻找一种只遍历一次边的方法。同时,使用方程求交点会用到乘法或除法运算,对性能也是一种伤害。因此,我们提出了下面两个数据结构。

下面的代码定义了边表和活动边表。

//定义用于边表ET和活动边表AET的通用类EdgeclassEdge{public:intymax;floatx;floatdx;Edge*next;};//边表Edge*ET[windowHeight];//活动边表Edge*AET;利用这两个数据结构就很容易计算出每条扫描线与多边形的交点了。我们只需要令扫描线从下往上扫描,已知每条边的下端点x坐标和x,就可以使用增量法计算出这条边上所有点的x坐标。具体方法放到后面叙述。

问题2:如何解决前面提到的极值顶点按照两个处理的问题?

如果两条边相交,它们的交点就是一个顶点。事实上,这个点本来就是按照两个点处理的,因为它分别属于两条边。那么这个问题其实应该转换成:如何把非极值顶点按照一个处理?解决办法是把顶点处从上面断开,如下图所示。缺口在y坐标上的长度是1个像素,所以并不会产生不利影响。

在后面的代码实现中,我们会在建立边表ET时判断非极值顶点并对其做特殊处理,请稍加注意。

问题3:如何快速配对交点并着色?

活动边表AET中存储了所有与当前扫描线相交的边及其交点坐标。配对的工作就自然变得很简单,只需要遍历一遍AET即可。

解决了这三个问题,我们就可以给出下面的算法流程:

依照该流程,我在Linux下使用c++实现了这个算法。由于无法真正实现向帧缓冲存储器填色,因此代码中使用了OpenGL,但仅使用它画点。

完整代码如下。

这是一个Linux下的CMake工程,请首先安装依赖库

sudoaptinstallcmakesudoaptinstallfreeglut3-dev然后进入工程目录(将下面的换成你下载的目录位置),按照如下方式编译运行

cdmkdirbuildcdbuildcmake..make./PolygonScan即可看到效果。

扫描线算法是多边形扫描转换中的常用算法,它的特点是效率高,但算法较为复杂。本文给出了一个简单的扫描线算法,只是用作简单的示例。而对于实际情况,由于多边形的复杂性,比如自交多边形,即两条边具有顶点之外的交点,这种多边形无法使用扫描线算法,可能需要先拆分成若干个非自交多边形之后再处理。而且,简单的扫描线算法效果并不理想,从上面给出的三张效果图可以看出,边的锯齿状很严重,需要额外进行抗锯齿处理。

最后,由于作者本人也不是计算机图形学专业,文中不免有错误之处,请大家及时指出。

THE END
1.什么是算法?算法设计有哪些基本方法?算法基本设计方法算法设计中列举法的效率问题如何解决? 在算法设计中,列举法(也称为穷举法或枚举法)是一种通过逐一列举所有可能情况来解决问题的方法。然而,列举法的效率问题主要在于其计算复杂性通常随着问题规模的增加而指数级增长,这使得它在处理大规模问题时效率低下。 https://blog.csdn.net/m0_61505785/article/details/144050327
2.什么是算法?常见的算法分类有哪些?什么是算法?常见的算法分类有哪些?相关知识点: 试题来源: 解析 答:算法指解决问题的方法或步骤,是计算机科学的核心内容之一。其包括:输入、输出、有限性、明确性和有效性五个要素,通常使用程序语言来描述。常见的算法分类包括: 贪心算法:采取当前最优的选择,从而使最终结果尽可能接近最优解。 动态规划算法:将问题https://easylearn.baidu.com/edu-page/tiangong/questiondetail?id=1767773586707891229&fr=search
3.K.O.《算法导论》——寻找算法真正入门路径这本要被淹没了,因为它有点阳春白雪,理论高度比前几本要高出不少。可贵的是作者研究的理论,是真正的 算法专业的理论,而不是《算法导论》那样用那么多数学说事。 作者质疑「计算机科学」这个名字,提出CS是研究计算,而不是计算机,这个观点让我印象很深刻。 https://www.douban.com/note/795313909
4.真正统治世界的十大算法10. 随机数生成 现在我们还没有一个“真正的”随机数生成器,但我们已经有了一些伪随机数生成器,这够用了。随机数生成器的用途非常广泛,从互联联络、数据加密、安全哈希算法、电子游戏、人工智能、优化分析,到问题的初始条件、金融等等,都有它们 最后,我想强调一下,上面这个列表经供参考,它并不完整。因为在机器学习https://maimai.cn/article/detail?fid=395232582&efid=aRtcr75j-oVVPJXATXh9WQ
5.冯少辉:真正支配世界的十种算法直白地讲,算法是指一切经过明确定义的计算过程,其将某个或者某组值作为输入内容,并产生某个或者某组值作为输出结果。因此,算法代表的是一系列计算步骤,用于将输入转换为输出。——资源来源:Thomas H. Cormen 与 Chales E. Leiserson(2009年),《算法导论》第3版。 http://yunrun.com.cn/tech/5470.html
6.这一次,真正理解回溯算法其他这一次,真正理解回溯算法 理解“回溯算法” 若人生可重来,如何才能在岔路口做出最正确选择,让自己的人生“最优”? 贪心算法,在每次面对岔路口的时候,都做出看起来最优的选择,期望这一组选择可以使得我们的人生达到“最优”。但不一定能得到的是最优解。https://www.saoniuhuo.com/article/detail-33254.html
7.关于“信息茧房”,误解真相和破解可见,真正的算法推荐系统远比“喜欢看蛋糕推荐蛋糕”要复杂得多,也深入得多、智能得多。把锅甩给技术和算法从来都是最简单不费力的方法,只不过这样一来人们就会拒绝更深入的反思和改变。 美国明尼苏达大学计算机系专门进行了实验,让两组人同时在协同过滤算法推荐的平台上获取内容:一组人对推荐结果进行“跟随”,一组https://zhuanzhi.ai/document/ea4415761381e6950b21c3d07728dec4?from=doc_sim_rec
8.为什么要稳定币?算法稳定币有什么用途?币种百科区块链2、算法稳定币旨在提高价格行情稳定性,无需中央机构,而且是去中心化的。这一般根据对供应进行预编程以配对财产情况来完成。 一个“算法”稳定币要想真正成功,这需要四个基本功能: 1、加速——迅速拓展能力,而且仍然能够抵挡主要的市场震荡; 2、偿付能力——对稳定币的支持的认可和信心; https://www.jb51.net/blockchain/889920.html
9.Netflix的海量封面图是怎么设计出来的?960万张图只选一张AVA 系统:真正的算法筛图 尽可能多、尽可能丰富、尽可能符合规律的的封面图,能给 Netflix 带来最直接的转化,精心挑选封面图这个事情……工作量太大了。AVA 系统就是用来解决这个「大量的封面图从哪里来」的问题。 著名剧集《怪奇物语》一集有大约 86000 个静态帧,这意味着10集一季的剧集当中,可以筛出接近 900https://www.uisdc.com/netflix-ava
10.“网络平台算法治理”系列评算法本身中立,但算法的规则制定、模型设计、数据分析等并非完全客观;算法固然是商业秘密,但算法应用涉及的往往是社会公共利益,滥用算法危害的是千千万万消费者的合法权益。 要真正打破算法“黑箱”,需要健全算法定价机制和信息披露机制,提升平台算法逻辑、定价规则等的透明度。此外,要畅通消费者的举报途径,http://bj.news.cn/20241127/0edbbb3abc2e4e40a18981a029ee4e77/c.html
11.透视算法黑箱:数字平台的算法规制与信息推送异质性本研究借鉴实验和逆向工程方法,通过设置若干虚拟账号与数字平台进行长时间真实互动,以尝试真正进入算法的政治化空间,分析算法规制对用户信息获取异质性的影响。实证结果揭示了数字时代算法规制的高度复杂化、精细化和隐蔽化。从信息主题维度看,算法增加了个体获得https://mp.weixin.qq.com/s?__biz=MjM5OTgyMzIxNw==&mid=2649727718&idx=1&sn=3b38a41b115648efa60d9e3f39ea6cc7&chksm=bf2e90f8885919ee268f3ed985786467775399b55aa528bae23ffe57677fac2fa3828831d717&scene=27
12.2023考研英语同源外刊文章:算法可能永远不会真正弄明白人类6、entrench [?n?trent?] vt. 确立,牢固;用壕沟围住;挖掘 vi. 侵犯;挖掘壕沟 7、evict [v?kt] vt. 驱逐;逐出 综上是-2023考研英语同源外刊文章:算法可能永远不会真正弄明白人类,希望对备考2023考研的小伙们有所帮助!预祝考生2023考研凯旋归来!https://www.kyjxy.com/beikao1/yingyu/1143.html
13.图形图像算法中必须要了解的设计模式(1)腾讯云开发者社区真正的识别处理,进行ORI区域识别。 这些预处理算法的顺序不同,将对结果产生很大的影响。 下面我们将以图像的边缘提取算法为例演示整个处理过程,为简单起见,假设有两个预处理过程(灰度化、梯度化)和一个核心算法(二值化边缘提取)。有两种处理顺序,分别如下: https://cloud.tencent.com/developer/article/1165835
14.以质取胜范文12篇(全文)总体看, 这两则案例中教师都在尝试运用新理念指导课堂教学, 都能给学生独立思考的时间, 在教学过程中强调通过“算法多样化”来培养学生的发散性思维。但教师都未能真正理解“算法多样化”的内涵, 两节课均未真正落实“算法多样化”。 案例1是笔者上公开课时的一个片段。笔者尊重学生的想法, 让他们选择自己喜欢的算法https://www.99xueshu.com/w/ikeyan9azu96.html