实验二 有效边表填充算法
计算机图形学课程设计-有效边表填充算法实现

计算机图形学课程设计设计题目改进的有效边表算法对多边形的填充学院名称信息科学与技术学院专业名称计算机科学与技术学生姓名刘柯学生学号201213030112任课教师梅占勇设计(论文)成绩教务处制2015年9 月28 日目录一、设计内容与要求 (3)1.1设计题目 (3)1.2 设计内容 (3)1.3 设计目标 (3)二、总体设计 (3)2.1 多边形的表示 (3)2.2 x-扫描线算法 (4)2.3 改进的有效边表算法 (4)2.3.1 改进的有效边表算法 (4)2.3.2 有效边表 (5)2.3.3 边表 (6)三、详细设计 (8)3.1 改进的有效边表算法的实现 (8)3.2 有效边表算法程序流程图 (9)四、测试结果 (9)五、总结 (15)六、源代码 (15)参考文献 (26)一、设计内容与要求1.1设计题目用改进的有效边表算法实现多边形的填充1.2 设计内容使用OpenGL实现用改进的有效边表算法填充多边形1.3 设计目标参照课本上改进的有效边表算法的思想,实现该算法的C语言代码,并用该算法搭配OpenGL以像素点的方式绘制出给定顶点坐标的多边形。
二、总体设计2.1 多边形的表示在计算机图形学中,多边形有2种重要的表示方法:顶点表示和点阵表示。
顶点表示用多边形的顶点序列来刻画多边形,这种方法直观、几何意义强,占用内存少,应用普遍,但它没有明确指出哪些像素在多边形内,故不能直接用于面着色。
点阵表示用位于多边形内的像素的集合来刻画多边形。
这种表示法虽然失去了许多重要的几何信息,但便于运用帧缓存表示图形,是面着色所需要的图形表示形式。
大多数图形应用系统采用顶点序列表示多边形,而顶点表示又不能直接用于显示,那么就必须有从多边形的顶点表示到点阵表示的转换,这种转换称为多边形的扫描转换或多边形的填充。
即从多边形的顶点信息出发,求出位于其内部的各个像素,并将其颜色值写入帧缓存的相应单元中。
2.2 x-扫描线算法x-扫描线算法的基本思想是,按照扫描线的顺序,计算扫描线与多边形的相交区间,再用要求的颜色显示这些区间的像素,即完成填充工作。
多边形边表桶填充

实验一:改进的有效边表算法一.实验目的用鼠标描绘几个顶点,画出多边形,用边表桶的填充算法实现多边形的填充。
二.算法思想在处理一条扫描线时,仅对与它相交的多边形的边(有效边)求交,其次利用扫描线的连贯性,考虑到当前扫描线与各边的交点顺序与下一条扫描线各边的交点顺序很可能相同或者相似,因此在当前扫描线处理完毕之后,不必为下一条扫描线从头开始构造交点信息;最后利用多边形边的连贯性,认为若某条边与当前扫描线相交,则它很可能也与下一条扫描线相交且其交点与上一次的交点相交。
三.实现过程1.边表的构造1.首先构造一个纵向链表,链表长度为多边形所占有的最大扫描线数,链表的每个结点,称为,称为一个桶,对应多边形覆盖的每一条扫描线。
2.将每条边的信息装入与该边最小Y坐标(Ymin)相对应的桶中,也就是说,若某条边的较低端点为Ymin,则该边就放在相应的Y=Ymin的扫描线桶中。
3.每条边的数据形成一个结点,内容包括该扫描线与该边的初始交点X(即较低端点的X坐标),该边的最大Y 坐标值Ymax,以及边斜率的倒数1/k.4.同一桶中若干条边按x|ymin 由小到大排序,若x|ymin相等,则按照1/k由小到大排序。
2.扫描线的填充算法1.初始化。
构造边表,AET表设置为空。
2.将第一个不空的ET表中的边与AET表合并。
3.由AET表中取出的交点并进行填充,填充时候设置一个布尔量b(初值为假),令指针有效边表中的第一个结点(交点)到最后一个结点遍历一次,每访问一个结点,把b取反一次,若b为真,则把从当前结点的x值开始到下一个结点的x值结束的区间用多边形色填充,填充之后删除y=ymax的边(需注意,填充时同样为避免多边形区域的扩大化,需要多交点进行与x-扫面线算法相同的处理)。
4.y i+1=y i+1,根据x i+1=x i+1/k计算并修改AET表,同时合并ET表中y=y i+1桶中的边,按次序插入到AET 表中形成新的AET表。
《计算机图形学》有序边表填充算法

初始化每条扫面线的边链表 */
/*
建“桶” */
edges[scan]->next=NULL;
}
BuildEdgeList(cnt,pts,edges);
/*
建立有序边表 */
active=(Edge *)malloc(sizeof(Edge));
active->next=NULL;
for(scan=scanmin;scan<=scanmax;scan++) /* 扫描每条扫描线, 求活性表 */
当多边形新边表 ET构成后,按下列步骤进行: ① 对每一条扫描线 i ,初始化 ET表的表头指针 ET[i] ; ② 将 ymax = i 的边放入 ET[i] 中; ③ 使 y = 多边形最低的扫描线号; ④ 初始化活性边表 AET为空; ⑤ 循环,直到 AET和 ET 为空。
将新边表 ET 中对应 y 值的新边节点插入到 AET表。 遍历 AET表,将两两配对的交点之间填充给定颜色值。 遍历 AET表,将 ymax= y 的边节点从 AET表中删除,并将 ymax> y 的各边节点 的 x 值递增 Δx;并重新排序。 y 增加 1。
/* 建立扫描线 scan 的活性边表 , 把活性边结点放入扫描线 scan 的结点指针数组
edges[scan] 中*/
{
Edge *p,*q;
p=edges[scan]->next;
/*
查找当前扫描线对应的 y 桶*/
while(p)
/*y
桶不空 */
{q=p->next;
/*
找到最后一个边结点, 插入 */
*edges[])
/* 把边结点 edge, 放到 lower.y 扫描线所在的边结点指针数组 edges[] 中 */
第四章 多边形填充

class CBucket { public: CBucket(); virtual ~CBucket(); public: int ScanLine; CAET *p; CBucket *next; }; 桶类
感知光强 实际光强
马赫带
填充多边形
多边形填充的主要算法是扫描线算法。先确定多边形 覆盖的扫描线条数,对每一条扫描线,计算扫描线与多 边形边界的交点区间,如果能判断该区间在多边形内部, 则将其内的像素绘制为指定的颜色。扫描线算法在处理 每条扫描线时,需要与多边形的所有边求交,处理效率 很低。改进的算法是有效边表算法。
}
4.2.5 算法步骤
输入:顶点数组 CPoint Point[7];//定义多边形,7个 顶点 算法 (1)根据顶点计算多边形最低点y值 (scanMin)和多边形最高点y值(scanMax); (2)建立桶表和边表; 建立桶表: i从scanMin到scanMax的循环, 将i赋给scanLine, 指针p为空,各节点相联
4.2
有效边表填充算法
4.2.1 填充原理
有效边表填充算法通过维护边表和有效边表,避开 了扫描线与多边形所有边求交的复杂运算。填充原理是 按照扫描线从小到大的移动顺序,计算当前扫描线与有 效边的交点,然后把这些交点按x值递增的顺序进行排序、 配对,以确定填充区间,最后用指定颜色填充区间内的 所有像素,即完成填充工作。有效边表填充算法已成为 目前最为有效的多边形填充算法之一。
[VIP专享]计算机图形学 有效边表填充算法实验报告
![[VIP专享]计算机图形学 有效边表填充算法实验报告](https://img.taocdn.com/s3/m/4ea18a9689eb172ded63b7d8.png)
图 2 屏幕显示多边形 3.算法设计: (1)建立 AET 和 BUCKET 类; (2)初始化桶,并在建立桶结点时为其表示的扫描线初始化为带头结点的链表; (3)对每个桶结点进行循环,将桶内每个结点的边表合并为有效边表,并进行有效边表循 环; (4)按照扫描线从小到大的移动顺序,计算当前扫描线与多边形各边的交点,然后把这些 交点按 X 值递增的顺序进行排序,配对,以确定填充区间; (5)用指定颜色点亮填充区间内的所有像素,即完成填充工作。 4.源程序: 1)//AET.h class AET { public:
}
Bucket::~Bucket() {
}
3)//TestView.h #include "AET.h"//包含有效边表类 #include "Bucket.h"//包含桶类 #define Number 7//N 为闭合多边形顶点数,顶点存放在整型二维数组 Point[N]中 class CTestView : public CView { 。。。。。。。。。 public:
COLORREF GetColor;//调色板 CPoint Point[7];//定义多边形 Bucket *HeadB,*CurrentB;//桶的头结点和当前结点 AET E[Number],*HeadE,*CurrentE,*T1,*T2;//有效边表的结点 } (4) TestView.cpp #define ROUND(a) int(a+0.5) //四舍五入 CTestView::CTestView() { //设置多边形的 7 个顶点 Point[0]=CPoint(550,400);//P0 Point[1]=CPoint(350,600);//P1 Point[2]=CPoint(250,350);//P2 Point[3]=CPoint(350,50);//P3 Point[4]=CPoint(500,250);//P4 Point[5]=CPoint(600,50);//P5 Point[6]=CPoint(800,450);//P6 }
有效边表填充算法

