区域填充的扫描线算法
贵州大学--实验三-多边形填充算法
![贵州大学--实验三-多边形填充算法](https://img.taocdn.com/s3/m/ffac49e2763231126fdb1149.png)
贵州大学实验报告学院:计算机科学与信息专业:软件工程班级:102班边界上的象素填充所遵循的规则为:“左闭右开”,“下闭上开”(将左边界和下边界的点算为内部,而将右边界和上边界算为外部)顶点:“上开下闭”。
几种特殊情况:1.扫描线交于一顶点,共享的两条边分另处于扫描线的两边,这时交点只取一个。
2.共享交点的两条边处于扫描线的上方,这时交点取二个。
3.共享交点的两条边处于扫描线的下方,这时交点取0个。
4.水平边在算法中不起任何作用,可不考虑。
活性边表(提高效率):为了减少求交的计算量,要利用一条边与相继的两条扫描线的交点的连贯性。
在处理一条扫描线时只对活性边(与它相交的多边形的边)进行求交运算。
把交点按x增加方向存在一个链表(活性边表)中。
活性边:与当前扫描线相交的边。
活性边表(AEL):按交点x的增量顺序存放在一个链表中,该链表称作活性边表(AEL)。
二、种子填充算法种子填充首先假定区域由封闭轮廓线围成,且轮廓线内某点是已知的,然后开始搜索与种子点相邻且位于轮廓线内的点。
如果这相邻点不在轮廓线内,则已达到轮廓线的边界;如果相邻点在轮廓线之内,则这相邻点成为新的种子点,继续搜索下去。
只适用于光栅扫描设备。
区域分类(区域采用边界定义,即区域边界上与边界外的象素取相同值,区域内部的点取不同值)1、四向连通区域:各象素在水平垂直四个方向是边通的。
即从区域内任一点出发,可水平/垂直移动到达区域内任一点。
实验结果运用扫描线算法进行多边形的填充时,截图显示如下:运用扫描线种子算法进行多边形的填充时,截图显示如下:(注:可编辑下载,若有不当之处,请指正,谢谢!)[文档可能无法思考全面,请浏览后下载,另外祝您生活愉快,工作顺利,万事如意!]。
c语言多边形区域填充算法
![c语言多边形区域填充算法](https://img.taocdn.com/s3/m/4ac7d40e2a160b4e767f5acfa1c7aa00b52a9d8d.png)
c语言多边形区域填充算法C语言多边形区域填充算法一、介绍多边形区域填充算法是计算机图形学中的一项重要技术,用于将给定的多边形区域进行填充,使其呈现出丰富的颜色或纹理,增强图形的效果和表现力。
本文将介绍一种常用的C语言多边形区域填充算法——扫描线填充算法。
二、扫描线填充算法原理扫描线填充算法是一种基于扫描线的填充方法,其基本思想是将多边形区域按照水平扫描线的顺序,从上到下逐行扫描,通过判断扫描线与多边形边界的交点个数来确定是否进入多边形区域。
具体步骤如下:1. 首先,确定多边形的边界,将其存储为一个边表。
边表中的每个边都包含起点和终点的坐标。
2. 创建一个活性边表(AET),用于存储当前扫描线与多边形边界的交点。
初始时,AET为空。
3. 从上到下逐行扫描多边形区域,对每一条扫描线,从边表中找出与该扫描线相交的边,并将其加入AET中。
4. 对于AET中的每一对交点,按照从左到右的顺序两两配对,形成水平线段,将其填充为指定的颜色或纹理。
5. 在扫描线的下一行,更新AET中的交点的坐标,然后重复步骤4,直到扫描到多边形区域的底部。
三、代码实现下面是一个简单的C语言实现扫描线填充算法的示例代码:```#include <stdio.h>#include <stdlib.h>#include <stdbool.h>typedef struct {int x;int y;} Point;typedef struct {int yMax;float x;float dx;int next;} Edge;void fillPolygon(int n, Point* points, int color) {// 获取多边形的边界int yMin = points[0].y;int yMax = points[0].y;for (int i = 1; i < n; i++) {if (points[i].y < yMin) {yMin = points[i].y;}if (points[i].y > yMax) {yMax = points[i].y;}}// 创建边表Edge* edges = (Edge*)malloc(sizeof(Edge) * n);int k = n - 1;for (int i = 0; i < n; i++) {if (points[i].y < points[k].y) {edges[i].yMax = points[k].y;edges[i].x = points[i].x;edges[i].dx = (float)(points[k].x - points[i].x) / (points[k].y - points[i].y);edges[i].next = k;} else {edges[i].yMax = points[i].y;edges[i].x = points[k].x;edges[i].dx = (float)(points[i].x - points[k].x) / (points[i].y - points[k].y);edges[i].next = i;}k = i;}// 扫描线填充for (int y = yMin; y < yMax; y++) {int xMin = INT_MAX;int xMax = INT_MIN;for (int i = 0; i < n; i++) {if (y >= edges[i].yMax) {continue;}edges[i].x += edges[i].dx;if (edges[i].x < xMin) {xMin = edges[i].x;}if (edges[i].x > xMax) {xMax = edges[i].x;}int j = edges[i].next;while (j != i) {edges[j].x += edges[j].dx; if (edges[j].x < xMin) {xMin = edges[j].x;}if (edges[j].x > xMax) {xMax = edges[j].x;}j = edges[j].next;}}for (int x = xMin; x < xMax; x++) { drawPixel(x, y, color);}}free(edges);}int main() {// 定义多边形的顶点坐标Point points[] = {{100, 100},{200, 200},{300, 150},{250, 100}};// 填充多边形区域为红色fillPolygon(4, points, RED);return 0;}```四、总结通过扫描线填充算法,我们可以实现对多边形区域的填充,从而提升图形的表现效果。
扫描线填充算法讲解
![扫描线填充算法讲解](https://img.taocdn.com/s3/m/77343b6225c52cc58bd6be50.png)
扫描线算法(Scan-Line F illing)扫描线算法适合对矢量图形进行区域填充,只需要直到多边形区域的几何位置,不需要指定种子点,适合计算机自动进行图形处理的场合使用,比如电脑游戏和三维CAD软件的渲染等等。
对矢量多边形区域填充,算法核心还是求交。
《计算几何与图形学有关的几种常用算法》一文给出了判断点与多边形关系的算法――扫描交点的奇偶数判断算法,利用此算法可以判断一个点是否在多边形内,也就是是否需要填充,但是实际工程中使用的填充算法都是只使用求交的思想,并不直接使用这种求交算法。
究其原因,除了算法效率问题之外,还存在一个光栅图形设备和矢量之间的转换问题。
比如某个点位于非常靠近边界的临界位置,用矢量算法判断这个点应该是在多边形内,但是光栅化后,这个点在光栅图形设备上看就有可能是在多边形外边(矢量点没有大小概念,光栅图形设备的点有大小概念),因此,适用于矢量图形的填充算法必须适应光栅图形设备。
2.1扫描线算法的基本思想扫描线填充算法的基本思想是:用水平扫描线从上到下(或从下到上)扫描由多条首尾相连的线段构成的多边形,每根扫描线与多边形的某些边产生一系列交点。
将这些交点按照x坐标排序,将排序后的点两两成对,作为线段的两个端点,以所填的颜色画水平直线。
多边形被扫描完毕后,颜色填充也就完成了。
扫描线填充算法也可以归纳为以下4个步骤:(1)求交,计算扫描线与多边形的交点(2)交点排序,对第2步得到的交点按照x值从小到大进行排序;(3)颜色填充,对排序后的交点两两组成一个水平线段,以画线段的方式进行颜色填充;(4)是否完成多边形扫描?如果是就结束算法,如果不是就改变扫描线,然后转第1步继续处理;整个算法的关键是第1步,需要用尽量少的计算量求出交点,还要考虑交点是线段端点的特殊情况,最后,交点的步进计算最好是整数,便于光栅设备输出显示。
对于每一条扫描线,如果每次都按照正常的线段求交算法进行计算,则计算量大,而且效率底下,如图(6)所示:图(6)多边形与扫描线示意图观察多边形与扫描线的交点情况,可以得到以下两个特点:(1)每次只有相关的几条边可能与扫描线有交点,不必对所有的边进行求交计算;(2)相邻的扫描线与同一直线段的交点存在步进关系,这个关系与直线段所在直线的斜率有关;第一个特点是显而易见的,为了减少计算量,扫描线算法需要维护一张由“活动边”组成的表,称为“活动边表(AET)”。
cad 区域填充的算法
![cad 区域填充的算法](https://img.taocdn.com/s3/m/18c8d99f6e1aff00bed5b9f3f90f76c660374c4f.png)
cad 区域填充的算法
CAD区域填充是一种用于计算机辅助设计软件中的算法,用于在指定区域内填充颜色。
这个算法基于扫描线填充方法,它从图形的顶部开始
扫描,逐行地将颜色填充到区域中。
具体而言,CAD区域填充算法可以通过以下步骤来实现:
1. 选择一个起始点,并确保该点位于待填充区域内。
2. 在当前扫描线上,从起始点开始向左和向右移动,找到左和右边界。
这可以通过检测不同颜色或图形边界来确定。
3. 填充当前扫描线的像素点,从左边界到右边界之间的像素。
4. 移动到下一行,通过向下移动一行并在新的扫描线上重复步骤2和
步骤3,直到所有行都被处理完毕或者遇到边界。
5. 当遇到边界或结束时,停止填充过程。
需要注意的是,在实际应用中,为了提高效率和减少计算量,可以使
用一些优化策略来加速CAD区域填充算法的执行,例如边界框剪裁和
扫描线段合并。
总之,CAD区域填充算法是一种实现图形填充的重要方法,它可以在计算机辅助设计软件中帮助用户快速填充指定区域并实现更好的可视化
效果。
计算机图形学扫描线种子填充算法
![计算机图形学扫描线种子填充算法](https://img.taocdn.com/s3/m/2f5cb3d050e2524de5187e49.png)
2.1 深度递归的种子填充算法
2.2 扫描线种子填充算法
2.1 深度递归的种子填充算法
种子填色又称边界填色(Boundary Filling)。 它的功能是,给出多边形光栅化后的边界位置及边 界色代码oundary_color,以及多边形内的一点(x, y)位置,要求将颜色fill_color填满多边形。
动画演示
扫描线种子填充算法特点
1. 该算法考虑了扫描线上象素的相关性,种子象 素不再代表一个孤立的象素,而是代表一个尚 未填充的区段。 2. 进栈时,只将每个区段选一个象素进栈(每个 区段最右边或最左边的象素),这样解决了堆 栈溢出的问题。 3. 种子出栈时,则填充整个区段。 4. 这样有机的结合:一边对尚未填充象素的登记 (象素进栈),一边进行填充(象素出栈), 既可以节省堆栈空间,又可以实施快速填充。
3. 已知有一个5边形如下。建立新边表 NET,并写出每一条扫描线经过时活性边 表AET中的数据状态。
X ΔX Ymax
第1项存当前扫描线与边的交点坐标x值; 第2项存从当前扫描线到下一条扫描线间x的增量Dx; 第3项存该边所交的最高扫描线号ymax; 第4项存指向下一条边的指针。
假定当前扫描线与多边形某一条边的交点的x 坐标为x,则下一条扫描线与该边的交点不要重计 算,只要加一个增量△x。(连贯性) 设该边的直线方程为:ax+by+c=0; 若y=yi,x=x i;则当y = y i+1时, x i+1=xi-b/a 其中ΔX= -b/a为常数, 另外使用增量法计算时,我们需要知道一条边 何时不再与下一条扫描线相交,以便及时把它从 活性边表中删除出去。
建立或调整AET(ActiveEdgeList);
区域填充算法
![区域填充算法](https://img.taocdn.com/s3/m/ed1ea940e45c3b3567ec8b7e.png)
7
9 9
9
对边界和内点表示的八连通区域的填充,只要将上述算法的对四 个像素点填充改为八个像素点即可。 四连通区域种子填充算法的缺点是有时不能通过狭窄区域区域, 因而不能填满多边形。八连通算法的缺点是有时会填出多边形的 边界。由于填不满比涂出更容易补救,因此四连通算法比八连通 算法用得更多。
(3)扫描线种子填充算法
(2)内点表示的四连通区域种子填充算法
基本思想:从多边形内部任一点(像素)出发,按照“右 上左下”的顺序判断相邻像素,若是区域内的像素,则对 其填充,并重复上述过程,直至所有像素填充完毕。 可以使用栈结构来实现该算法,种子像素入栈,档栈非空, 重复执行下面操作: 1)栈顶像素出栈; 2)将出栈像素置成多边形填充的颜色;
基本思想:从多边形内部任一点(像素)出发,按照 “右上左下”的顺序判断相邻像素,若不是边界像素 且没被填充过,则对其填充,并重复上述过程,直至 所有像素填充完毕。 可以使用栈结构来实现该算法,种子像素入栈,档栈 非空,重复执行下面操作: 1)栈顶像素出栈; 2)将出栈像素置成多边形填充的颜色; 3)按“右上左下”的顺序检查与出栈像素相邻的四个 像素,若其中某个像素不在边界上且未置成多边形色, 则把该像素入栈。
扫描线算法分析(举例分析)
基本思想:在任意不间断的区间中只取一个像素(不 间断区间指一条扫描线上的一组相邻元素),填充当 前扫描线上的该段区间,然后确定与这一段相邻的上 下两条扫描线位于区域内的区段,并依次把它们保存 起来,反复进行这个过程,指导所有保存的每个区段 都填充完毕。
(3)扫描线种子填充算法
种子像素入栈,当栈非空时,重复以下步骤: (1)栈顶像素出栈 (2)沿扫描线对出栈像素的左右像素进行填充, 直到遇到边界像素为止 (3)将上述区间内最左、最右像素记为xl 和xr (4)在区间[xl ,xr]中检查与当前扫描线相邻的上 下两条扫描线是否全为边界像素、或已填充 的像素,若为非边界、未填充的像素,则把 每一区间的最右像素取为种子像素入栈
扫描线填充算法讲解
![扫描线填充算法讲解](https://img.taocdn.com/s3/m/65e278aa376baf1ffc4fadc4.png)
扫描线算法(Scan-Line F illing)扫描线算法适合对矢量图形进行区域填充,只需要直到多边形区域的几何位置,不需要指定种子点,适合计算机自动进行图形处理的场合使用,比如电脑游戏和三维CAD软件的渲染等等。
对矢量多边形区域填充,算法核心还是求交。
《计算几何与图形学有关的几种常用算法》一文给出了判断点与多边形关系的算法――扫描交点的奇偶数判断算法,利用此算法可以判断一个点是否在多边形内,也就是是否需要填充,但是实际工程中使用的填充算法都是只使用求交的思想,并不直接使用这种求交算法。
究其原因,除了算法效率问题之外,还存在一个光栅图形设备和矢量之间的转换问题。
比如某个点位于非常靠近边界的临界位置,用矢量算法判断这个点应该是在多边形内,但是光栅化后,这个点在光栅图形设备上看就有可能是在多边形外边(矢量点没有大小概念,光栅图形设备的点有大小概念),因此,适用于矢量图形的填充算法必须适应光栅图形设备。
扫描线算法的基本思想扫描线填充算法的基本思想是:用水平扫描线从上到下(或从下到上)扫描由多条首尾相连的线段构成的多边形,每根扫描线与多边形的某些边产生一系列交点。
将这些交点按照x坐标排序,将排序后的点两两成对,作为线段的两个端点,以所填的颜色画水平直线。
多边形被扫描完毕后,颜色填充也就完成了。
扫描线填充算法也可以归纳为以下4个步骤:(1)求交,计算扫描线与多边形的交点(2)交点排序,对第2步得到的交点按照x值从小到大进行排序;(3)颜色填充,对排序后的交点两两组成一个水平线段,以画线段的方式进行颜色填充;(4)是否完成多边形扫描?如果是就结束算法,如果不是就改变扫描线,然后转第1步继续处理;整个算法的关键是第1步,需要用尽量少的计算量求出交点,还要考虑交点是线段端点的特殊情况,最后,交点的步进计算最好是整数,便于光栅设备输出显示。
对于每一条扫描线,如果每次都按照正常的线段求交算法进行计算,则计算量大,而且效率底下,如图(6)所示:图(6)多边形与扫描线示意图观察多边形与扫描线的交点情况,可以得到以下两个特点:(1)每次只有相关的几条边可能与扫描线有交点,不必对所有的边进行求交计算;(2)相邻的扫描线与同一直线段的交点存在步进关系,这个关系与直线段所在直线的斜率有关;第一个特点是显而易见的,为了减少计算量,扫描线算法需要维护一张由“活动边”组成的表,称为“活动边表(AET)”。
区域填充的扫描线算法
![区域填充的扫描线算法](https://img.taocdn.com/s3/m/84196e6b443610661ed9ad51f01dc281e53a56d1.png)
区域填充的扫描线算法区域填充是一种常见的计算机图形学算法,用于将一个封闭区域内的所有像素点填充为指定的颜色。
扫描线算法是区域填充的一种常用方法,本文将介绍扫描线算法的基本原理、实现步骤和一些优化技巧。
扫描线算法的基本原理是利用扫描线从图像的上边界向下扫描,检测每个扫描线与区域的交点。
当遇到一个交点时,根据该交点的左右两侧的交点情况,确定将该交点连接到哪个交点上。
通过不断地扫描和连接交点,最终将整个区域填充为指定的颜色。
下面是扫描线算法的具体实现步骤:1.首先需要确定区域的边界,可以由用户提供或通过其他算法生成。
边界可以用一系列的线段、多边形或曲线表示。
2. 创建一个数据结构来存储每个扫描线与区域的交点。
常用的数据结构是活性边表(Active Edge Table,AET)和扫描线填充表(Scanline Fill Table,SFT)。
AET用于存储当前扫描线与区域边界的交点,SFT用于存储所有扫描线的交点。
3.初始化扫描线的起始位置为图像的上边界,并创建一个空的AET。
4.开始扫描线的循环,直到扫描线到达图像的下边界。
每次循环都进行以下操作:-将扫描线与区域边界进行相交,找出所有与区域相交的线段,并将它们的交点加入到AET中。
-对AET按照交点的x坐标进行排序。
-从AET中取出相邻的两个交点,根据这两个交点之间的像素点是否在区域内来决定是否填充这些像素点。
5.当扫描线到达图像的下边界时,完成填充。
扫描线算法的实现可能会遇到一些边界情况和优化需求。
下面是一些常见的优化技巧:1.边界处理:在AET中存储的交点需要进行边界处理,确保交点处于图像范围内。
2.垂直线段处理:对于垂直线段,可以进行特殊处理,避免在AET中重复存储相同的交点。
3.区域内部边界处理:当区域内部有不连续的边界时,需要对交点进行合并,避免出现多余的像素点填充。
4.使用扫描线填充算法优化:对于大尺寸的区域填充,可以使用扫描线填充算法进行优化。
计算机图形学——区域填充算法(基本光栅图形算法)
![计算机图形学——区域填充算法(基本光栅图形算法)](https://img.taocdn.com/s3/m/b68a02fa18e8b8f67c1cfad6195f312b3169eb4f.png)
计算机图形学——区域填充算法(基本光栅图形算法)⼀、区域填充概念区域:指已经表⽰成点阵形式的填充图形,是象素的集合。
区域填充:将区域内的⼀点(常称【种⼦点】)赋予给定颜⾊,然后将这种颜⾊扩展到整个区域内的过程。
区域填充算法要求区域是连通的,因为只有在连通区域中,才可能将种⼦点的颜⾊扩展到区域内的其它点。
1、区域有两种表⽰形式1)内点表⽰:枚举出区域内部的所有象素,内部所有象素着同⼀个颜⾊,边界像素着与内部象素不同的颜⾊。
2)边界表⽰:枚举出区域外部的所有象素,边界上的所有象素着同⼀个颜⾊,内部像素着与边界象素不同的颜⾊。
21)四向连通区域:从区域上⼀点出发可通过【上、下、左、右】四个⽅向移动的组合,在不越出区域的前提下,到达区域内的任意象素。
2)⼋向连通区域:从区域上⼀点出发可通过【上、下、左、右、左上、右上、左下、右下】⼋个⽅向移动的组合,在不越出区域的前提下,到达区域内的任意象素。
⼆、简单种⼦填充算法给定区域G⼀种⼦点(x, y),⾸先判断该点是否是区域内的⼀点,如果是,则将该点填充为新的颜⾊,然后将该点周围的四个点(四连通)或⼋个点(⼋连通)作为新的种⼦点进⾏同样的处理,通过这种扩散完成对整个区域的填充。
这⾥给出⼀个四连通的种⼦填充算法(区域填充递归算法),使⽤【栈结构】来实现原理算法原理如下:种⼦像素⼊栈,当【栈⾮空】时重复如下三步:这⾥给出⼋连通的种⼦填充算法的代码:void flood_fill_8(int[] pixels, int x, int y, int old_color, int new_color){if(x<w&&x>0&&y<h&&y>0){if (pixels[y*w+x]==old_color){pixels[y*w+x]== new_color);flood_fill_8(pixels, x,y+1,old_color,new_color);flood_fill_8(pixels, x,y-1,old_color,new_color);flood_fill_8(pixels, x-1,y,old_color,new_color);flood_fill_8(pixels, x+1,y,old_color,new_color);flood_fill_8(pixels, x+1,y+1,old_color,new_color);flood_fill_8(pixels, x+1,y-1,old_color,new_color);flood_fill_8(pixels, x-1,y+1,old_color,new_color);flood_fill_8(pixels, x-1,y-1,old_color,new_color);}}}简单种⼦填充算法的不⾜a)有些像素会多次⼊栈,降低算法效率,栈结构占空间b)递归执⾏,算法简单,但效率不⾼,区域内每⼀像素都要进/出栈,费时费内存c)改进算法,减少递归次数,提⾼效率三、扫描线种⼦填充算法基本思想从给定的种⼦点开始,填充当前扫描线上种⼦点所在的⼀区段,然后确定与这⼀段相邻的上下两条扫描线上位于区域内的区段(需要填充的区间),从这些区间上各取⼀个种⼦点依次把它们存起来,作为下次填充的种⼦点。
扫描线区域填充算法
![扫描线区域填充算法](https://img.taocdn.com/s3/m/2ef17a0cdc36a32d7375a417866fb84ae45cc32d.png)
扫描线区域填充算法
扫描线区域填充算法,又称为"扫描线填涂算法",它用于对平面中特定区域填充指定的颜色、灰度或纹理,是计算机图形学中常用的算法之一。
该算法的原理是:给定待填充的区域内的点的有限个边界,从某一顶点开始,以某一规则遍历所有的边界点,形成边界数组,接着顺次扫描边界数组,将包含在边界中的每个合理像素点标记成已填充状态,由此而达到填充区域的目的。
算法步骤如下:
(1)设置起始点A,判断是否存在右方向上有没有边界点,若有,则把下一个边界点B作为起始点;
(2)从起始点A 开始,以扫描线的形式一次扫描边界点,把有效的像素点标记为“已填充”;
(3)把已扫描的点加入边界数组,直到下一个边界点C,且C点不等于起始点A;
(4)重复步骤(2)和(3),直至再回到起始点A,完成一次区域填充;
(5)如果还有未填充的区域,则重复步骤(1)至(4),直至所有区域填充完成。
实际应用中,为了避免停滞,可以采用八方向搜索策略;此外,由于扫描线填充算法中填充空间的范围是由边界点定义的,因此,当边界未经处理的是孤立的点或直线时,将无法实现实际的填充效果。
多边形的转换及区域填充
![多边形的转换及区域填充](https://img.taocdn.com/s3/m/4fa83d62bfd5b9f3f90f76c66137ee06eef94e45.png)
弧长法(累计角度法) 步骤 从v点向多边形P各顶点发出射线,形成有向角 计算有向角的和,得出结论
逐点判断算法-小结
逐点判断的算法虽然程序简单,但不可取。原因是速度太慢,效率低。 主要是由于该算法割断了各象素之间的联系,孤立地考察各象素与多边形的内外关系,使得几十万甚至几百万个象素都要一一判别,每次判别又要多次求交点,需要做大量的乘除运算,花费很多时间。
扫描线算法-数据结构
扫描线算法-数据结构
(扫描线6的活性边表 ) AET (扫描线7的活性边表) AET
பைடு நூலகம்
单击此处可添加副标题
如何计算下一条扫描线与边的交点? 直线方程:ax+by+c = 0 当前交点坐标:(xi, yi) 下一交点坐标:(xi+1,yi+1) xi+1= ((-byi+1)-c)/a = (-b(yi+1)-c)/a =xi-b/a xi+1=xi+Δx(Δx=-b/a为常数 ) 活动边表中需要存放的信息 x:当前扫描线与边的交点 Δx=-b/a:从当前扫描线到下一条扫描线之间的x增量 ymax:边所交的最高扫描线,即边的上端点的y坐标;
扫描线的连贯性
交点个数为偶数。 交点之间的区段按交替的顺序依次出现在多边形内部和外部。 以上性质称为扫描线的连贯性,它是多边形区域连贯性在一条扫描线上的反映。
由扫描线y=e和多边形的所有交点递推出扫描线y=d=e+1与多边形各边的交点。 边的连贯性,它是区域的连贯性在相邻两扫描线上的反映。
扫描线
扫描线算法-数据结构
扫描线算法-数据结构
为了方便边的活性边表(AET)的更新,建立另一个表,即边表(ET----Edge Table) 边表中需要存放的信息 x: 扫描线与该边的初始交点,即边的下端点的x坐标 Δx:x的增量 ymax:该边的最大y值,即边的上端点的y坐标; 边表ET是按边的下端点的y坐标对非水平边进行分类的指针数组。下端点的y坐标的值等于i的边归入第i类。同一类中,各边按x值(x值相等时,按Δx的值)递增的顺序排列成行。
计算机图形学-区域填充的扫描线算法
![计算机图形学-区域填充的扫描线算法](https://img.taocdn.com/s3/m/ea951c7eaf1ffc4ffe47acc7.png)
计算机图形学——区域填充的扫描线算法一.实验名称:区域填充的扫描线算法二.实验目的:1、理解区域填充扫描线算法的原理;2、实现区域填充的扫描线算法并测试;三.算法原理:算法基本思想: 首先填充种子点所在扫描线上位于区域内的区段,然后确定与该区段相邻的上下两条扫描线上位于区域内的区段,并依次将各区段的起始位置保存, 这些区段分别被用区域边界色显示的像素点所包围。
随后,逐步取出一开始点并重复上述过程,直到所保存各区段都填充完毕为止。
借助于栈结构,区域填充的扫描线算法之步骤如下:Step 1. 初始化种子点栈:置种子点栈为空栈,并将给定的种子点入栈;Step 2. 出栈:若种子点栈为空,算法结束;否则,取栈顶元素(x,y)为种子点;Step 3. 区段填充:从种子点(x, y) 开始沿纵坐标为y 的当前扫描线向左右两个方向逐像素点进行填色,其颜色值置为newcolor 直至到达区域边界。
分别以xl 和xr 表示该填充区段两端点的横坐标;Step 4. 新种子点入栈: 分别确定当前扫描线上、下相邻的两条扫描线上位于区段[xl, xr] 内的区域内的区段。
若这些区段内的像素点颜色值为newolor ,则转至Step 2;否则以区段的右端点为种子点入种子点栈,再转至Step 2。
四.原程序代码:/*****************************************//*4-ScanLineFill 区域填充的扫描线算法实现*//*****************************************/#include <stdio.h>#include <conio.h>#include <graphics.h>#include <malloc.h>#define Stack_Size 100 //栈的大小常量//定义结构体,记录种子点typedef struct{int x;int y;}Seed;//定义顺序栈(种子点)typedef struct{Seed Point[Stack_Size];int top;}SeqStack;//初始化栈操作void InitStack(SeqStack *&S){S=(SeqStack *)malloc(sizeof(SeqStack));S->top=-1;}//种子点栈置空;void setstackempty (SeqStack *S){S->top==-1;}//种子点栈状态检测函数int isstackempty (SeqStack *S){if(S->top==-1)return true; //空栈返回trueelsereturn false; //非空栈返回false}//种子点入栈;int stackpush (SeqStack *&S,Seed point){if(S->top==Stack_Size-1)//栈已满,返回false return false;S->top++;//栈未满,栈顶元素加1S->Point[S->top]= point;return true;}//取栈顶元素;int stackpop (SeqStack *&S,Seed &point){if(S->top==-1)//栈为空,返回falsereturn false;point=S->Point[S->top];S->top --;//栈未空,top减1return true;}//画圆void CirclePoints (int xc, int yc, int x, int y, int Color) {putpixel (xc + x, yc + y, Color);putpixel (xc + x, yc - y, Color);putpixel (xc - x, yc + y, Color);putpixel (xc - x, yc - y, Color);putpixel (xc + y, yc + x, Color);putpixel (xc + y, yc - x, Color);putpixel (xc - y, yc + x, Color);putpixel (xc - y, yc - x, Color); }//中点画圆算法void MidpointCircle(int radius, int Color) {int x, y;float d;x=0;y=radius;d=5.0/4-radius;CirclePoints(250,250,x,y,Color);while(x<y){if (d<0){d+=x*2.0+3;}else{d+=(x-y)*2.0+5;y--;}x++;CirclePoints(250,250,x,y,Color);}}//四连通扫描线算法void ScanLineFill4(int x, int y, int oldcolor, int newcolor) {int xl, xr, i;bool SpanNeedFill;Seed pt;//种子点SeqStack *S;//定义顺序栈InitStack(S);//定义了栈之后必须把栈先初始化setstackempty(S);//种子点栈置空;pt.x = x;pt.y = y;stackpush (S,pt); // 种子点(x, y)入栈while (!isstackempty(S)){stackpop (S,pt);//取种子点y = pt.y;x = pt.x;while (getpixel (x,y)==oldcolor) {// 从种子点开始向右填充putpixel (x, y, newcolor);x++;}xr = x -1;x = pt.x -1;while (getpixel (x,y)==oldcolor) { // 从种子点开始向左填充putpixel (x, y, newcolor);x--;}xl = x + 1;x = xl;y = y +1; // 处理上面一条扫描线while (x < xr){SpanNeedFill = false;while (getpixel (x, y)==oldcolor){SpanNeedFill = true;x++ ;} // 待填充区段搜索完毕if (SpanNeedFill){// 将右端点作为种子点入栈pt.x = x - 1;pt.y = y;stackpush (S,pt);SpanNeedFill = false;} //继续向右检查以防遗漏while ((getpixel (x, y)!=oldcolor) && (x< xr)) x++;} //上一条扫描线上检查完毕x = xl;y=y-2; // 处理下面一条扫描线while (x < xr){SpanNeedFill = false;while (getpixel (x, y)==oldcolor){SpanNeedFill=true;x++ ;}if (SpanNeedFill){pt.x= x - 1;pt.y = y;stackpush (S,pt);SpanNeedFill=false;}while ((getpixel (x, y)!=oldcolor) && (x < xr))x++;}}}//主函数检测void main(){int radius,color;int x,y;//种子点int oldcolor,newcolor;//原色与填充色//输入参数值printf("input radius and color:\n");//画圆参数scanf("%d,%d",&radius,&color);printf("input x and y:\n"); //读入内点scanf("%d,%d", &x, &y);printf("input oldcolor and newcolor:\n"); //读入原色与填充色scanf("%d,%d", &oldcolor, &newcolor);int gdriver = DETECT,gmode;initgraph(&gdriver, &gmode, "c:\\tc");// 用背景色清空屏幕cleardevice();// 设置绘图色为红色setcolor(RED);MidpointCircle(radius,color);//用中点画圆算法画圆rectangle(150, 150, 350, 350);//再画一个矩形区域ScanLineFill4 (x,y,oldcolor,newcolor);//扫描线区域填充getch();closegraph();}五.运行结果与讨论:测试结果1:测试结果2:六.实验分析与讨论:1.通过借助栈这一数据结构,完成了区域填充的扫描线算法的实现,并利用以前所学的画圆等算法,进行综合运用,在此基础上进行扩充,设计多种图案,进行扫描线填充算法的检测,都得到了理想的结果,体现了算法的有效性;2.栈的数据结构给种子点的操作带来了极大的方便,为算法的实现提供了便利,同时还提高了算法的复用性和可靠性;3.此扫描线填充算法能够对多种图案进行填充,展现了算法的实用性。
区域填充算法
![区域填充算法](https://img.taocdn.com/s3/m/06d7b2ac18e8b8f67c1cfad6195f312b3169ebc9.png)
3、基于曲线积分的区域填充算法
• 算法的实现: ➢对一个区域进行轮廓跟踪,求出区域的边
• 改进算法的基本思想是:每找到一个新的内部
区段时,不仅将新区段的y值(yn)和左右列值xnl, xnr压入堆栈,而且同时把当前区段的y值和左右 列值xl,xr也压入堆栈,以保存和传递有关的信息。
3、基于曲线积分的区域填充算法
基于曲线积分的区域填充算法是邓国强,孙 景鳌等(2001)提出的一种以格林公式求区域面 积为基本原理进行区域填充的特殊算法。
1、递归种子填充算法
递归种子填充算法,又称边界填色算 法。
算法的原理是:让单个像元作为填充 胚,在给定的区域范围内,通过某种方法 进行蔓延,最终填充满整个多边形区域。 为了实现填充胚的蔓延,可采用四邻法或 八邻法进行填充。
2、扫描线种子填充算法
(1)扫描线种子填充算法
扫描线种子填充算法的对象是一个个扫描 线段。扫描线段是指区域内同值相邻像素 在水平方向的组合,它的两端以具有边界 值的像素为边界,即一段扫描线段的中间 只有同一种像素。
(2)计算多边形面积
4、区域填充算法在地图制图中的应用
(2)计算多边形面积
Sa
24
1 5 2
1 13 33 2
Sb
30
1 2
5
1 2
17
41
ScΒιβλιοθήκη 1031 213
1 2
17
实验三区域填充扫描线算法
![实验三区域填充扫描线算法](https://img.taocdn.com/s3/m/20debd632e60ddccda38376baf1ffc4ffe47e281.png)
实验三区域填充扫描线算法区域填充扫描线算法是一种计算机图形学算法,用于实现区域填充功能。
该算法通过扫描像素的方式,检测封闭区域内的每一条扫描线与区域边界的交点,并根据交点之间的像素颜色进行填充。
算法步骤如下:1.扫描线从画布的最底部开始,逐行向上移动。
2.检测扫描线与区域边界的交点,并记录交点的x坐标。
3.对于每对相邻的交点(称为活动边),按照交点的x坐标从左到右进行遍历。
4.遍历过程中,判断当前像素是否在封闭区域内。
如果在区域内,根据填充颜色进行颜色填充。
5.对于扫描线上的下一条扫描线,根据当前扫描线的活动边情况,更新活动边,即将下一条扫描线上的新交点加入到活动边中。
区域填充扫描线算法的优点在于其适用于任意形状的封闭区域,并且可以处理带有内部孔洞的区域。
相比其他填充算法,如扫描线填充算法,区域填充扫描线算法具有更好的效率和性能。
然而,区域填充扫描线算法也存在一些限制和问题。
首先,该算法要求区域边界是封闭的,并且必须采用逆时针顺序来定义区域内的边界。
其次,算法的实现和性能受到硬件设备的限制,特别是在处理较大尺寸的区域时可能出现性能问题。
为了解决这些问题,可以采用一些优化方法来改进算法的性能。
例如,可以使用空间填充曲线(Space Filling Curves)来加速扫描线的遍历过程。
还可以使用并行计算技术来加速算法的执行,特别是在处理大尺寸区域时。
总之,区域填充扫描线算法是一种常用的图形学算法,用于实现区域填充功能。
虽然具有一些限制和问题,但可以通过一些优化方法来改进算法的效率和性能,满足实际应用的需求。
扫描线算法
![扫描线算法](https://img.taocdn.com/s3/m/a4fc303331126edb6f1a10f0.png)
一、扫描线算法基本思想按扫描线顺序,计算扫描线与多边形的相交区间,再用要求的颜色显示这些区间的象素,即完成填充工作。
对于一条扫描线填充过程可以分为四个步骤:(1) 求交:计算扫描线与多边形各边的交点(2) 排序:把所有交点按x 坐标递增顺序来排序(3) 配对:确定扫描线与多边形的相交区间,第一个与第二个,第三个与第四个等等,每对交点代表扫描线与多边形的一个相交区间(4) 填充:显示相交区间的象素存在问题1:当扫描线与多边形顶点相交时,交点的取舍问题解决方法:当扫描线与多边形的顶点相交时,若共享顶点的两条边分别落在扫描线的两边,交点只算一个;若共享顶点的两条边在扫描线的同一边,这时交点作为零个或两个,取决于该点是多边形的局部最高点或局部最低点。
具体实现:只需检查顶点的两条边的另外两个端点的y值,按这两个y值中大于交点y 值的个数是0,1,2 来决定。
存在问题2:多边形边界上象素的取舍解决方法:规定右/上边界的象素不予填充;左/下边界的象素予以填充。
具体实现:对扫描线与多边形的相交区间取左闭右开。
算法的实现求交一条扫描线往往只和少数几条边相交。
与当前扫描线相交的边称为活性边,把它们按与扫描线交点x 坐标递增的顺序存入一个链表中,称为活性边表( AET, Active Edge Table)由边的连贯性(当某条边与当前扫描线相交时,它很可能也与下一条扫描线相交)和扫描线的连贯性(当前扫描线与各边的交点顺序,与下一条扫描线与各边的交点顺序很可能相同或类似),只需对当前扫描线的活性边表作更新,即可得到下一条扫描线的活性边表。
计算下一条扫描线与边的交点设直线方程:a x + b y + c = 0,当前交点坐标:(xi , yi),下一交点坐标:(xi+1,yi+1)xi+1=((-b yi+1)-c)/a = ((-b yi+1)-c)/a = xi-b/a 增量为-b/a故在活性边表中需要存放的信息: x :当前扫描线与边的交点△x = -b /a :从当前扫描线到下一条扫描线之间的 x 增量 ymax :该边所交的最高扫描线P PA BCD△x y maxP P P P P PFGP 4P 5P 3P 4上图为扫描线 6 的活性边表 左图为扫描线 7 的活性边表 活性边表的更新为方便活性边表的更新,建立另一个表。
压入新、旧区段的区域填充扫描线算法
![压入新、旧区段的区域填充扫描线算法](https://img.taocdn.com/s3/m/0c1976c9d5bbfd0a795673ef.png)
压入新 、 旧区段的区域填充扫描线算法
降爱莲 谢 克 明
( 太原理 工 大 学计 算机 与软件 学院 , 太原 0 0 2 ) 3 0 4
E m i alni g 8@sh . r — a :iaj n 6 5 oucn l i a o
摘
要
指 出压入 区段 端 点 的 区域 填 充扫 描 线 算 法对 一 类 特 殊 4 连 通 区域 有 可 能 产 生 漏 填 . 用像 素 间 的相 关性 和 区 一 利
K y o d :a afl g 4 ajcn o nc o ,- i co —x a dn to , a , ak e w rs r ln ,- daetcn et n 4 dr t n ep n igme d s n s c e ii i ei h p t
区 域填 充是 指 用 某 种 颜 色或 图案 来 填 充 一个 有 界 区域 。 种
域 在 扫 描 线上 的连 贯 性 提 出 了采 用“ 写 区段 左 端 点 ” 4向 填 充 方法 进 行 改 进 : 过 分 析 原 算 法 中 仍 然 存 在 的 像 素 点 重 的 通 颜 色判 读 的 重 复操 作 , 出 了压 入 新 、 区段 的 区域 填 充扫 描 线 算 法 并 给 出算 法 的描 述 ; 型 的填 充 测 试 证 明 了本 算 法 提 旧 典
l 算法 l中的漏填 现 象
压 人 区 段 端 点 的 区 域 填 充 扫 描 线 算 法 ( 法 1 可 描 述 为 算 ) 如 下 几个 步骤 : 步骤 1( 找种子点所 在 区段 ) 给定 的种子点 ( , 出 寻 从 , ) ,
子 填 充算 法 要 求 区域 是 连通 的 只有 在 连 通 的 区 域 中 , 有 可 才
扫描线区域填充算法
![扫描线区域填充算法](https://img.taocdn.com/s3/m/217d499a81eb6294dd88d0d233d4b14e85243ee9.png)
扫描线区域填充算法算法步骤如下:1.找到图形区域的上下边界:-遍历图形的所有边界点,找到最大纵坐标和最小纵坐标,确定扫描线的上下边界。
2.初始化扫描线列表:-从上到下依次生成扫描线,建立一个扫描线列表。
3.计算扫描线与图形的交点:-遍历扫描线列表中的每个扫描线,与图形的所有边界进行求交。
-如果与边界有交点,将交点的横坐标存入一个集合中,集合中的数据按从小到大排序。
4.进行填充:-遍历扫描线列表中的每个扫描线,找到对应的交点集合。
-将集合中的每两个横坐标之间的像素点进行填充。
以下是对算法的详细解释:首先,我们需要遍历所有边界点,找到最大纵坐标和最小纵坐标。
这样就确定了我们需要扫描的区域范围,也就是扫描线的上下边界。
接下来,我们生成一个扫描线列表。
从上到下依次生成每一条扫描线,将其存储在扫描线列表中。
然后,对于每一条扫描线,我们需要计算该扫描线与图形的交点。
我们遍历图形的所有边界,并与当前扫描线进行求交。
如果与边界有交点,我们将交点的横坐标存入一个集合中。
这个集合中的数据按从小到大排序,以便后续的填充操作。
最后,我们对于每一条扫描线,找到对应的交点集合。
我们遍历集合中的每两个横坐标之间的像素点,将其进行填充。
这可以通过修改像素的颜色或设置像素的属性来实现。
总结一下,扫描线区域填充算法通过逐行扫描图形区域,计算每行与区域内部的交点,然后进行填充。
该算法的优点是简单、高效,适用于填充简单凸多边形等闭合图形。
然而,该算法对于非凸多边形或包含内孔的图形表现较差,可能需要额外的处理逻辑。
扫描线区域填充算法
![扫描线区域填充算法](https://img.taocdn.com/s3/m/b1d2e0b90342a8956bec0975f46527d3250ca611.png)
扫描线区域填充算法算法步骤如下:1.首先需要定义一个边表(ET)和活动边表(AET)。
-边表是存储多边形所有边的一张表格,将每条边的y坐标、x坐标以及斜率存储起来。
-活动边表是指当前扫描线与多边形边的交点,它是一个按照x坐标排列的列表。
2.初始化边表(ET)和活动边表(AET)。
-通过遍历多边形的边,将边表中存储对应的边信息。
-初始时活动边表为空。
3.根据多边形的顶点,将边添加到边表中。
-对于每条边,计算出其斜率,以及y坐标的最小值和最大值。
4.进行扫描线填充:a.设置当前扫描线的y坐标,从最小的y值开始,逐行向下扫描。
b.遍历边表,将与当前扫描线相交的边添加到活动边表中。
c.按照x坐标对活动边表进行排序。
d.遍历活动边表,两两配对,填充对应的像素点。
e.过滤掉扫描线下方的边。
f.更新活动边表,将不再与当前扫描线相交的边从活动边表中删除。
5.重复步骤4,直到扫描完整个区域。
然而,扫描线区域填充算法也存在一些局限性和问题:-对于包含小尺寸多边形的大区域填充,算法的迭代次数会增加,导致填充时间变长。
-在多边形内有重叠区域时,算法无法区分内外部,可能导致填充错误。
-当多边形内有孔洞时,算法无法正确填充孔洞。
为了解决以上问题,可以采用一些优化策略来改进算法性能和填充效果。
例如,可以使用边表索引和活动边表的双向链表结构,减少查找和插入操作的时间开销。
此外,还可以使用扫描线的上下两根线段来同时填充两个相邻区域,提高填充速度。
总结起来,扫描线区域填充算法是一种常用且有效的图形填充算法,通过逐行扫描和交点判断来填充封闭区域。
它可以广泛应用于计算机图形学领域,如图形渲染、图像处理等。
算法在实际应用中需根据具体场景进行优化和改进,以满足不同需求。
区域填充算法区域填充算法
![区域填充算法区域填充算法](https://img.taocdn.com/s3/m/9d7515d1dc88d0d233d4b14e852458fb770b38b2.png)
区域填充算法区域填充算法
下面将介绍两种常见的区域填充算法:扫描线填充算法和种子填充算法。
1. 扫描线填充算法(Scanline Fill Algorithm):
-扫描线填充算法基于扫描线的原理,从图像的上方向下扫描,对每条扫描线上的像素进行填充。
-算法流程如下:
-选择一个初始扫描线,例如选择图像的最上面一条扫描线;
-遍历该扫描线上的每一个像素,判断是否需要填充该像素;
-如果需要填充,则向区域内部延伸扫描线,同时判断该扫描线上的相邻像素是否需要填充;
-一直延伸扫描线,直到整个区域被填充完毕。
-扫描线填充算法的优点是简单、易于实现,但是算法的效率较低,在处理大尺寸区域时耗时较长。
2. 种子填充算法(Seed Fill Algorithm):
-种子填充算法基于种子点的概念,选择一个起始点作为种子点,然后根据预设的填充规则进行填充。
-算法流程如下:
-选择一个起始点作为种子点,将该点填充上颜色;
-判断该种子点的相邻像素是否需要填充,如果需要则将其填充;
-一直延伸填充,直到整个区域被填充完毕。
-种子填充算法的优点是效率较高,能够处理较大的区域,但是需要选择合适的填充规则,否则可能会导致填充区域不准确或者出现漏填的情况。
以上两种区域填充算法在实际应用中会根据具体的场景和需求选择合适的算法进行使用。
在实际实现时,还需要考虑一些特殊情况,如图像边界处理、扫描顺序等,以确保算法的正确性和效率。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
计算机图形学——区域填充的扫描线算法NORTHWESTUNIVER SITY一、实验目的1.通过实验,进一步理解和掌握几种常用多边形填充算法的基本原理2.掌握多边形区域填充算法的基本过程3.掌握在C/C++环境下用多边形填充算法编程实现指定多边形的填充。
4.利用TC2.0编写区域填充的扫描线算法。
二、实验内容算法基本思想:首先填充种子点所在扫描线上位于区域内的区段,然后确定与该区段相邻的上下两条扫描线上位于区域内的区段,并依次将各区段的起始位置保存, 这些区段分别被用区域边界色显示的像素点所包围。
随后,逐步取出一开始点并重复上述过程,直到所保存各区段都填充完毕为止。
算法描述:扫描线填充算法一般包括四个步骤:求交、排序、交点配对、区域填充。
正确求得扫描线与区域填内外轮廓线的交点是算法成败的关键问题。
另一方面,采用合适的数据结构又可以简化操作、提高算法的效率。
本论文由于采用链表结构记录轮廓线和交点,无需焦点排序的过程,因而提高了算法效率。
扫描线来源于光栅显示器的显示原理:对于屏幕上所有待显示像素的信息,将这些信息按从上到下、自左至右的方式显示。
扫描线多边形区域填充算法是按扫描线顺序,计算扫描线与多边形的相交区间,再用要求的颜色显示这些区间的象素,即完成填充工作。
区间的端点可以通过计算扫描线与多边形边界线的交点获得。
对于一条扫描线,多边形的填充过程可以分为四个步骤:(1)求交:计算扫描线与多边形各边的交点;(2)排序:把所有交点按x值递增顺序排序;(3)配对:第一个与第二个,第三个与第四个等等;每对交点代表扫描线与多边形的一个相交区间;(4)填色:把相交区间内的象素置成多边形颜色;三、实验原理扫描线填充算法的基本过程如下:当给定种子点(x,y)时,首先填充种子点所在扫描线上的位于给定区域的一个区段,然后确定与这一区段相连通的上、下两条扫描线上位于给定区域内的区段,并依次保存下来。
反复这个过程,直到填充结束。
区域填充的扫描线算法可由下列四个步骤实现:(1)初始化:堆栈置空。
将种子点(x,y)入栈。
(2)出栈:若栈空则结束。
否则取栈顶元素(x,y),以y作为当前扫描线。
(3)填充并确定种子点所在区段:从种子点(x,y)出发,沿当前扫描线向左、右两个方向填充,直到边界。
分别标记区段的左、右端点坐标为xl和xr。
(4)并确定新的种子点:在区间[xl,xr]中检查与当前扫描线y上、下相邻的两条扫描线上的象素。
若存在非边界、未填充的象素,则把每一区间的最右象素作为种子点压入堆栈,返回第(2)步。
四、实验步骤1.复习有关算法,明确实验目的和要求;2.依据算法思想,绘制程序流程图(指定填充多边形);3.设计程序界面,要求操作方便;4.用C/C++语言编写源程序并调试、执行分析实验结果5.对程序设计过程中出现的问题进行分析与总结;具体做法如下:1)打印源程序或把源程序以文件的形式提交;分析多边形区域扫描线填充算法的原理,确定算法流程①初始化:构造边表ET,置AET表为空;②将第一个不空的ET表中的边插入AET表;③由AET表取出交点进行配对(奇偶)获得填充区间,依次对这些填充区间着色;④y=y i+1时,根据x=x i+1/k修改AET表所有结点中交点的x坐标。
同时如果相应的ET表不空,则将其中的结点插入AET表,形成新的AET表;⑤AET表不空,则转(3),否则结束。
2)编程实现:⑥首先确定多边形顶点和ET/AET表中结点的结构;⑦编写链表相关操作(如链表结点插入、删除和排序等);⑧根据1)中的算法结合上述已有的链表操作函数实现多边形区域扫描线填充的主体功能;⑨编写主函数,测试该算法。
3)算法描述:void polyfill (多边形polygon, 颜色color){ for (各条扫描线i ){ 初始化新边表头指针NET [i];把ymin = i 的边放进边表NET [i];}y = 最低扫描线号;初始化活性边表AET为空;for (各条扫描线i ){ 把新边表NET[i]中的边结点用插入排序法插入AET表,使之按x坐标递增顺序排列;遍历AET表,把y max= i 的结点从AET表中删除,并把y max > i 结点的x值递增D x;若允许多边形的边自相交,则用冒泡排序法对AET表重新排序;遍历AET表,把配对交点区间(左闭右开)上的象素(x, y),用drawpixel (x, y, color) 改写象素颜色值;}} /* polyfill */6.五、实验结果及分析扫描线填充算法是通过沿扫描线填充水平像素段,来处理四连通或八连通相邻点,这样就仅仅只需要将每个水平像素段的起始位置压入栈,而不需要将当前位置周围尚未处理的相邻像素都压入栈,从而可以节省大量的栈空间。
六、程序代码#include "Conio.h"#include "graphics.h"#include "stdio.h"#define closegr closegraphvoid initgr(void) /* BGI初始化*/{int gd = DETECT, gm = 0; /* 和gd = VGA,gm = VGAHI是同样效果*/registerbgidriver(EGA VGA_driver);/* 注册BGI驱动后可以不需要.BGI文件的支持运行*/initgraph(&gd, &gm, "");}enum BOOL{FALSE = 0, TRUE = 1};typedef struct{int y;int xLeft;int xRight;}Span;/*区段*/typedef struct stacknode{Span span;struct stacknode *next;}stacknode;typedef struct{stacknode *top;}linkstack;/*-----------------进栈操作----------------------------------------*/void PushStack(linkstack *s, Span *span){stacknode *p=(stacknode*)malloc(sizeof(stacknode));p->span.y = span->y;p->span.xLeft = span->xLeft;p->span.xRight = span->xRight;p->next=s->top;s->top=p;}/*-----------------出栈操作------------------------------------------*/ void PopStack(linkstack *s,Span *span){int x;stacknode *p=s->top;span->y = p->span.y;span->xLeft = p->span.xLeft;span->xRight = p->span.xRight;s->top=p->next;free(p);}/*-----------------将栈清空------------------------------------------*/ void SetStackEmpty(linkstack *s){stacknode *p=s->top;while( s->top != NULL){free(p);s->top=p->next;}}/*--------------判断栈是否为空----------------------------------------*/ int IsStackEmpty(linkstack *s){if(s->top == NULL)return 1;elsereturn 0;}/*----------------核心程序开始----------------------------------------*/ void ScanLineFill4(int x,int y,int oldColor,int newColor){int xLeft,xRight;int i;enum BOOL isLeftEndSet, spanNeedFill;Span span;linkstack *s=(linkstack*)malloc(sizeof(linkstack));s->top = NULL;/*填充并确定种子点(x,y)所在的区段*/i = x;while(getpixel(i,y) == oldColor)/*向右填充*/{putpixel(i,y,newColor);i++;}span.xRight = i - 1; /*确定区段右边界*/i = x - 1;while(getpixel(i,y) == oldColor)/*向左填充*/{putpixel(i,y,newColor);i--;}span.xLeft = i + 1; /*确定区段左边界*//*初始化*/SetStackEmpty(s);span.y = y;PushStack(s,&span);/*将前面生成的区段压入堆栈*/ while( ! IsStackEmpty(s) )/*终止判断*/{/*出栈*/PopStack(s, &span);/*处理上面扫描线*/y = span.y + 1;xRight = span.xRight;i = span.xLeft - 1;isLeftEndSet = FALSE;while(getpixel(i,y) == oldColor)/*向左填充*/{putpixel(i, y, newColor);i--;}if( i != span.xLeft - 1)/*确定区段左边界*/{isLeftEndSet = TRUE;xLeft = i + 1;}i = span.xLeft;while( i < xRight){spanNeedFill = FALSE;while(getpixel(i,y) == oldColor) /*向右填充*/{if( ! spanNeedFill){spanNeedFill = TRUE;if( ! isLeftEndSet){isLeftEndSet = TRUE;xLeft = i;}}putpixel(i,y,newColor);i++;}if( spanNeedFill ){span.y = y;span.xLeft = xLeft;span.xRight = i - 1;PushStack(s, &span); /*将区段压入堆栈*/isLeftEndSet = FALSE;spanNeedFill = FALSE;}/* while(getpixel(i,y) != oldColor) */i++;}/*end of while( i < xRight) *//*处理下面一条扫描线,与处理上面一条扫描线完全类似*/ y = y - 2;xRight = span.xRight;i = span.xLeft - 1;isLeftEndSet = FALSE;while(getpixel(i,y) == oldColor)/*向左填充*/{putpixel(i, y, newColor);i--;}if( i != span.xLeft - 1)/*确定区段左边界*/{isLeftEndSet = TRUE;xLeft = i + 1;}i = span.xLeft;while( i < xRight){spanNeedFill = FALSE;while(getpixel(i,y) == oldColor) /*向右填充*/{if( ! spanNeedFill){spanNeedFill = TRUE;if( ! isLeftEndSet){isLeftEndSet = TRUE;xLeft = i;}}putpixel(i,y,newColor);i++;}if( spanNeedFill ){span.y = y;span.xLeft = xLeft;span.xRight = i - 1;PushStack(s, &span); /*将区段压入堆栈*/isLeftEndSet = FALSE;spanNeedFill = FALSE;}/* while(getpixel(i,y) != oldColor) */i++;}/*end of while( i < xRight) */delay(2000); /*延时*/}/*end of while( ! isStackEmpty() ) */}/*end of ScanLineFill4() *//*---------------------main()------------------------------------------*/ int main(){initgr(); /* BGI初始化*/setbkcolor(3);setcolor(1);moveto(50, 50); /*绘制4连通区域*/lineto(400, 50);lineto(400,300);lineto(150,300);lineto(150,400);lineto(50, 400);lineto(50, 50);ScanLineFill4(150,150,0,14); /*相与后oldColor == 0*/ getch(); /* 暂停一下,看看前面绘图代码的运行结果*/ closegr(); /* 恢复TEXT屏幕模式*/return 0;}七、实验结果。