ImageVerifierCode 换一换
格式:DOCX , 页数:30 ,大小:168.54KB ,
资源ID:11790940      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/11790940.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(计算机图形学课程设计有效边表填充算法的实现.docx)为本站会员(b****4)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

计算机图形学课程设计有效边表填充算法的实现.docx

1、计算机图形学课程设计有效边表填充算法的实现 计算机图形学 课程设计设计题目 改进的有效边表算法对多边形的填充 学院名称 信息科学与技术学院 专业名称 计算机科学与技术 学生姓名 刘 柯 学生学号 201213030112 任课教师 梅 占 勇 设计(论文)成绩 教务处 制2015年 9 月 28 日一、设计内容与要求1.1 设计题目用改进的有效边表算法实现多边形的填充1.2 设计内容使用OpenGL实现用改进的有效边表算法填充多边形1.3 设计目标参照课本上改进的有效边表算法的思想,实现该算法的C语言代码,并用该算法搭配OpenGL以像素点的方式绘制出给定顶点坐标的多边形。二、总体设计2.1

2、多边形的表示在计算机图形学中,多边形有2种重要的表示方法:顶点表示和点阵表示。顶点表示用多边形的顶点序列来刻画多边形,这种方法直观、几何意义强,占用内存少,应用普遍,但它没有明确指出哪些像素在多边形内,故不能直接用于面着色。点阵表示用位于多边形内的像素的集合来刻画多边形。 这种表示法虽然失去了许多重要的几何信息,但便于运用帧缓存表示图形,是面着色所需要的图形表示形式。大多数图形应用系统采用顶点序列表示多边形,而顶点表示又不能直接用于显示,那么就必须有从多边形的顶点表示到点阵表示的转换,这种转换称为多边形的扫描转换或多边形的填充。即从多边形的顶点信息出发,求出位于其内部的各个像素,并将其颜色值写

3、入帧缓存的相应单元中。2.2 x-扫描线算法 x-扫描线算法的基本思想是,按照扫描线的顺序,计算扫描线与多边形的相交区间,再用要求的颜色显示这些区间的像素,即完成填充工作。区间的端点可以通过计算扫描线与多边形边界线的交点获得。根据此原理,x-扫描线算法可以填充凸的、凹的或带有孔的多边形区域。 x-扫描线的算法步骤如下:(1) 确定多边形顶点的最小和最大y值(ymin和ymax),得到多边形所占有的最大扫描线数。(2) 从y=ymin到y=ymax,每次用一条扫描线填充。每一条扫描线填充的过程分为4个步骤:1 求交。计算扫描线与多边形所有边的交点。2 排序。把所有交点按x坐标递增的顺序进行排序。

4、3 交点配对。配对第一与第二、第三与第四个交点等,每对交点代表一个填充区间。4 区间填色。把这些相交区间内的像素置成不同于背景色的填充色。x-扫描线算法在处理每条扫描线时,需要与多边形的所有边求交,这样处理效率非常低。因为一条扫描线往往只与少数几条边相交,甚至与整个多边形都不相交。因此,有必要对算法进行改进。2.3 改进的有效边表算法2.3.1 改进的有效边表算法将x-扫描线算法加以改进可以得到改进的有效边表算法,也称y连贯算法。改进可以从三个方面进行:首先,在处理一条扫描线时,仅对与它相交的多边形的边(有效边)求交;其次,利用扫描线的连贯性,考虑到当前扫描线与各边的交点顺序与下一条扫描线与各

5、边的交点顺序很可能相同或非常相似,因此在当前扫描线处理完毕之后,不必为下一条扫描线从头开始构造交点信息;最后,利用多边形的连贯性,认为若某条边与当前扫描线相交,则它很可能也与下一条扫描线相交且其交点与上一次的交点相关。如下图所示,设直线的斜率为k,若y=yi时,x=xi;则当y=yi+1时,有xi+1=xi+1/k。2.3.2 有效边表 有效边(Active Edge)是指与当前扫描线相交的多边形的边,也称活性边。把有效边按与扫描线交点x坐标递增的顺序存放在一个链表中,此链表称为有效边表(Active Edge Table, AET)。有效边表的每个结点存放对应边的如下信息: 其中,x为当前扫