实验二有效边表填充算法实验题目:有效边表填充算法学号:姓名:班级:指导老师:完成日期:1.实验目的:设计有效边表结点和边表结点数据结构设计有效边表填充算法编程实现有效边表填充算法2.实验描述:下图1 所示多边形覆盖了12 条扫描线,共有7 个顶点和7 条边。
7 个顶点分别为:P0(7,8),P1(3,12),P2(1,7),P3(3,1), P4(6,5), P5(8,1), P6(12,9)。
在1024×768 的显示分辩率下,将多边形顶点放大为P0(500,400),P1(350,600),P2(250,350),P3(350,50), P4(500,250), P5(600,50), P6(800,450)。
图1示例多边形图2屏幕显示多边形3.算法设计:多边形的有效边表填充算法的基本原理是按照扫描线从小到大的移动顺序,计算当前扫描线与多边形各边的交点,然后把这些交点按x值递增的顺序进行排序、配对,以确定填充区间,然后用指定颜色点亮填充区间的所有像素,即完成填充工作。
有效边表填充算法通过访问多边形覆盖区间内的每个像素,可以填充凸、凹多边形和环,已成为目前最为有效的多边形填充算法。
4.源程序:1)//AET.h和AET..cppclass AET{public:AET();virtual ~AET();double x;int yMax;double k; //代替1/kAET *next;}2)//Bucket.h和Bucket.cppclass Bucket{public:Bucket();virtual ~Bucket();int ScanLine;AET *p;//桶上的边表指针Bucket *next;}3) // TestView.h#include "AET.h"//包含有效边表类#include "Bucket.h"//包含桶类#define Number 7//N为闭合多边形顶点数,顶点存放在整型二维数组Point[N]中class CTestView : public CView{。
计算机图形学实验有效边表填充算法

实验二2-2一、实验题目给定四个点绘制图4-44所示的不同转角的两个正方形,使用有效边表算法进行填充,填充效果如图4-45所示,注意采用“左闭右开”和“上闭下开”的原则,使得每个正方形的右边界和下边界没有填充。
二、实验思想有效边表填充算法通过维护边表和有效边表,避开了扫描线与多边形所有边求交的复杂运算。
填充原理是按照扫描线从小到大的移动顺序,计算当前扫描线与有效边的交点,然后把这些交点按x值递增的顺序进行排序、配对,以确定填充区间,最后用指定颜色填充区间内的所有像素,即完成填充工作。
三、实验代码void CTestView::GetMaxX()//获得屏幕宽度{CRect Rect;GetClientRect(&Rect);MaxX=Rect.right;}void CTestView::GetMaxY()//获得屏幕高度{CRect Rect;GetClientRect(&Rect);MaxY=Rect.bottom;}void CTestView::ReadPoint()//读入点表函数{//设置第一个正方形的4个顶点int a=160;P1[0]=CP2(MaxX/4-a,MaxY/2+a);//P0P1[1]=CP2(MaxX/4+a,MaxY/2+a);//P1P1[2]=CP2(MaxX/4+a,MaxY/2-a);//P2P1[3]=CP2(MaxX/4-a,MaxY/2-a);//P3//设置第二个正方形的4个顶点int b=ROUND(sqrt(2)*a);P2[0]=CP2(3*MaxX/4,MaxY/2+b);//P0P2[1]=CP2(3*MaxX/4+b,MaxY/2);//P1P2[2]=CP2(3*MaxX/4,MaxY/2-b);//P2P2[3]=CP2(3*MaxX/4-b,MaxY/2);//P3}void CTestView::DrawRect(CDC *pDC,CP2 *P)//绘制正方形函数{CP2 T;CLine line;for(int i=0;i<4;i++)//边循环{if(i==0){line.MoveTo(pDC,P[i]);T=P[0];}else{line.LineTo(pDC,P[i]);;}}line.LineTo(pDC,T);//闭合}void CTestView::OnMENUIFill(){// TODO: Add your command handler code hereCOLORREF FColor;CColorDialog ccd(RGB(255,0,0));if(ccd.DoModal()==IDOK)//调用调色板选取色{FColor=ccd.GetColor();m_Red=GetRValue(FColor);//获得颜色的红色分量m_Green=GetGValue(FColor);//获得颜色的绿色分量m_Blue=GetBValue(FColor);//获得颜色的蓝色分量}RedrawWindow();//刷新屏幕FillRect(P1);//填充正方形1FillRect(P2);//填充正方形2}void CTestView::FillRect(CP2 *P)//填充正方形函数{CFill fill;CPi2 Point[4];for(int i=0;i<4;i++){Point[i].x=P[i].x;Point[i].y=ROUND(P[i].y);Point[i].c=CRGB(double(m_Red)/255.0,double(m_Green)/255.0,double(m_Blue)/255.0);}CDC *pDC=GetDC();fill.SetPoint(Point,4);//填充正方形fill.CreateBucket();fill.CreateEdge();fill.Gouraud(pDC);ReleaseDC(pDC);}四、实验截图。
有效边表填充算法

