1、有效边表填充算法实验二 有效边表填充算法实验题目: 有效边表填充算法 学号: 姓名: 班级: 指导老师: 完成日期: 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)。在 1024768 的显示分辩率下,将多边形顶点放大为 P0(500,400) ,P1(350,600) ,P2(250,350),P3(350,50),
2、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; in
3、t yMax; double k; /代替1/k AET *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为闭合多边形顶点数,顶点存放在整型二维数组PointN中class CTestView : public CView。public: void Po
4、lygonFill();/上闭下开填充多边形 void CreatBucket();/建立桶结点桶 void Et();/构造边表 void AddEdge(AET *);/将边插入AET表 void EdgeOrder();/对AET表进行排序 。protected: COLORREF GetColor;/调色板 CPoint Point7;/定义多边形 Bucket *HeadB,*CurrentB;/桶的头结点和当前结点 AET ENumber,*HeadE,*CurrentE,*T1,*T2;/有效边表的结点4)/ TestView.cppCTestView:CTestView() /
5、设置多边形的7个顶点 Point0=CPoint(550,400);/P0 Point1=CPoint(350,600);/P1 Point2=CPoint(250,350);/P2 Point3=CPoint(350,50);/P3 Point4=CPoint(500,250);/P4 Point5=CPoint(600,50);/P5 Point6=CPoint(800,450);/P6void CTestView:OnDraw(CDC* pDC) CTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDC-Polygon(Point,7
6、);/绘制多边形 /输出多边形的顶点编号 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(GetColo
7、r); if(ccd.DoModal()=IDOK)/调用调色板选取前景色 GetColor=ccd.GetColor(); RedrawWindow();/刷新屏幕 CreatBucket();/初始化桶 Et();/建立边表 PolygonFill();/多边形填充 void CTestView:CreatBucket()/初始化桶 int ScanMin,ScanMax;/确定扫描线的最小值和最大值 ScanMax=ScanMin=Point0.y; for(int i=1;iNumber;i+) if(Pointi.yScanMax) ScanMax=Pointi.y;/扫描线的最大值
8、 for(i=ScanMin;iScanLine=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; void CTestView:Et()/构造边表 for(int i=0;iPointi.y)/终点比起点高 while(Curr
9、entB-ScanLine!=Pointi.y)/在桶内寻找该边的yMin CurrentB=CurrentB-next;/移到下一个桶结点 Ei.x=Pointi.x;/计算AET表的值 Ei.yMax=Pointj.y; Ei.k=double(Pointj.x-Pointi.x)/(Pointj.y-Pointi.y);/代表1/k Ei.next=NULL; CurrentE=CurrentB-p;/获得桶上链接边表的地址 if(CurrentB-p=NULL)/当前桶结点上没有链接边结点 CurrentE=&Ei;/赋边的起始地址 CurrentB-p=CurrentE;/第一个边结
10、点直接连接到对应的桶中 else while(CurrentE-next!=NULL)/如果当前边已连有边结点 CurrentE=CurrentE-next;/移动指针到当前边的最后一个边结点 CurrentE-next=&Ei;/把当前边接上去 if(Pointj.yScanLine!=Pointj.y) CurrentB=CurrentB-next; Ei.x=Pointj.x; Ei.yMax=Pointi.y; Ei.k=double(Pointi.x-Pointj.x)/(Pointi.y-Pointj.y); Ei.next=NULL; CurrentE=CurrentB-p; i
11、f(CurrentE=NULL) CurrentE=&Ei; CurrentB-p=CurrentE; else while(CurrentE-next!=NULL) CurrentE=CurrentE-next; CurrentE-next=&Ei; CurrentB=NULL; CurrentE=NULL;void CTestView:AddEdge(AET *NewEdge)/插入临时边表函数 T1=HeadE; if(T1=NULL)/边表为空,将边表置为TempEdge T1=NewEdge; HeadE=T1; else while(T1-next!=NULL)/边表不为空,将Te
12、mpEdge连在该边之后 T1=T1-next; T1-next=NewEdge; void CTestView:EdgeOrder()/对边表进行排序函数 T1=HeadE; if(T1=NULL) return; if(T1-next=NULL)/如果该边表没有再连边表 return;/桶结点只有一条边,不需要排序 else if(T1-next-xx)/边表按x值排序 T2=T1-next; T1-next=T2-next; T2-next=T1; HeadE=T2; T2=HeadE; T1=HeadE-next; while(T1-next!=NULL)/继续两两比较相连的边表的x值
13、,进行排序 if(T1-next-xx) T2-next=T1-next; T1-next=T1-next-next; T2-next-next=T1; T2=T2-next; else T2=T1; T1=T1-next; void CTestView:PolygonFill()/多边形填充函数 HeadE=NULL; for(CurrentB=HeadB;CurrentB!=NULL;CurrentB=CurrentB-next)/访问所有桶结点 for(CurrentE=CurrentB-p;CurrentE!=NULL;CurrentE=CurrentE-next)/访问桶中排序前的边
14、结点 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
15、; 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
16、) xb=T1-x; In=true;/每访问一个结点,把In值取反一次 else/如果In值为真,则填充从当前结点的x值开始到下一结点的x值结束的区间 xe=T1-x-1;/左闭右开 CClientDC dc(this); for(double x=xb;xScanLine,GetColor);/填充语句 Sleep(1);/延时1ms,提高填充过程的可视性 In=FALSE; for(T1=HeadE;T1!=NULL;T1=T1-next)/边连贯性 T1-x=T1-x+T1-k;/x=x+1/k delete HeadB; delete CurrentB; delete CurrentE; delete HeadE;5.运行结果:(屏幕截图)
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1