6、描线与有效边交点的x坐标;ymax是有效边所在的最大扫描线值,通过它可以知道何时才能“抛弃”该边;1/k是边斜率的倒数;next是下一个结点的指针。 如下图所示的多边形P0P1P2P3P4P5P6,其顶点表示为:P0(7,8),P1(3,12),P2(1,7),P3(3,1),P4(6,5),P5(8,1),P6(12,9)。 当y=8时的有效边表如下图所示:2.3.3 边表 有效边表给出了扫描线和有效边交点坐标的计算方法,但是没有给出新边出现的位置坐标。为了方便有效边表的建立与更新,就需要构造一个边表(Edge Table, ET),用以存放扫描线上多边形各条边的信息。由于水平边的1/k为,

7、并且水平边本身就是扫描线,所以在建立边表时不予考虑。 边表的构造分为4个步骤:1 首先构造一个纵向链表,链表的长度为多边形占有的最大扫描线数,链表的每个结点,称为一个桶,对应多边形覆盖的每一条扫描线。2 将每条边的信息装入与该边最小y坐标(ymin)相对应的桶中。也就是说,若某边的较低端点为ymin,则该边就放在相应的y=ymin的扫描线桶中。3 每条边的数据形成一个结点,内容包括该扫描线与该边的初始交点x(即较低端点的x坐标值),该边最大y坐标值ymax,以及斜率的倒数1/k和下一个边结点的指针next:4 同一桶中若干条边按x|ymin由小到大排列,若x|ymin相等,则按1/k由小到大排

8、序。 从上面可以看出,边表是有效边表的特例,有效边表和边表可以使用同一个数据结构来表示。 对于多边形P0P1P2P3P4P5P6,它的边表结构如下图所示:三、详细设计3.1 改进的有效边表算法的实现 改进的有效边表算法具体实现过程如下:1 初始化边表ET。为了方便边表的建立,可以定义sort()函数对多边形的边进行排序,保证边表中每个桶中的边是有序的。同时定义一个creat_edge_table()函数,该函数需要多边形的顶点信息作为参数传入,并返回一个边表指针。2 初始化有效边表AET。从ET表中取出第一个不为空的桶与AET表合并。为了初始化AET表,可以定义一个init_active_ta

9、ble()函数,该函数传入边表指针作为形参,返回一个有效边表指针。3 从AET表中取出交点进行填充。填充时设置一个布尔值b(初值为假),令指针从有效边表的第一个结点(也就是扫描线与有效边的交点)开始遍历。每访问一个结点,把b取反一次。若b为真,则把从当前结点的x值开始(设为x1)到下一结点的x值结束(设为x2)的区间x1, x2用多边形色填充。填充时为了避免多边形区域扩大化,需要对区间边界进行如下处理:若x是整数,则按“左闭右开”的原则处理,即左边界上的x(x1)不变,右边界上的x(x2)减1;若x不是整数,左边界上的x(x1)向右取整,右边界上的x(x2)向左取整。4 更新AET表。设当前A

10、ET表中扫描线为y,首先更新扫描线为y=y+1,然后删除AET表中所有ymax=y的边结点;再根据xi+1=xi+1/k计算并修改AET表中各边结点的x坐标,同时合并ET表对应于扫描线y的桶中的边,按次序插入到AET表中,形成新AET表。此步骤满足多边形的“下闭上开”原则。此过程用到自定义的函数delete_edge()、add_edge()、update_active_table()。5 判断AET表是否为空。若为空,则结束;否则转到3.2 有效边表算法程序流程图四、测试结果 为了便于观察多边形的填充,本程序将像素点进行放大处理,400 x 300的分辨率投影到20 x 15,并绘制出网格,