有效边表填充算法基本思想:⽤⽔平扫描线从上到下(或从下到上)扫描由多条⾸尾相连的线段构成的多边形,每根扫描线与多边形的某些边产⽣⼀系列的交点。
将这些交点按照x坐标排序,将排序后的点两两配对,作为线段的两个端点,以所填的颜⾊画⽔平直线。
步骤1.求交,计算扫描线与多边形的交点。
2.交点排序,对第1步得到的交点按照x从⼩到⼤排序3.颜⾊填充,对排序后的交点两两组成⼀个⽔平线段,以画线段的⽅式进⾏颜⾊填充。
4.完成多边形扫描,就结束算法,否则,继续1有效边多边形与当前扫描线相交的边成为有效边(active edge)。
在处理⼀条扫描线时仅对有效边进⾏求交运算,避免与多边形所有边求交,提⾼效率。
x y max1/k next桶表与边表有效边给出了扫描线与有效边交点的计算⽅法,但没有给出新边出现的位置坐标。
为了确定在哪条扫描线上加⼊了新边,就需要构造⼀个边表(edge table ET),⽤以存放扫描线上多边形各条边出现的信息。
⽔平边本⾝就是扫描线在建⽴边表时可以不予考虑。
桶表与边表的表⽰法桶表是按照扫描线顺序管理边出现的⼀个数据结构。
⾸先,构造⼀个纵向扫描线链表,链表的长度为多边形所占有的最⼤扫描线数,链表的每个节点称为桶(bucket),对应多边形覆盖的每⼀条扫描线。
将每条边的信息链加⼊该边最⼩y坐标对应的桶处。
对每⼀条扫描线,如果新增多条边,按照x|y min 坐标递增的顺序存放在⼀个链表中,若x|y min 相等,则按照1/k递增,就形成边表。
x|ymin ymax1/k next。
填充算法实验报告

填充算法实验报告实验报告:填充算法研究与实验1. 实验目的填充算法在计算机图形学中有着广泛的应用,并且对于计算机图形学的发展有着重要意义。
本次实验旨在通过对填充算法的研究与实验,了解填充算法的原理和应用,掌握填充算法的基本实现方法,实现简单的填充效果。
2. 实验背景填充算法是计算机图形学中的一种常用算法,用于将指定区域进行填充。
填充算法可以应用于图像的编辑、区域选择、图像渲染等方面。
常见的填充算法包括区域种子填充算法、扫描线填充算法等。
3. 实验内容本次实验主要研究和实现了区域种子填充算法和扫描线填充算法。
区域种子填充算法是指通过指定一个待填充的种子点,在其周围的区域进行填充。
扫描线填充算法是指通过扫描图像的每一行,在特定条件下对像素进行填充。
在实验中,我们首先实现了区域种子填充算法。
通过在待填充的区域中选择一个点作为种子点,然后从指定点出发,通过递归或栈的方式对相邻的像素进行着色,直到遇到与起始点像素颜色不同的像素为止,从而完成填充效果。
其次,我们实现了扫描线填充算法。
这种算法的核心是扫描图像的每一行,在每一行上找到待填充区域的边界并将其记录下来,然后根据边界的位置对每一个像素进行填充。
我们采用了活性边表和扫描线转换算法来实现扫描线填充算法。
4. 实验结果通过实验我们成功实现了区域种子填充算法和扫描线填充算法,在输入指定的区域和种子点后,程序能够快速地对指定区域进行填充,生成了良好的填充效果。
5. 实验分析区域种子填充算法是一种简单且直观的填充算法,但对于复杂区域的填充效果并不理想。
它的主要缺点是可能导致栈溢出或填充效果不均匀,因此在实际应用中不太常用。
相比之下,扫描线填充算法具有更好的填充效果和效率。
其使用了活性边表和扫描线转换算法,可以在进行每一行的扫描时快速地找到边界并进行填充。
但该算法无法很好地处理较复杂的几何形状,例如存在凹陷和自相交的区域。
6. 实验总结通过本次实验,我们深入学习了填充算法的基本原理和实现方法,并成功实现了区域种子填充算法和扫描线填充算法。
多边形填充算法-有序边表法(扫描线算法)

多边形填充算法-有序边表法(扫描线算法)1.算法的基本思想(扫描线连贯性原理): 对于⼀个给定的多边形,⽤⼀组⽔平(垂直)的扫描线进⾏扫描,对每⼀条扫描线均可求出与多边形边的交点,这些交点将扫描线分割成落在多边形内部的线段和落在多边形外部的线段;并且⼆者相间排列。
于是,将落在多边形内部的线段上的所有象素点赋以给定的⾊彩值。
算法中不需要检验每⼀个象素点,⽽只考虑与多边形边相交的交点分割后的扫描线段。
2.算法求解:对于每⼀条扫描线的处理:1)求交点:⾸先求出扫描线与多边形各边的交点;2)交点排序:将这些交点按X坐标递增顺序排序;3)交点匹配:即从左到右确定落在多边形内部的那些线段;4)区间填充:填充落在多边形内部的线段。
3.求交点的⽅法最简单的办法:将多边形的所有边放在⼀个表中,在处理每条扫描线时,从表中顺序取出所有的边,分别求这些边与扫描线的交点。
不使⽤该⽅法的原因:将做⼀些⽆益的求交点动作,因为扫描线并不⼀定与多边形的边相交,扫描线只与部分甚⾄较少的边相交;因此,在进⾏扫描线与多边形边求交点时,应只求那些与扫描线相交的边的交点。
确定与扫描线相交的边:⽤边表来确定哪些边是下⼀条扫描线求交计算时应该加⼊运算的。
4.边表(ET):ET的意义在于为扫描线提供待加⼊的新边信息。
建⽴边的分类表ET(Edge Table),每个结点结构如下:(Ymax ,ΔX ,X Ymin,)Ymax:边的最⼤Y值;ΔX:从当前扫描线到下⼀条扫描线之间的X增量(dX/ dY);X Ymin:边的下端点的X坐标;next:指针,指向下⼀条边。
边的分类表可以这样建⽴:先按下端点的纵坐标(y值)对所有边作桶分类,再将同⼀组中的边按下端点X坐标递增的顺序进⾏排序, X坐标还相同的按ΔX递增的顺序进⾏排序。
5.活性边表AET把与当前扫描线相交的边称活化边AEL(Active Edge List) 。
组成的表称为活性表AET,其数据域组成如下:Ymax :存放边的上端点Y坐标;X :边与当前扫描线交点的X坐标;ΔX ,next指针:同边表。
扫描线填充算法--有效边表填充算法

代码:draw.cpp//using OpenGL#include "opengl.h"#include <iostream>#include <vector>#include <algorithm>#include <unistd.h>#define PN 6intpoint[N][2]={{40,5},{75,40},{60,70},{35,50},{25,80},{5,30 }};//AEstruct AE{AE(float _x,float _dx,int_ymax){x=_x;dx=_dx;ymax=_ymax;}float x;float dx;int ymax;void operator++(int){x+=dx;}};//AET//which eage is on the rightbool fill_comp(const AE& ae1,const AE& ae2){if(ae1.x<ae2.x){return true;}if(ae1.x==ae2.x&&ae1.dx<ae2.dx){return true;}return false;}void fillline(int y,int x1,int x2){for(int i=x1;i<=x2;i++) drawpoint(i,y);flush();}void fill(){//make k=(x2-x1)/(y2-y1)float k[PN]={0.0};for(inti=0;i!=PN;i++){k[i]=((float)(point[(i+1)%PN][0]-point[i][ 0])/(float)(point[(i+1)%PN][1]-point[i][1]));}//find min and max with selection sort.int min=point[0][1],max=min;for(inti=0;i!=PN;i++){if(point[i][1]>max){max=point[i][1];};;if( point[i][1]<min){max=point[i][1];}}//make scanning line liststd::vector<AE>*ET =new std::vector<AE>[max-min+1];//make ET//for(int i =0; i<PN;++i){//get ymin, ymaxint yminn=point[i][1]<point[(i+1)%PN][1]? i :(i+1)%PN;int ymaxn=point[i][1]>=point[(i+1)%PN][1]? i :(i+1)%PN;AE *tmp =newAE(point[yminn][0],k[i],point[ymaxn][1]);//insert nodeET[point[yminn][1]-min].push_back(*tmp);}//init AETstd::vector<AE> AET;for(int i=0;i!=max-min+1;i++){//insert node from ET to AETfor(int ii=0;ii!=ET[i].size();ii++){//sort with selection sort.AET.insert(std::upper_bound(AET.begin(),AET.end(),ET[i][ii],fill_comp),ET[i][ii]);}//delete y=ymax,"下闭上开"for(intii=0;ii!=AET.size();){if(i+min==AET[ii].ymax){AET.erase(AET.begin()+ii);}else{ii++;}}//draw{bool flag=false;for(int ii=0;ii!=AET.size();ii++){if(flag)fillline(i+min,(int)(AET[ii-1].x+0.5),(int)(AET[ii].x+0.5 ));//if(flag)std::cout<<i+min<<'\t'<<(int)(AET[ii].x+0.5)<<','<<(int)( AET[ii-1].x+0.5)<<'\n';flag=!flag;}}for(int ii=0;ii!=AET.size();ii++){AET[ii]++;} }delete[](ET);}void draw(){drawgrid(0.8,0.8,0.8);setcolor(1,0.5,0.5);fill();draweage(point,PN);}int main(int n,char*avg[]){init(n,avg,"L2");reinit(draw);loop();return0;}opengl.h#include <GL/glut.h>#define N 100#define GRIDSIZE 5int size=N*GRIDSIZE;void init(int argc,char** argv,char*title){//init openGLsize = N * GRIDSIZE;glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(10,10);glutInitWindowSize(size, size);glutCreateWindow(title);glClearColor(1.0, 1.0, 1.0, 1.0);//whiteglClear(GL_COLOR_BUFFER_BIT);glColor3f(0.0,0.0,0.0);//blackgluOrtho2D(0, size,0, size);}void reinit(void(*p)()){glutDisplayFunc(p);}void flush(){glFlush();}void loop(){glutMainLoop();}void clear(){glClearColor(1.0, 1.0, 1.0, 1.0);//whiteglClear(GL_COLOR_BUFFER_BIT);}void setcolor(double r,double g,double b){glColor3f(r, g, b);}void drawline(int x1,int y1,int x2,int y2){glBegin(GL_LINES);glVertex2i(x1, y1);glVertex2i(x2, y2);glEnd();flush();}void drawgrid(double r,double g,double b){int i =0;glColor3f(r, g, b);for(i =0;i !=N *GRIDSIZE;i +=GRIDSIZE){drawline(i, 0, i, size);}for(i =0;i !=N *GRIDSIZE;i +=GRIDSIZE){drawline(0, i, size, i);}flush();}void drawpoint(int x,int y){glPointSize((double)GRIDSIZE);glBegin(GL_POINTS);glVertex2i(x * GRIDSIZE, y * GRIDSIZE);glEnd();flush();}void draweage(int p[][2],int pn){if(pn<2)return;setcolor(0,0.8,0.8);for(int i=0;i!=pn-1;i++){drawline(p[i][0]*GRIDSIZE,p[i][1]*GRIDSIZE,p[i+1][0]*GRID SIZE,p[i+1][1]*GRIDSIZE);}drawline(p[pn-1][0]*GRIDSIZE,p[pn-1][1]*GRIDSIZE,p[0][0]* GRIDSIZE,p[0][1]*GRIDSIZE);}运行环境:ubuntu 13.10 + g++ 运行结果:。
实验二 有效边表填充算法