11、使用OpenGL画出多边形的边框。使用了Sleep()函数来延时生成像素点,并且每填充一个像素点刷新一次,给人动态直观的感受。1 在不处理边界的情况下,如下图所示,多边形的区域可能会扩大化。2 对边界进行处理后,结果如下:3 为了验证改进的有效边表填充算法,现将本程序的像素大小恢复为1:1,按比例扩大多边形的顶点坐标,测试结果如下: 从上图可以看出填充过后的多边形与原多边形P0P1P2P3P4P5P6的形状一致,该算法验证通过。4 测试其他多边形长方形:三角形:五角星:从以上结果来看,该算法基本得到完美实现。而程序的执行时间来看,生成边表的时间(包括分配内存、对桶中的结点进行排序等)远比填充像

12、素点的时间要长。因此,该算法的效率虽然很高,但对于表的维护和排序开销太大,它适合软件实现而不适合硬件实现。五、总结 通过本次课程设计,我掌握了多边形的填充算法,了解了OpenGL的运行结构,熟悉了很多OpenGL的函数,对OpenGL编程也产生的浓厚的兴趣。同时也巩固了对计算机图形学知识的掌握,锻炼了我对手实验的能力,看清了自己的水平,认识到了自己的不足。 在本次课程设计中,存在一些不足之处。比如对边界的处理,课本上的说法模糊不清,在网上也没有找到相应的解答,我只能根据自己的理解来试着解决;这方面也存在没有及时和老师沟通的原因。从这一点上,我认识到理论和实践的差别,我们应该多实践才能真正掌握理

13、论。 还有就是完全填充后的多边形,边缘有“锯齿”现象,不知道是我程序的原因还是算法的问题。或许对于多边形的填充算法还应该处理“锯齿”。六、源代码/源代码仅包含文件PolygonFilling.cpp#include #include #include #include #define EPSILON 0.000001 /最小浮点数/点结构体struct Point int x; /x坐标 int y; /y坐标;/线结构体struct Line Point high_point; /高端点 Point low_point; /低端点 int is_active; /是否为有效边,水平边(0),

14、非水平边(1) double inverse_k; /斜率k的倒数;/边结点struct EdgeNode double x; /扫描线与边交点的x坐标(边的低端点的x坐标) int y_max; /边的高端点的y坐标ymax double inverse_k; /斜率k的倒数 EdgeNode *next; /下一个边结点的指针;/有效边表struct ActiveEdgeTable int y; /扫描线y EdgeNode *head; /边链表的头指针;/桶结点typedef struct Bucket int y; /扫描线y EdgeNode *head; /边链表的头指针 Buc

15、ket *next; /下一个桶的指针 EdgeTable;int compare(Point p1, Point p2);Line* create_lines(Point points, int n);Point get_lowest_point(Line lines, int n);Point get_highest_point(Line lines, int n);void s &l1, Line &l2);void sort(Line lines, int n);EdgeTable* create_edge_table(Line lines, int n);ActiveEdgeTabl

16、e* init_active_table(EdgeTable *edge_table);void delete_edge(ActiveEdgeTable *active_table, int y_max);void add_edge(ActiveEdgeTable *active_table, EdgeNode edge);ActiveEdgeTable* update_active_table(ActiveEdgeTable *active_table, EdgeTable *edge_table);void DrawPolygon(Point points, int n);void Dra