实验二有效边表填充算法20091104091 计算机科学与技术师范汉班丁仕钰1.实验目的:(1)设计有效边表结点和边表结点数据结构(2)设计有效边表填充算法(3)编程实现有效边表填充算法2.实验描述:下图 1 所示多边形覆盖了12 条扫描线,共有7 个顶点和7 条边。
7 个顶点分别为:P0(7,8),P1(3,12),P2(1,7),P3(3,1), P4(6,5), P5(8,1), P6(12,9)。
在1024×768 的显示分辩率下,将多边形顶点放大为P0(500,400),P1(350,600),P2(250,350),P3(350,50), P4(500,250), P5(600,50), P6(800,450)。
请使用有效边表算法填充该多边形。
图1示例多边形图2 屏幕显示多边形3.算法设计:4.源程序:(1)class AET{public:AET *next;double k;int yMax;double x;AET();virtual ~AET();};(2)#include "AET.h"class Bucket{public:Bucket *next;AET *p;int Scanline;Bucket();virtual ~Bucket();};(3) void CShiyan1View::AddEdge(AET *NewEdge){T1 = HeadE;if(T1 == NULL) //边表为空,将边表置为TempEdge{T1 = NewEdge;HeadE =T1;}else{while(T1->next!=NULL) //边表不为空,将TempEdge连在该边之后{T1 = T1->next;}T1->next = NewEdge;}}(4) void CShiyan1View::PolygonFill(){HeadE = NULL;for(CurrentB = HeadB;CurrentB!=NULL;CurrentB=CurrentB->next) //访问所有的桶节点{for(CurrentE = CurrentB->p;CurrentE!=NULL;CurrentE = CurrentE->next)//桶中所有边节点{AET * TempEdge = new AET;TempEdge->x = CurrentE->x;TempEdge->yMax = CurrentE->yMax;TempEdge->k = CurrentE->k;TempEdge->next = NULL;AddEdge(TempEdge); //将该边插入临时AET表}EdgeOrder(); //边表按照x递增的顺序存放T1 = HeadE; //根据yMax抛弃扫描完的边节点if(T1 == NULL){return;}while(CurrentB->Scanline>=T1->yMax) //放弃该节点,AET表指针后移,下闭上开{T1 = T1->next;HeadE = T1;if(HeadE == NULL){return;}}if(T1->next!=NULL){T2 = T1;T1 = T2->next;}while(T1!=NULL){if(CurrentB->Scanline>=T1->yMax) //跳过一个节点{T2->next = T1->next;T1->next = NULL;T1 = T2->next;}else{T2 = T1;T1 = T2->next;}}bool In =false; //设置一个bool变量In,初始值为假double xb,xe; //扫描线的起点和终点for(T1 = HeadE;T1!=NULL;T1=T1->next) //填充扫描线和多边形相交的区间{if(In == false){xb = T1->x;In =true; //每访问一个节点,把In值取反一次}else //如果In值为真,则填充从当前节点的x值开始到下一个节点的x值结束的区间{xe = T1->x-1; //左闭右开CClientDC dc(this);for(double x = xb;x<=xe;x++)dc.SetPixel(ROUND(x),CurrentB->Scanline,GetColor); //填充Sleep(1); //延时ms,提高填充过程的可视性In = false;}}for(T1 = HeadE;T1!=NULL;T1=T1->next) //边连贯性{T1->x = T1->x+T1->k;}}delete HeadB;delete HeadE;delete CurrentB;delete CurrentE;}(5) void CShiyan1View::EdgeOrder(){AET *F,*T;T1 = HeadE;if(T1 == NULL){return;}if(T1->next== NULL) //如果该边表没有再连接边{return;}else{F =HeadE->next;HeadE->next = NULL;while(F!=NULL){for (T=F, T1=HeadE; ((T1!=NULL) && (T1->x < T->x)); T2=T1, T1=T1->next);F = F->next;if(T1 == HeadE){HeadE = T;}else{T2->next = T;}T->next = T1;}}}(6) void CShiyan1View::Et(){for(int i=0;i<Number;i++) //访问每个顶点{CurrentB = HeadB; //从桶链表的头节点开始循环int j = i+1; //边的第二个顶点,Point[i]和Point[j]构成边if(j==Number) j=0; //保证多边形的闭合if(Point[j].y>Point[i].y) //终点比起点高{while(CurrentB->Scanline!=Point[i].y) //在桶内寻找该边的yMin{CurrentB = CurrentB->next; //移到下一个桶节点}E[i].x = Point[i].x; //计算AET表的值E[i].yMax = Point[j].y;E[i].k = (double(Point[j].x-Point[i].x))/(Point[j].y-Point[i].y);E[i].next = NULL;CurrentE = CurrentB->p; //获得桶上链接边表的地址if(CurrentB->p==NULL) //当前桶节点上没有链接边节点{CurrentE = &E[i]; //赋边的起始地址CurrentB->p=CurrentE; //第一个边节点直接连接到对应的桶中}else{while(CurrentE->next!=NULL) //如果当前边已有边节点{CurrentE = CurrentE->next; //移动指针到当前边的最后一个节点}CurrentE->next = &E[i]; //把当前边接上去}}if(Point[j].y<Point[i].y) //终点比起点低{while(CurrentB->Scanline!=Point[j].y){CurrentB = CurrentB->next;}E[i].x = Point[j].x;E[i].yMax = Point[i].y;E[i].k = (double(Point[i].x-Point[j].x))/(Point[i].y-Point[j].y);E[i].next = NULL;CurrentE = CurrentB->p;if(CurrentE == NULL){CurrentE=&E[i];CurrentB->p = CurrentE;}else{while(CurrentE->next!=NULL){CurrentE = CurrentE->next;}CurrentE->next=&E[i];}}}CurrentB = NULL;CurrentE = NULL;}(7) void CShiyan1View::CreatBucket(){ScanMax = ScanMin = Point[0].y;for(int i=1;i<Number;i++){if(Point[i].y<ScanMin){ScanMin = Point[i].y; //扫描线的最小值}if(Point[i].y>ScanMax){ScanMax = Point[i].y; //扫描线的最大值}}for( i=ScanMin;i<=ScanMax;i++) //建立桶节点{if(ScanMin == i) //桶头结点{HeadB = new Bucket; //建立桶的头结点CurrentB = HeadB; //CurrentB为Bucket当前节点指针CurrentB->Scanline = ScanMin;CurrentB->p = NULL; //没有连接边链表CurrentB->next = NULL;}else{ //建立桶的其他节点CurrentB->next = new Bucket; //新建一个桶节点CurrentB = CurrentB->next; //使CurrentB指向新建的桶节点CurrentB->Scanline = i;CurrentB->p = NULL; //没有连接边链表CurrentB->next = NULL;}}}(8) void CShiyan1View::OnDraw(CDC* pDC){AfxGetMainWnd()->SetWindowText(":有效边表填充算法");CShiyan1Doc* pDc = GetDocument();ASSERT_V ALID(pDc);CShiyan1Doc* pDoc = GetDocument();ASSERT_V ALID(pDoc);// TODO: add draw code for native data here//Cshiyan1Doc *pDoc = GetDocument();ASSERT_V ALID(pDoc);if (!pDoc)return;// TODO: 在此处为本机数据添加绘制代码pDC->Polygon(Point,7); //绘制多边形pDC->TextOut(550,410,_T("P0")); //注意文本的输出pDC->TextOut(350,600,_T("P1"));pDC->TextOut(230,340,_T("P2"));pDC->TextOut(350,30,_T("P3"));pDC->TextOut(490,220,_T("P4"));pDC->TextOut(600,30,_T("P5"));pDC->TextOut(805,450,_T("P6"));}(9) void CShiyan1View::OnTianchong(){// TODO: Add your command handler code hereCColorDialog ccd(GetColor);if(ccd.DoModal() == IDOK){GetColor = ccd.GetColor();}RedrawWindow();CreatBucket();Et();PolygonFill();}5.运行结果:(屏幕截图)。
有序边表算法

else
j=k+1; /*当前顶点不是最后一个顶点,下一个顶点为数组下标加一*/
while(pts[k].y==pts[j].y)
/*扫描线扫过平行顶点,需分情况找到当前顶点下下个顶点*/
if((j+1)>(cnt-1))
j=0;
else
j++;
return(pts[j].y); /*返回下一个顶点的y值 */
① 对每一条扫描线i,初始化ET表的表头指针ET[i];
② 将ymax = i的边放入ET[i]中;
③ 使y =多边形最低的扫描线号;
④ 初始化活性边表AET为空;
⑤ 循环,直到AET和ET为空。
将新边表ET中对应y值的新边节点插入到AET表。
遍历AET表,将两两配对的交点之间填充给定颜色值。
遍历AET表,将 ymax= y的边节点从AET表中删除,并将ymax> y的各边节点的x值递增Δx;并重新排序。y增加1。
3. ymax -该边最高顶点相交的扫描线号。
每条扫描线的活性边表中的活性边节点按照各活性边与扫描线交点的x值递增排序连接在一起。
当扫描线y移动到下一条扫描线y = y+1时,活性边表需要更新,即删去不与新扫描线相交的多边形边,同时增加与新扫描线相交的多边形边,并根据增量法重新计算扫描线与各边的交点x。当多边形新边表ET构成后,按下列步骤进行:
}
/* 计算增量,修改AET*/ /*生成边表结点,并插入到边表中的主体函数*/
void MakeEdgeRec(POINT lower,POINT upper,int yComp,Edge *edge,Edge
*edges[])
/*把边结点edge,放到lower.y扫描线所在的边结点指针数组edges[]中 */
多边形的边缘填充算法

多边形的边缘填充算法1.实验目的:在一个区域的内部填上不同的灰度或色彩2试验步骤:实验基本思想:逐边向右求补。
可以按任意顺序处理多边形的每条边。
在处理每条边时,首先求出该边与扫描线的交点,然后将每一条扫描线上交点右方的所有像素取补。
多边形的所有边处理完毕之后,填充即完成。
3实验程序(算法思想):1、找出扫描线的范围2、建立边角桶(1)建立空桶(2)遍历多边形各边,根据边的r较小端输入桶中。
3、扫描填充#include "ggltools.h"void gltRasterText(double x, double y, const char *text, void *font){if(text == NULL) return ;glRasterPos2d(x, y);for(int i=0; text[i] != '\0'; i++){glutBitmapCharacter(font, text[i]);}}void gltLine2d(double x0, double y0, double x1, double y1){glBegin(GL_LINES);glVertex2d(x0, y0);glVertex2d(x1, y1);glEnd();}void gltRect2d(double x0, double y0, double x1, double y1)glBegin(GL_LINE_STRIP);glVertex2d(x0, y0);glVertex2d(x1, y0);glVertex2d(x1, y1);glVertex2d(x0, y1);glVertex2d(x0, y0);glEnd();}char gltClipCode(const GPoint2d &pt, const GPoint2d &top, const GPoint2d &bottom) {char code = 0;if(pt.y() > top.y()) code |= 0x01;else if(pt.y() < bottom.y()) code |= 0x02;if(pt.x() > bottom.x()) code |= 0x04;else if(pt.x() < top.x()) code |= 0x08;return code;}template <class T>void swap(T &a , T &b){T t =a;a=b;b=t;}bool gltLineClip2d(GPoint2d &pt0, GPoint2d &pt1,const GPoint2d &top, const GPoint2d &bottom){char c0,c1;double x,y;while (true){c0=gltClipCode(pt0,top,bottom);c1=gltClipCode(pt1,top,bottom);if (c0 & c1) return false;if (c0==0&&c1==0)return true;if(c0==0){swap(pt0,pt1);swap(c0,c1);}if(c0 & 0x01)//点在yt 上方;{y=top.y();x=pt0.x()+(y-pt0.y())*(pt1.x()-pt0.x())/(pt1.y()-pt0.y());}else if (c0 & 0x02){y=bottom.y();x=pt0.x()+(y-pt0.y())*(pt1.x()-pt0.x())/(pt1.y()-pt0.y());}else if(c0 & 0x04){x=bottom.x();y=pt0.y()+(x-pt0.x())*(pt1.y()-pt0.y())/(pt1.x()-pt0.x());}else if(c0 & 0x08){x=top.x();y=pt0.y()+(x-pt0.x())*(pt1.y()-pt0.y())/(pt1.x()-pt0.x());}pt0.set(x,y);}return false;}4.实验输出结果:。
《计算机图形学》有序边表填充算法资料讲解

《计算机图形学》有序边表填充算法实验报告一、实验目的1、掌握有序边表算法填充多边形区域;2、理解多边形填充算法的意义;3、增强C语言编程能力。
二、算法原理介绍根据多边形内部点的连续性知:一条扫描线与多边形的交点中,入点和出点之间所有点都是多边形的内部点。
所以,对所有的扫描线填充入点到出点之间所有的点就可填充多边形。
判断扫描线上的点是否在多边形之内,对于一条扫描线,多边形的扫描转换过程可以分为四个步骤:(1)求交:计算扫描线与多边形各边的交点;(2)排序:把所有交点按x值递增顺序排序;(3)配对:第一个与第二个,第三个与第四个等等;每对交点代表扫描线与多边形的一个相交区间;(4)着色:把相交区间内的象素置成多边形颜色,把相交区间外的象素置成背景色。
p1,p3,p4,p5属于局部极值点,要把他们两次存入交点表中。
如扫描线y=7上的交点中,有交点(2,7,13),按常规方法填充不正确,而要把顶点(7,7)两次存入交点表中(2,7,7,13)。
p2,p6为非极值点,则不用如上处理。
为了提高效率,在处理一条扫描线时,仅对与它相交的多边形的边进行求交运算。
把与当前扫描线相交的边称为活性边,并把它们按与扫描线交点x坐标递增的顺序存放在一个链表中,称此链表为活性边表(AET)。
对每一条扫描线都建立一个与它相交的多边形的活性边表(AET)。
每个AET的一个节点代表一条活性边,它包含三项内容1.x -当前扫描线与这条边交点的x坐标;2.Δx -该边与当前扫描线交点到下一条扫描线交点的x增量;3.ymax -该边最高顶点相交的扫描线号。
每条扫描线的活性边表中的活性边节点按照各活性边与扫描线交点的x值递增排序连接在一起。
当扫描线y移动到下一条扫描线y = y+1时,活性边表需要更新,即删去不与新扫描线相交的多边形边,同时增加与新扫描线相交的多边形边,并根据增量法重新计算扫描线与各边的交点x。
当多边形新边表ET构成后,按下列步骤进行:①对每一条扫描线i,初始化ET表的表头指针ET[i];②将ymax = i的边放入ET[i]中;③使y =多边形最低的扫描线号;④初始化活性边表AET为空;⑤循环,直到AET和ET为空。
计算机图形学课程设计报告报告实验报告