17、wGrid(int x, int y);void Fill(Point points, int n);void Initial();void Display();int main(int argc, char* argv) glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(400, 300); glutInitWindowPosition(100, 120); glutCreateWindow(Polygon Filling); glutDisplayFunc(Displ

18、ay); Initial(); glutMainLoop(); return 0;/比较2个点的高度int compare(Point p1, Point p2) if (p1.y p2.y) return 1; else if (p1.y = p2.y) return 0; return -1;/由点数组生成线段数组Line* create_lines(Point points, int n) Line *lines = (Line*)malloc(n * sizeof(Line); for (int i = 0; i 0 ? p1 : p2; linesi.low_point = resu

19、lt 0 ? p1 : p2; linesi.inverse_k = (double)(p2.x - p1.x) / (double)(p2.y - p1.y); return lines;/获取线数组中最低的端点Point get_lowest_point(Line lines, int n) Point lowest_point = lines0.low_point; for (int i = 1; i 0) lowest_point = low_point; return lowest_point;/获取线数组中最高的端点Point get_highest_point(Line line

20、s, int n) Point highest_point = lines0.high_point; for (int i = 1; i n; +i) Point high_point = linesi.high_point; if (compare(highest_point, high_point) 0) highest_point = high_point; return highest_point;/交换2个Line对象void s &l1, Line &l2) Line temp = l1; l1 = l2; l2 = temp;/对线数组进行排序void sort(Line lin

21、es, int n) /先按低端点的y坐标进行升序排序 for (int i = 0; i n; +i) int min_index = i; for (int j = i + 1; j n; +j) if (linesj.low_point.y linesmin_index.low_point.y) min_index = j; si, linesmin_index); /再将有序数组按低端点的x坐标升序排列,若x坐标相等,按inverse_k升序 for (int i = 0; i n; +i) int min_index = i; for (int j = i + 1; linesj.l

22、ow_point.y = linesi.low_point.y; +j) if (linesj.low_point.x 0 & linesi.low_point.x = linesi - 1.low_point.x) if (linesi.is_active = 1 & linesi - 1.is_active = 1) if (linesi.inverse_k head = NULL; edge_table-next = NULL; sort(lines, n); Point lowest_point = get_lowest_point(lines, n); Point highest_p

23、oint = get_highest_point(lines, n); EdgeTable *s = edge_table; for (int i = lowest_point.y; i y = i; bucket-next = NULL; bucket-head = (EdgeNode*)malloc(sizeof(EdgeNode); bucket-head-next = NULL; EdgeNode *p = bucket-head; for (int j = 0; j x = linesj.low_point.x; q-y_max = linesj.high_point.y; q-in

24、verse_k = linesj.inverse_k; q-next = NULL; p-next = q; p = q; s-next = bucket; s = bucket; return edge_table;/从边表中取出第一个不为空的桶初始化有效边表ActiveEdgeTable* init_active_table(EdgeTable *edge_table) ActiveEdgeTable *active_table = (ActiveEdgeTable*)malloc(sizeof(ActiveEdgeTable); active_table-y = edge_table-n

25、ext-y; active_table-head = (EdgeNode*)malloc(sizeof(EdgeNode); active_table-head-next = NULL; EdgeNode *p = edge_table-next-head; EdgeNode *q = active_table-head; while (p-next != NULL) EdgeNode *s = (EdgeNode*)malloc(sizeof(EdgeNode); s-x = p-next-x; s-y_max = p-next-y_max; s-inverse_k = p-next-inv

26、erse_k; s-next = NULL; q-next = s; q = s; p = p-next; return active_table;/从有效边表中删除指定y_max的边结点void delete_edge(ActiveEdgeTable *active_table, int y_max) EdgeNode *p = active_table-head; while (p-next != NULL) EdgeNode *q = p-next; if (q-y_max = y_max) p-next = q-next; free(q); else p = p-next; /将一个边

27、结点按次序添加到有效边表中void add_edge(ActiveEdgeTable *active_table, EdgeNode edge) EdgeNode *t = (EdgeNode*)malloc(sizeof(EdgeNode); t-x = edge.x; t-y_max = edge.y_max; t-inverse_k = edge.inverse_k; t-next = NULL; EdgeNode *p = active_table-head; while (p-next != NULL) EdgeNode *q = p-next; if (edge.x x) | (edge.x = q-x & edge.i

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1