《计算机图形学》实验报告班级计算机科学与技术姓名学号2014 年6 月2 日实验一基本图形生成算法一、实验目的:1、掌握中点Bresenham绘制直线的原理;2、设计中点Bresenham算法;3、掌握八分法中点Bresenham算法绘制圆的原理;4、设计八分法绘制圆的中点Bresenham算法;5、掌握绘制1/4椭圆弧的上半部分和下半部分的中点Bresenham算法原理;6、掌握下半部分椭圆偏差判别式的初始值计算方法;7、设计顺时针四分法绘制椭圆的中点Bresenham算法。
二、实验过程:1、实验描述实验1:使用中点Bresenham算法绘制斜率为0<=k<=1的直线。
实验2:使用中点Bresenham算法绘制圆心位于屏幕客户区中心的圆。
实验3:使用中点Bresenham算法绘制圆心位于屏幕客户区中心的椭圆。
2、实验过程1)用MFC(exe)建立一个单文档工程;2)编写对话框,生成相应对象,设置相应变量;3)在类CLineView中声明相应函数,并在相关的cpp文件中实现;4)在OnDraw()函数里调用函数实现绘制直线、圆、椭圆;5)运行程序,输入相应值,绘制出图形。
三、源代码实验1:直线中点Bresenham算法1.// cline.cpp : implementation file// cline dialogcline::cline(CWnd* pParent /*=NULL*/): CDialog(cline::IDD, pParent){//{{AFX_DATA_INIT(cline)m_x0 = 0;m_y0 = 0;m_x1 = 0;m_y1 = 0;//}}AFX_DATA_INIT}void cline::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(cline)DDX_Text(pDX, IDC_x0, m_x0);DDX_Text(pDX, IDC_y0, m_y0);DDX_Text(pDX, IDC_x1, m_x1);DDX_Text(pDX, IDC_y1, m_y1);//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(cline, CDialog)//{{AFX_MSG_MAP(cline)//}}AFX_MSG_MAPEND_MESSAGE_MAP()2、// LineView.hclass CLineView : public CView{public:CLineDoc* GetDocument();..........void Mbline(double,double,double,double); //直线中点Bresenham函数.......}3、// Line.cpp//*******************直线中点Bresenham函数*********************/void CLineView::Mbline(double x0, double y0, double x1, double y1) {CClientDC dc(this);COLORREF rgb=RGB(0,0,255); //定义直线颜色为蓝色double x,y,d,k;x=x0; y=y0; k=(y1-y0)/(x1-x0); d=0.5-k;for(x=x0;x<=x1;x++){dc.SetPixel((int)x,(int)y,rgb);if(d<0){y++;d+=1-k;}elsed-=k;}}4、//LineView.cppvoid CLineView::OnDraw(CDC* pDC){CLineDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data herecline a;a.DoModal();//初始化CLineView::Mbline(a.m_x0,a.m_y0,a.m_x1,a.m_y1); }实验2:圆中点Bresenham算法1、//cricle.cpp// Ccricle dialogCcricle::Ccricle(CWnd* pParent /*=NULL*/): CDialog(Ccricle::IDD, pParent){//{{AFX_DATA_INIT(Ccricle)m_r = 0;//}}AFX_DATA_INIT}void Ccricle::DoDataExchange(CDataExchange* pDX) {CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(Ccricle)DDX_Text(pDX, r_EDIT, m_r);//}}AFX_DATA_MAP}2、//CcircleView.hclass CCcircleView : public CView{.......public:CCcircleDoc* GetDocument();void CirclePoint(double,double); //八分法画圆函数void Mbcircle(double); //圆中点Bresenham函数........}3、//CcircleView.cppvoid CCcircleView::OnDraw(CDC* pDC){CCcircleDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCcricle r;r.DoModal();CCcircleView::Mbcircle(r.m_r);//画圆}4、//CcircleView.cpp//*******************八分法画圆*************************************/ void CCcircleView::CirclePoint(double x,double y){CClientDC dc(this);COLORREF rgb=RGB(0,0,255);dc.SetPixel((int)(300+x),(int)(300+y),rgb);dc.SetPixel((int)(300-x),(int)(300+y),rgb);dc.SetPixel((int)(300+x),(int)(300-y),rgb);dc.SetPixel((int)(300-x),(int)(300-y),rgb);dc.SetPixel((int)(300+y),(int)(300+x),rgb);dc.SetPixel((int)(300-y),(int)(300+x),rgb);dc.SetPixel((int)(300+y),(int)(300-x),rgb);dc.SetPixel((int)(300-y),(int)(300-x),rgb);}//**************************圆中点Bresenham函数*********************/ void CCcircleView::Mbcircle(double r){double x,y,d;COLORREF rgb=RGB(0,0,255);d=1.25-r;x=0;y=r;for(x=0;x<y;x++){CirclePoint(x,y); //调用八分法画圆子函数if(d<0)d+=2*x+3;else{d+=2*(x-y)+5;y--;}}}实验3:椭圆中点Bresenham算法1、//ellipse1.cpp// Cellipse dialogCellipse::Cellipse(CWnd* pParent /*=NULL*/) : CDialog(Cellipse::IDD, pParent){//{{AFX_DATA_INIT(Cellipse)m_a = 0;m_b = 0;//}}AFX_DATA_INIT}void Cellipse::DoDataExchange(CDataExchange* pDX) {CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(Cellipse)DDX_Text(pDX, IDC_EDIT1, m_a);DDX_Text(pDX, IDC_EDIT2, m_b);//}}AFX_DATA_MAP}2、//EllipseView.hclass CEllipseView : public CView{......................public:CEllipseDoc* GetDocument();void EllipsePoint(double,double); //四分法画椭圆void Mbellipse(double a, double b); //椭圆中点Bresenham函数..................}3、//Ellipse.cpp//*****************四分法画椭圆********************************/void CEllipseView::EllipsePoint(double x,double y){CClientDC dc(this);COLORREF rgb=RGB(0,0,255);dc.SetPixel((int)(300+x),(int)(300+y),rgb);dc.SetPixel((int)(300-x),(int)(300+y),rgb);dc.SetPixel((int)(300+x),(int)(300-y),rgb);dc.SetPixel((int)(300-x),(int)(300-y),rgb);}//************************椭圆中点Bresenham函数*********************/ void CEllipseView::Mbellipse(double a, double b){double x,y,d1,d2;x=0;y=b;d1=b*b+a*a*(-b+0.25);EllipsePoint(x,y);while(b*b*(x+1)<a*a*(y-0.5))//椭圆AC弧段{if(d1<0)d1+=b*b*(2*x+3);else{d1+=b*b*(2*x+3)+a*a*(-2*y+2);y--;}x++;EllipsePoint(x,y);}d2=b*b*(x+0.5)*(x+0.5)+a*a*(y-1)*(y-1)-a*a*b*b;//椭圆CB弧段while(y>0){if(d2<0){d2+=b*b*(2*x+2)+a*a*(-2*y+3);x++;}elsed2+=a*a*(-2*y+3);y--;EllipsePoint(x,y);}}4、//EllipseView.cppvoid CEllipseView::OnDraw(CDC* pDC){CEllipseDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCellipse el;el.DoModal();//初始化CEllipseView::Mbellipse(el.m_a, el.m_b);//画椭圆}四、实结果验实验1:直线中点Bresenham算法实验2:圆中点Bresenham 算法实验3:椭圆中点Bresenham 算法实验二有效边表填充算法一、实验目的:1、设计有效边表结点和边表结点数据结构;2、设计有效边表填充算法;3、编程实现有效边表填充算法。
实验二 有效边表填充算法

实验二有效边表填充算法1.实验目的:设计有效边表结点和边表结点数据结构设计有效边表填充算法编程实现有效边表填充算法2.实验描述:下图1 所示多边形覆盖了12 条扫描线,共有7 个顶点和7 条边。
7 个顶点分别为:P0(7,8),P1(3,12),P2(1,7),P3(3,1), P4(6,5), P5(8,1), P6(12,9)。
在1024×768 的显示分辩率下,将多边形顶点放大为P0(500,400),P1(350,600),P2(250,350),P3(350,50), P4(500,250), P5(600,50), P6(800,450)。
请使用有效边表算法填充该多边形。
图1示例多边形图2 屏幕显示多边形3.算法设计:4.源程序:1)//AET.h和AET..cppclass AET{}2)//Bucket.h和Bucket.cppclass Bucket{}3) // TestView.h#include "AET.h"//包含有效边表类#include "Bucket.h"//包含桶类#define Number 7//N为闭合多边形顶点数,顶点存放在整型二维数组Point[N]中class CTestView : public CView{。
public:void PolygonFill();//上闭下开填充多边形void CreatBucket();//建立桶结点桶void Et();//构造边表void AddEdge(AET *);//将边插入AET表void EdgeOrder();//对AET表进行排序。
protected:COLORREF GetColor;//调色板CPoint Point[7];//定义多边形Bucket *HeadB,*CurrentB;//桶的头结点和当前结点AET E[Number],*HeadE,*CurrentE,*T1,*T2;//有效边表的结点4)// TestView.cppCTestView::CTestView(){//设置多边形的7个顶点Point[0]=CPoint(550,400);//P0Point[1]=CPoint(350,600);//P1Point[2]=CPoint(250,350);//P2Point[3]=CPoint(350,50);//P3Point[4]=CPoint(500,250);//P4Point[5]=CPoint(600,50);//P5Point[6]=CPoint(800,450);//P6}void CTestView::OnDraw(CDC* pDC){CTestDoc* pDoc = GetDocument();ASSERT_V ALID(pDoc);pDC->Polygon(Point,7);//绘制多边形//输出多边形的顶点编号pDC->TextOut(550,410,"P0");pDC->TextOut(350,600,"P1");pDC->TextOut(230,340,"P2");pDC->TextOut(350,30,"P3");pDC->TextOut(490,220,"P4");pDC->TextOut(600,30,"P5");pDC->TextOut(805,450,"P6");}void CTestView::OnMenuAET() //菜单函数{AfxGetMainWnd()->SetWindowText("多边形有效边表填充算法");//显示标题CColorDialog ccd(GetColor);if(ccd.DoModal()==IDOK)//调用调色板选取前景色{GetColor=ccd.GetColor();}RedrawWindow();//刷新屏幕CreatBucket();//初始化桶Et();//建立边表PolygonFill();//多边形填充}void CTestView::CreatBucket()//初始化桶{}void CTestView::Et()//构造边表{}void CTestView::AddEdge(AET *NewEdge)//插入临时边表函数{}void CTestView::EdgeOrder()//对边表进行排序函数{}void CTestView::PolygonFill()//多边形填充函数{}5.运行结果:(屏幕截图)。
计算机图形学-实验报告2-多边形有效边表填充算法

(9)如果甬结点的扫描线值大于等于有效边表中的结点值ymax,则该边为无效边。
(10)当甬结点不为空则转(6)否则删除甬表和边表的头结点,算法结束。
(11)实验结果及分析:
实验地点
软件实验室
指导教师
(3)动态链表的排序算法
二、实验内容:
三、自定义屏幕二维坐标系,原点位于客户区中心,x轴水平向右为正,y轴垂直向上为正。
四、在屏幕客户区内使用cline类绘制示例多边形边界。
五、设置屏幕背景色为白死,调用windows的颜色对话框选择填充色使用单一颜色填充多边形。
六、使用有效边表填充算法填充示例多边形内部及边界。
(5)对每个甬结点链接的边表,根据x|ymin值的大小进行排序,若x|ymin相等,则按照k由小到大排序。
(6)循环访问每个甬结点,将甬内每个结点的边表合并成有效边表,并循环访问有限边表。
(7)从有效边表中取出扫描线上相邻两条边的结点对进行配对。填充时设置一个逻辑变量binflag,每访问一个结点,把binflag值取反一次,若binflag为真,则把从当前结点的x值开始到下一结点x值结束的区间用指定的颜色填充。
七、实验步骤:
(1)调用颜色对话框读取填充色。
(2)根据示例多边形顶点坐标值,计算扫描线的最大值ScanMax和最小值ScanMin。
(3)用多边形覆盖的扫描线动态建立甬结点。
(4)循环访问多边形的所有顶点,根据边的顶点y值比起点y值高或边的终点y值比起点y值低两种情况,计算每条边的ymin。在甬中寻找与该ymin相对应的甬结点计算该边表示的x|ymin,ymax,k,并依据次链接该边表结点到甬结点。
边填充算法_计算机图形学实用教程(第3版)_[共2页]
![边填充算法_计算机图形学实用教程(第3版)_[共2页]](https://img.taocdn.com/s3/m/73b3d3fdcfc789eb162dc88e.png)
68图3-26 各条扫描线的活性边表例如,扫描线0.5的y桶为空,则该扫描线对应的活性边表为空。
而扫描线1.5的y桶不为空,则将扫描线1.5的y桶指向的新边表插入到扫描线1.5对应的活性边表中。
在建立扫描线2.5的y桶时,首先检查是否有旧边删除,由于y = 2.5,大于扫描线1.5的活性边表中的y max,所以将边P1P2的结点信息从扫描线2.5的活性边表中删除;然后对未删除的P2P3边结点信息进行更新,即按照x = x + ∆x更新其中的x值;最后检查是否有新边插入,由于扫描线2.5的y桶不为空,所以将扫描线2.5的y桶指向的新边表中的结点信息按x值由小到大的顺序插入到扫描线2.5的活性边表中。
依此类推,当处理完所有的扫描线并建立相应的活性边表后,对每一条扫描线,依次从活性边表中成对地取出交点,并激活相应的像素。
其填充结果如图3-24所示。
3.4.4 边填充算法有序边表算法是一个有效的多边形填充算法,它将扫描转换过程中的计算种类减少,将求交计算方法简化,而且由于对每个显示的像素只访问一次,因此对于帧缓存输入输出的要求可降低为最小。
此外,由于算法与输入输出的具体操作无关,因此算法与设备也无关。
算法的主要缺点是数据结构复杂,表的维护和排序的开销较大,不适合硬件实现。
本小节要介绍的边填充算法无需复杂的链表结构,并且特别适合于有帧缓冲存储器的显示器。
1.简单的边填充算法边填充算法的基本思想是,对每一条与多边形相交的中心扫描线,将像素中心位于交点右方的全部像素取补(即异或写)。
屏幕像素的异或写操作的特点就是,第一次异或写操作,像素被置成前景色,第二次异或写操作,像素恢复为背景色。
算法的具体描述为:对于每一条与多边形相交的扫描线,计算中心扫描线与边的交点,设其交点为(x1, y1),将像素中心位于(x1, y1)右方即满足x+0.5>x1的全部像素取补(相当于异或写操作)。
对多边形的每一条边分别应用上述算法,处理的顺序可以是任意的,当所有的边都处理完以后,即可得到填充后的多边形。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验二有效边表填充算法
1.实验目的:
设计有效边表结点和边表结点数据结构
设计有效边表填充算法
编程实现有效边表填充算法
2.实验描述:
下图1 所示多边形覆盖了12 条扫描线,共有7 个顶点和7 条边。
7 个顶点分别为:P0(7,8),P1(3,12),P2(1,7),P3(3,1), P4(6,5), P5(8,1), P6(12,9)。
在1024×768 的显示分辩率下,将多边形顶点放大为P0(500,400),P1(350,600),P2(250,350),P3(350,50), P4(500,250), P5(600,50), P6(800,450)。
请使用有效边表算法填充该多边形。
图1示例多边形
图2 屏幕显示多边形
3.算法设计:
4.源程序:
1)//AET.h和AET..cpp
class AET
{
}
2)//Bucket.h和Bucket.cpp
class Bucket
{
}
3) // TestView.h
#include "AET.h"//包含有效边表类
#include "Bucket.h"//包含桶类
#define Number 7//N为闭合多边形顶点数,顶点存放在整型二维数组Point[N]中class CTestView : public CView
{。
public:
void PolygonFill();//上闭下开填充多边形
void CreatBucket();//建立桶结点桶
void Et();//构造边表
void AddEdge(AET *);//将边插入AET表
void EdgeOrder();//对AET表进行排序。
protected:
COLORREF GetColor;//调色板
CPoint Point[7];//定义多边形
Bucket *HeadB,*CurrentB;//桶的头结点和当前结点
AET E[Number],*HeadE,*CurrentE,*T1,*T2;//有效边表的结点
4)// TestView.cpp
CTestView::CTestView()
{
//设置多边形的7个顶点
Point[0]=CPoint(550,400);//P0
Point[1]=CPoint(350,600);//P1
Point[2]=CPoint(250,350);//P2
Point[3]=CPoint(350,50);//P3
Point[4]=CPoint(500,250);//P4
Point[5]=CPoint(600,50);//P5
Point[6]=CPoint(800,450);//P6
}
void CTestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_V ALID(pDoc);
pDC->Polygon(Point,7);//绘制多边形
//输出多边形的顶点编号
pDC->TextOut(550,410,"P0");
pDC->TextOut(350,600,"P1");
pDC->TextOut(230,340,"P2");
pDC->TextOut(350,30,"P3");
pDC->TextOut(490,220,"P4");
pDC->TextOut(600,30,"P5");
pDC->TextOut(805,450,"P6");
}
void CTestView::OnMenuAET() //菜单函数
{
AfxGetMainWnd()->SetWindowText("多边形有效边表填充算法");//显示标题CColorDialog ccd(GetColor);
if(ccd.DoModal()==IDOK)//调用调色板选取前景色
{
GetColor=ccd.GetColor();
}
RedrawWindow();//刷新屏幕
CreatBucket();//初始化桶
Et();//建立边表
PolygonFill();//多边形填充
}
void CTestView::CreatBucket()//初始化桶
{
}
void CTestView::Et()//构造边表
{
}
void CTestView::AddEdge(AET *NewEdge)//插入临时边表函数{
}
void CTestView::EdgeOrder()//对边表进行排序函数
{
}
void CTestView::PolygonFill()//多边形填充函数
{
}
5.运行结果:(屏幕截图)。