图形学实验报告四 多边形填充算法
计算机图形学图形区域填充效果
// Fill.cpp : implementation file
#include "stdafx.h"
#include "FloodFill.h"
#include "Fill.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
(1)种子填充算法原理
在多边形内部找到一个已知的象素点作为种子点,由此开始,利用区域的连通性找到多边形内部的 其它所有象素点进行填充。
(i)四向连通区域
①四向连通区域概念:从区域上任一点出发,在不超出区域边界的前提下,可通过4个方向:上、下、左、右的移动组合到达区域中的任意象素点,称此区域为四向连通区域。
{
//有需要填充的区域
if(spanNeedFill==FALSE)
{
spanNeedFill = TRUE;
}
x++;
}
if(spanNeedFill)
{
CPoint rightp(x-1,y);
stack.Push(x-1);
stack.Push(y);
spanNeedFill = FALSE;
virtual ~CStack();
};
#endif // !defined(AFX_STACK_H__D198F788_4ED1_4C09_98E5_433BAB24D864__INCLUDED_)
CStack.cpp参考代码:
// Stack.cpp: implementation of the CStack class.
#if !defined(AFX_STACK_H__D198F788_4ED1_4C09_98E5_433BAB24D864__INCLUDED_) #define AFX_STACK_H__D198F788_4ED1_4C09_98E5_433BAB24D864__INCLUDED_
多边形的填充实验经典
试验实验一:图形的区域填充一、实验目的区域填充是指先将区域内的一点(常称为种子点)赋予给定颜色,然后将这种颜色扩展到整个区域内的过程。
区域填充技术广泛应用于交互式图形、动画和美术画的计算机辅助制作中。
本实验采用递归填充算法或打描线算法实现对光栅图形的区域填充。
通过本实验,可以掌握光栅图形编程的基本原理和方法。
实验内容掌握光栅图形的表示方法,实现种子算法或扫描线算法。
通过程序设计实现上述算法。
建议采用VC++实现OpenGL程序设计。
三、实验原理、方法和手段递归算法在要填充的区域内取一点(X, Y)的当前颜色记为oldcoloo用要填充的颜色ne wcolor去取代,递归函数如下:procedure flood-fill(XXoldcoloLnewcolor:integer); beginif getpixel(fiainebufier,x,y)=oldcolorthen beginsetpixel(fiamebuffer,x,y,newcolor); flood-fill(X.Y+1 .oldcoloLiiewcolor);flood-fill(X.Y^ 1 ,oldcoloi;newcolor); flood-fill(X-l,Y;oldcoloi;newcolor); flood-fill(X+l,Yoldcoloi;newcolor);endend扫描线算法扫描线算法的效率明显高于递归算法,其算法的基本思想如下:(1)(初始化)将算法设置的堆栈置为空,将给定的种子点(x,y)压入堆栈。
(2)(出栈)如果堆栈为空,算法结束;否则取栈顶元素(x,y)作为种子点。
(3)(区段填充)从种子点(x,y)开始沿纵坐标为y的当前扫描线向左右两个方向逐个象素进行填色,其值置为newcoloi;直到抵达边界为止。
(4)(定范围)以XleA和Xn血分别表示在步骤3中填充的区段两端点的横坐标。
(5)(进栈)分别在与当前扫描线相邻的上下两条打描线上,确定位于区间[Xldb Xn 曲]内的给定区域的区段。
图形学实验报告
图形学实验报告图形学实验报告概述:在本次图形学实验中,我们将探索和学习计算机图形学的基本概念和技术。
通过实验,我们深入了解了图形学的原理和应用,以及如何使用计算机生成和处理图像。
实验一:像素和颜色在这个实验中,我们学习了图像是由像素组成的,每个像素都有自己的颜色值。
我们使用了Python编程语言和PIL库来创建一个简单的图像,并设置了不同的像素颜色。
通过改变像素的颜色值,我们可以创建出各种各样的图像效果。
实验二:坐标系统和变换在这个实验中,我们学习了坐标系统和图形变换。
我们使用OpenGL库来创建一个简单的二维图形,并通过平移、旋转和缩放等变换操作来改变图形的位置和形状。
这些变换操作使我们能够在屏幕上创建出各种不同的图案和效果。
实验三:线段和多边形在这个实验中,我们学习了如何使用线段和多边形来绘制图形。
我们使用了Bresenham算法来绘制直线,并学习了如何使用多边形填充算法来填充图形。
通过这些技术,我们可以创建出更加复杂和精细的图像。
实验四:光照和阴影在这个实验中,我们学习了光照和阴影的原理和应用。
我们使用了光照模型来模拟光线的传播和反射,以及计算物体的明暗效果。
通过调整光照参数和材质属性,我们可以创建出逼真的光照和阴影效果。
实验五:纹理映射和渲染在这个实验中,我们学习了纹理映射和渲染的概念和技术。
我们使用了纹理映射来将图像贴到三维物体表面,以增加物体的细节和真实感。
通过渲染技术,我们可以模拟光线的折射和反射,以及创建出逼真的材质效果。
实验六:三维建模和动画在这个实验中,我们学习了三维建模和动画的基本原理和方法。
我们使用了三维建模工具来创建三维模型,并学习了如何使用关键帧动画来实现物体的运动和变形。
通过这些技术,我们可以创建出逼真的三维场景和动画效果。
总结:通过这次图形学实验,我们深入了解了计算机图形学的原理和应用。
我们学习了像素和颜色、坐标系统和变换、线段和多边形、光照和阴影、纹理映射和渲染,以及三维建模和动画等技术。
多边形的区域填充
b++;
p[b]=(int)edge[j].xmax;
}
}
if((scan>edge[j].ymin)&&(scan<edge[j].ymax))
{
b++;
p[b]=(int)(edge[j].xmax+edge[j].dx*(scan-edge[j].ymax));
}
}
//pDC->LineTo(spt[edge[0].num].x,spt[edge[0].num].y);
4.用C/C++语言编写源程序并调试、执行(最好能用动画显示填充过程);
5.分析实验结果
6.对程序设计过程中出现的问题进行分析与总结;
7.打印源程序或把源程序以文件的形式提交;
8.按格式要求完成实验报告。
五、实验结果及分析
种子填充算法的优点是非常简单,缺点是需要大量栈空间来存储相邻的点。扫描线填充算法就是它的改进的方法。它是通过沿扫描线填充水平像素段,来处理四连通或八连通相邻点,这样就仅仅只需要将每个水平像素段的起始位置压入栈,而不需要将当前位置周围尚未处理的相邻像素都压入栈,从而可以节省大量的栈空间。
if(spt[i].y > pmax)
pmax = spt[i].y;
if(spt[i+1].y < pmin)
pmin = spt[i+1].y;
}
}
for(int r=1;r<=6;r++)//排序edge(yUpper,xIntersect),结果为从大到小
{
for(int q=0;q<=6-r;q++)
计算机图形学实验有效边表填充算法
实验二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);}四、实验截图。
计算机图形学实验四 区域填充算法的实现
实验四区域填充算法的实现班级 08信计2班学号 20080502082 姓名分数一、实验目的和要求:1、理解区域的表示和类型。
2、能正确区分四连通和八连通的区域3、了解区域填充的实验原理。
4、利用C++实现区域填充的递归算法。
二、实验内容:1假设在多边形内有一像素已知,由此出发利用连通性找到区域内所有像素。
2 取(x,y)为种子点将整个区域填充为新的颜色。
3 进行递归填充。
三、实验结果分析区域填充属性包括填充样式,填充颜色和填充图案的类型。
C语言中定义了某种图形后,即可调用-floodfill函数,对指定区域进行填充. 程序代码#define pi 3.141592#define MAX(a,b) (a>b)? a:b#define MIN(a,b) (a<b)? a:b#include "graphics.h"#include "math.h"struct edge {int ymax;float x;float delat;struct edge * pedge; };struct point{int x;int y;} ;struct et { struct edge * pedge;int n;};struct edge g_aet[10];struct edge dge[10];struct et g_et[10];struct point point1,point2;int ZUO(float x){ if((int)x==x)return (int)x;return (int)x+1;}int YOU(float x){ if((int)x==x)return (int)x-1;return (int)x;}int k=400,l=0;void draw1(){int i,t,j,a,c,p,z; float b;struct edge temp;for(i=k;i<=l;i++){a=0;for(t=0;t<=9;t++){ if(g_et[t].n==i) break;}for(j=0;j<=9;j++){ if(g_aet[j].ymax==0) break;}if(t!=10){ g_aet[j].ymax=g_et[t].pedge->ymax;g_aet[j].x=g_et[t].pedge->x;g_aet[j].delat=g_et[t].pedge->delat;if(g_et[t].pedge->pedge!=0){g_aet[j+1].ymax=g_et[t].pedge->pedge->ymax;g_aet[j+1].x=g_et[t].pedge->pedge->x;g_aet[j+1].delat=g_et[t].pedge->pedge->delat; }}for(j=0;j<=9;j++){ if(g_aet[j].ymax==0) break; }j--;for(t=0;t<=j;t++){ for(z=0;z<=j-1;z++){if(g_aet[z].x>g_aet[z+1].x){ temp.ymax=g_aet[z].ymax;temp.x=g_aet[z].x;temp.delat=g_aet[z].delat;g_aet[z].ymax=g_aet[z+1].ymax;g_aet[z].x=g_aet[z+1].x;g_aet[z].delat=g_aet[z+1].delat;g_aet[z+1].ymax=temp.ymax;g_aet[z+1].x=temp.x;g_aet[z+1].delat=temp.delat;}}}for(j=0;j<=9;j++){ if(g_aet[j].ymax==0) break; }j--;for(p=0;p<=j;p++){ a++;if(a%2!=0)b=g_aet[p].x;else{for(c=ZUO(b);c<=YOU(g_aet[p].x);c++)putpixel(c,i,2);}}for(t=0;t<=j;t++){ if(g_aet[t].ymax==(i+1)){ g_aet[t].ymax=0;g_aet[t].x=0;g_aet[t].delat=0;}g_aet[t].x+=g_aet[t].delat;}for(t=0;t<=j;t++){ for(z=0;z<=j-1;z++){if(g_aet[z].x<g_aet[z+1].x){ temp.ymax=g_aet[z].ymax;temp.x=g_aet[z].x;temp.delat=g_aet[z].delat;g_aet[z].ymax=g_aet[z+1].ymax;g_aet[z].x=g_aet[z+1].x;g_aet[z].delat=g_aet[z+1].delat;g_aet[z+1].ymax=temp.ymax;g_aet[z+1].x=temp.x;g_aet[z+1].delat=temp.delat;}}}}}void generate(){int i,y,n=1,m,q,p;float x;for(i=0;i<=9;i++){if(n==1){ point2.x=point1.x=300;point2.y=point1.y=200;n++;}else{ if(n%2==0){ x=40*cos(i*pi/5)+200;y=40*sin(i*pi/5)+200;}else{ x=100*cos(i*pi/5)+200;y=100*sin(i*pi/5)+200;}if(point1.y==y) { n++; continue;}m=MIN(point1.y,y);if(x==point1.x){ dge[i-1].delat=0;dge[i-1].ymax=MAX(point1.y,y);dge[i-1].x=x;dge[i-1].pedge=0;for(q=0;q<=9;q++){ if(g_et[q].n==m) break;}if(q==10){g_et[i-1].pedge=&dge[i-1];g_et[i-1].n=m;}else{g_et[q].pedge->pedge=&dge[i-1];g_et[i-1].n=0;}}else{dge[i-1].delat=(float)(x-point1.x)/(y-point1.y);dge[i-1].ymax=MAX(point1.y,y);if(point1.y>y) dge[i-1].x=x;else {dge[i-1].x=point1.x; }dge[i-1].pedge=0;for(q=0;q<=9;q++){ if(g_et[q].n==m) break;}if(q==10){ g_et[i-1].pedge=&dge[i-1];g_et[i-1].n=m;}else{g_et[q].pedge->pedge=&dge[i-1];g_et[i-1].n=0;}}p=MAX(point1.y,y);k=MIN(k,m);l=MAX(l,p);point1.x=x;point1.y=y;n++;}}if(point1.y==point2.y) return;else{if(point2.x==point1.x){dge[i-1].delat=0;dge[i-1].ymax=MAX(point1.y,point2.y);dge[i-1].x=point2.x;}else{ dge[i-1].ymax=MAX(point1.y,point2.y);if(point1.y>point2.y) dge[i-1].x=point2.x;else {dge[i-1].x=point1.x;}dge[i-1].delat=(float)(point2.x-point1.x)/(point2.y-point1.y);}}m=MIN(point1.y,point2.y);k=MIN(k,m);l=MAX(l,dge[i-1].ymax);g_et[i-1].n=m;g_et[i-1].pedge=&dge[i-1];}void main(){ int driver=DETECT,mode; int i; registerbgidriver(EGA VGA_driver);initgraph(&driver,&mode,"\\tc");initgraph(&driver,&mode,"\\tc");for(i=0;i<=9;i++){ g_aet[i].ymax=0; g_aet[i].x=0; g_aet[i].delat=0;g_et[i].pedge=0;}generate();draw1();circle(200,200,100); circle(200,200,40);getch();closegraph();}。
计算机图形学 有效边表填充算法实验报告
实验题目: 实验二有效边表填充算法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.算法设计:(1)建立AET和BUCKET类;(2)初始化桶, 并在建立桶结点时为其表示的扫描线初始化为带头结点的链表;(3)对每个桶结点进行循环, 将桶内每个结点的边表合并为有效边表, 并进行有效边表循环;(4)按照扫描线从小到大的移动顺序, 计算当前扫描线与多边形各边的交点, 然后把这些交点按X值递增的顺序进行排序, 配对, 以确定填充区间;(5)用指定颜色点亮填充区间内的所有像素, 即完成填充工作。
4.源程序:1)//AET.hclass AET{public:AET();virtual ~AET();double x;int yMax;double k;//代替1/kAET *next;};//AET..cppAET::AET(){}AET::~AET(){}2) //Bucket.h#include "AET.h"class Bucket{public:Bucket();virtual ~Bucket();int ScanLine;AET *p;//桶上的边表指针Bucket *next;};// Bucket.cppBucket::Bucket(){}Bucket::~Bucket(){}3)//TestView.h#include "AET.h"//包含有效边表类#include "Bucket.h"//包含桶类#define Number 7//N为闭合多边形顶点数, 顶点存放在整型二维数组Point[N]中class CTestView : public CView{。
多边形填充算法实验报告
学生实验报告
实验课名称:计算机图形学
实验项目名称:多边形填充算法
专业名称:计算机科学与技术
班级:
学号:
学生姓名:
教师姓名:
2016年4月30 日
六.运行结果与分析:
图1:扫描线种子填充算法
图2:种子填充算法
七.实验中遇到的问题、解决方法及体会:
多边形的填充对我来说很困难,因为一开始我不知道要输入什么数据,后来我决定要输入五个点来形成一个五边形,但是输入的顺序是一个大问题。
后来我采取顺序输入的方法,但是程序运行时常常崩溃,结果不尽人意。
最后,我在同班同学的帮助之下,找到了自己的问题,完成了填充。
多边形填充算法-有序边表法(扫描线算法)
多边形填充算法-有序边表法(扫描线算法)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指针:同边表。
计算机图形学作业实验报告
计算机图形学实验报告班级:学号:姓名:指导教师:完成日期:实验一:多边形填充一、实验目的了解多边形属性,熟悉相关函数的调用。
二、实验内容步骤和实现:首先进行初始化工作,进行显示模式(单缓冲区)和窗口等设定,主要实现根据两个函数,一个是指定场景绘制函数,glutDisplayFunc(Paint),paint函数中设置了两个三角形,一个填充,一个不填充。
用到了启用多边形点画模式glEnable(GL_POL YGON_STIPPLE)的函数,和指定多边形点画模式(填充) glPolygonStipple(fly)的函数。
另外一个就是循环执行OpenGl命令的glutMainLoop()函数。
三、实验结果四、源程序// POL Y_STIPPLE.C#include <gl/glut.h>void makeObject() // 定义一个三角形{ glBegin(GL_TRIANGLES); // 开始定义三角形// 按逆时针方向指定三角形的顶点坐标glVertex2f(-0.95, -0.95);glVertex2f(0.95, -0.95);glVertex2f(0, 0.95);glEnd(); // 三角形定义结束}void display(){ GLsizei w = glutGet(GLUT_WINDOW_WIDTH); // 程序窗口宽度GLsizei h = glutGet(GLUT_WINDOW_HEIGHT); // 程序窗口高度GLubyte fly[] = // 第二个三角形点画模式的mask值{ 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, // 0X03, 0X80, 0X01, 0XC0, 0X06, 0XC0, 0X03, 0X60, //0X04, 0X60, 0X06, 0X20, 0X04, 0X30, 0X0C, 0X20, //0X04, 0X18, 0X18, 0X20, 0X04, 0X0C, 0X30, 0X20, //0X04, 0X06, 0X60, 0X20, 0X44, 0X03, 0XC0, 0X22, //0X44, 0X01, 0X80, 0X22, 0X44, 0X01, 0X80, 0X22, //0X44, 0X01, 0X80, 0X22, 0X44, 0X01, 0X80, 0X22, //0X44, 0X01, 0X80, 0X22, 0X44, 0X01, 0X80, 0X22, //0X66, 0X01, 0X80, 0X66, 0X33, 0X01, 0X80, 0XCC, //0X19, 0X81, 0X81, 0X98, 0X0C, 0XC1, 0X83, 0X30, //0X07, 0XE1, 0X87, 0XE0, 0X03, 0X3F, 0XFC, 0XC0, //0X03, 0X31, 0X8C, 0XC0, 0X03, 0X33, 0XCC, 0XC0, //0X06, 0X64, 0X26, 0X60, 0X0C, 0XCC, 0X33, 0X30, //0X18, 0XCC, 0X33, 0X18, 0X10, 0XC4, 0X23, 0X08, //0X10, 0X63, 0XC6, 0X08, 0X10, 0X30, 0X0C, 0X08, //0X10, 0X18, 0X18, 0X08, 0X10, 0X00, 0X00, 0X08 };glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区glViewport(0, 0, w / 2, h); // 第一个视口,显示第一个三角形glColor3f(1, 1, 1); // 设置颜色,白色,默认值makeObject(); // 第一个三角形glViewport(w / 2, 0, w / 2, h); // 第二个视口,显示第二个三角形glColor3f(1, 0, 0); // 设置颜色,红色glEnable(GL_POL YGON_STIPPLE); // 启用多边形点画模式glPolygonStipple(fly); // 指定多边形点画模式(填充)makeObject(); // 第二个三角形glDisable(GL_POL YGON_STIPPLE); // 关闭多边形点画模式glFlush(); // 强制OpenGL命令序列在有限的时间内完成执行}int main(){ glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);// 设置程序窗口的显示模式(单缓冲区、RGBA颜色模型)glutInitWindowPosition(100, 100); // 程序窗口的位置glutInitWindowSize(300, 150); // 程序窗口的大小glutCreateWindow("一个填充多边形的例子!"); // 窗口的标题glutDisplayFunc(display); // 指定场景绘制函数glutMainLoop(); // 开始循环执行OpenGL命令}实验二:基本图元绘制二、实验目的了解OpenGL图形软件包绘制图形的基本过程及其程序框架,并在已有的程序框架中添加代码实现直线和圆的生成算法,演示直线和圆的生成过程,从而加深对直线和圆等基本图形生成算法的理解。
第4章多边形填充算法
E2
E5
E3 E4
边缘填充算法示意图
1.边缘填充算法(正负相消法) 基本原理是:对每一条扫描线,依次求与多边形各边 的交点,将该扫描线上交点右边的所有像素求补。多 边形所有边处理完毕,填充即完成。
优点:简单易行 缺点:多边形外的像素处 理过多,输入输出量大
算法改进
• ቤተ መጻሕፍቲ ባይዱ围盒 • 栅栏
带包围盒的多边形
第4章 多边形填充算法
4.3 边缘填充算法
4.3.1 填充原理
• 求出多边形的每条边与扫描线的交点 • 将交点右侧的所有像素颜色全部取为补
色。 • 按任意顺序处理完多边形的所有边。
4.3.2 填充过程
假定边的访问顺序为E0、E1、E2、E3、E4、E5和E6。
P1(x1,y1)
E1
E0
E6
P0(x0,y0)
缺点:某些像素被重复取补
3.边标志填充算法
基本思想:先用一种特殊的颜色在帧缓存中将多边形 的边界(水平边除外)勾画出来,然后将着色的像素点依x 坐标递增的顺序两两配对,再将每一对像素所构成的扫描线 区间内的所有像素置为填充色。
3.边标志填充算法
①打标记:对多边形边界所在像素置一个特殊标志。按照 “下闭上开”的原则处理局部最低点为两个交点,局部 最高点为0个交点。
② 填充:对于每条与多边形相交的扫描线,依照“左闭 右开”的原则从左至右逐个访问该扫描线上的像素,并 着色。
3.边标志填充算法
栅栏填充算法
栅栏:一条过多边形顶点且与扫描线垂直的直线,它将 多边形分成两半,只要将栅栏与多边形之间的像素求补 即可。
缺点:某些像素被重复取补
栅栏填充算法
基本原理:对于每条扫描线与多边形的交点,将交点与栅栏 之间的扫描线上的像素取补,也就是说,若交点位于栅 栏左边,则将交点之右、栅栏之左的所有像素取补;若 交点位于栅栏右边,则将栅栏之右、交点之左的所有像 素取补。
计算机图形学学习报告
《计算机图形学》课程学习报告班级学号:102055208学生姓名:牛慧敏一、算法名称多边形边缘填充算法二、算法理论知识1) 根据示例多边形顶点坐标值,计算多边形的最大、最小x 坐标,最大、最小y 坐标。
2) 使用CLine 类对象绘制多边形及其包围盒。
3) 填充色FClr 为调色板上取得的颜色,背景色BCr 为白色。
4) 对于每一条边,y 从ymin 开始,执行下面的循环。
5) X 从扫描线与边的交点处开始到包围盒右边界,先获得(x,y)位置的像素颜色,如果是填充色,则置为背景色,否则使用填充色填充,执行x=x+1/k,计算下一个扫描线与边交点的x 坐标。
6) 如果y=ymin ,则结束循环,否则y+1后转(5)。
三、算法功能说明1) 绘制示例多边形及其包围盒。
2) 用于填充示例多边形。
四、算法程序流程图否 是五、算法执行结果绘制多边形 读取多边形点表,并保存需要填充的颜色是否填充填充多边一、算法名称金刚石图案算法二、算法理论知识1) 读入圆的等分点的个数n 与圆的半径r 。
2) 根据等分点个数计算金刚是图案的等分角θ=2π/n 。
3) 计算金刚石图案的起始角α=π/2-θ。
α是用于调整金刚石图案的起始位置。
4) 将园等分后的定点坐标存储于数组P 中。
5) 设计一个二重循环,代表起点的外层整型变量j 从j=i+1循环到j=n-1.以p[i]为起点,以p[j]为终点连接各线段构成金刚石图案。
三、算法功能说明1) 可以自定义圆的等分点个数和圆的半径,并绘制金刚石的图案。
2) 自定义屏幕二位坐标系,原点位于客户区中心,x 轴水平向右为正,y轴垂直向上为正。
以二位坐标系原点为圆心绘制半径为r 的圆,将圆的n 等分点使用直线段批次连接形成金刚石图案。
四、算法程序流程图五、算法执行结果输入圆的等分点个数n 和圆的半径人r 确定坐标系的原点 计算等分点坐标,依次各连接等分点,则金刚石图案绘制完成 5<N<50 &&200<r<500 否 是。
多边形的边缘填充算法
多边形的边缘填充算法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为空。
【免费下载】计算机图形学 区域填充算法的实现
圆中填充蓝色,
2. 出栈,若栈空则结束;否则取栈顶元素(x,y),以 y 作为扫描线。
3. 填充并确定种子点所在区段,从种子点(x,y)出发,沿当前扫描线向左、右两个方
向填充,直到边界。
4. 确定新的种子点,在以上确定的边界中检查与当前扫描线 y 上、下相邻的两条扫描线
上的像素。若存在非边界、未填充的像素,则把每一区间的最右像素作为种子点压入
三、实验内容及步骤:
3.1、实验内容:
1. 利用种子算法实现内点表示的四连通区域的填充。如:设(x,y)为内点表示的四连
通区域内的一点,oldcolor 为区域的原色,要将整个区域填充为新的颜色 newcolor;
2. 利用扫描线算法实现以上区域的填充。如:填充以下图案,
三角形中填充红色;
3.2、实验步骤:
typedef struct{ NhomakorabeaElemType data[MaxSize];
int top;
} SqStack;
//栈顶指针
void InitStack(SqStack *&s) {
s=(SqStack *)malloc(sizeof(SqStack)); s->top=-1; }
int StackEmpty(SqStack *s) {
实验四 区域填充算法的实现
班级 08 信计二 学号 64 姓名 刘辉 分数
一、实验目的和要求:
1、理解区域的表示和类型; 2、能够正确区分四连通、八连通的区域; 3、了解填充函数、区域填充的实现原理; 4、了解掌握区域填充的各种算法(种子填充算法、扫描线算法、边填充
算法等),并实现种子填充算法和扫描线算法; 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,并依据次链接该边表结点到甬结点。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
扫描线种子填充:
public void FillField(int x, int y, Color newColor, uint oldColor, Graphics g) {
if ("".Equals(txtx.Text) || "".Equals(txty.Text)) { return; } else { x = Convert.ToInt32(txtx.Text); y = Convert.ToInt32(txty.Text); } int xl, xr; bool spanNeedFill; myStack.Clear();
个交点。如右图,对 y=8 的扫描线排序 x 坐标得到的表是(2,4,9,13),然后对交点 2 与 4 之间、9 与 13 之间 的所有象素点进行填充。 边界上的象素:“左闭右开”,“下闭上开”(将左边界和下边界的点算为内部,而将右边界和上边界 算为外部) 顶点:“上开下闭”。
几种特殊情况: 1.扫描线交于一顶点,共享的两条边分另处于扫描线的两边,这时交点只取一个,如扫描线 y=3,该点被填 充一次。2.共享交点的两条边处于扫描线的上方,这时交点取二个,如扫描线 y=1,该点被填充一次。 3.共享交点的两条边处于扫描线的下方,这时交点取 0 个,如扫描线 y=9,无交点,不填充。 4.水平边在算法中不起任何作用,可不考虑。 活性边表(提高效率): 为了减少求交的计算量,要利用一条边与相继的两条扫描线的交点的连贯性。在处理一条扫描线时只对活 性边(与它相交的多边形的边)进行求交运算。把交点按 x 增加方向存在一个链表(活性边表)中。活性边: 与当前扫描线相交的边。 活性边表(AEL) :按交点 x 的增量顺序存放在一个链表中,该链表称作活性边表(AEL) 。
扫描线种子算法
测试对象为象素段 ,对区域内的每一象素段 ,只保留其最右边 (或左边)的象素作为种子象素 .区域填充(扫描 线算法): –目标:减少递归层次 –适用于内点表示的 4 连通区域 基本过程: 当给定种子点时,首先填充种子点所在的扫描线上的位于给定区域的一个区段,然后确定与这一区段相通的上 下两条扫描线上位于给定区域内的区段,并依次保存下来。反复这个过程,直到填充结束。 算法步骤: 1、填充并确定种子区段; 2、初始化:将种子区段压入堆栈; 3、出栈:如果堆栈为空,则算法结束;否则取栈顶元素 y,xLeft,xRight) ,以纵坐标为 y 的扫描线为当前扫描 线,[xLeft, xRight]为搜索区间; 4、填充并确定新的区段 。
}
四连通种子填充:
public void BoundaryFill4(int x, int y, uint oldColor, Graphics g) { if ("".Equals(txtx.Text) || "".Equals(txty.Text)) { return; } else { x = Convert.ToInt32(txtx.Text); y = Convert.ToInt32(txty.Text); } if (bitmap.GetPixel(g, x, y) != oldColor && bitmap.GetPixel(g, x, y) == ColorTranslator.ToWin32(Color.Yellow)) { bitmap.SetPixel(g, x, y, ColorTranslator.ToWin32(Color.Red)); BoundaryFill4(x, y + 1, oldColor, g); BoundaryFill4(x - 1, y, oldColor, g); BoundaryFill4(x, y - 1, oldColor, g); BoundaryFill4(x + 1, y, oldColor, g); } }
y = pty; while (bitmap.GetPixel(g, x, y) == oldColor) { bitmap.SetPixel(g, x, y, ColorTranslator.ToWin32(newColor)); x++; } xr = x - 1; x = ptx - 1; while (bitmap.GetPixel(g, x, y) == oldColor) { bitmap.SetPixel(g, x, y, ColorTranslator.ToWin32(newColor)); x--; } xl = x + 1;
扫描线算法算法原理:
利用相邻像素之间的连贯性, 提高算法效率。 根据多边形内部点的连续性知:一条扫描线与多
10 8 实 6 验 原 理 4 2 0 2 4 6 8 10 12 1 2 3 4
边形的交点中,入点和出点之间所有点都是多边 形的内部点。所以,对所有的扫描线填充入点到 出点之间所有的点就可填充多边形。 处理对象:非自交多边形(边与边之间除了 顶点外无其它交点)判断扫描线上的点是否在多 边形之内,根据多边形区域连续性, 分为 3 个步骤: – – – – 求出扫描线与多边形所有边的交点; 把这些交点的 x 坐标值以升序排列; 对每一对交点间的区域进行填充。 第三个步骤是从奇数个交点出发到偶数
int ptx = x; int pty = y; myStack.Push(ptx); myStack.Push(pty); while (myStack.Count != 0) { pty = (int)myStack.Pop(); ptx = (int)myStack.Pop(); x = ptx;
指 导 教 师 意 见 签名: 年 月 日
实 验 VS2010(C#) 环 境 1、 添加一个 C#下的 Windows 窗体应用程序,实现对于算法的选择。 实 2、 根据不同算法添加不同窗体,接受圆初始化数据,编写核心函数。代码见实验原理中代码 验 部分。 步 3、 调试运行。 骤
实 验 内 容 在 VS2010 环境下利用 C#编程实现多边形填充算法,并给出实验报告。
种子填充算法算法原理
种子填充算法首先假定区域由封闭轮廓线围成,且轮廓线内某点是已知的,然后开始搜索与种子点相邻且 位于轮廓线内的点。如果这相邻 点不在轮廓线内,则已达到轮廓线的边界;如果相邻点在轮廓线之内,则这相 邻点成为新的种子点,继续搜索下去。只适用于光栅扫描设备。 区域分类(区域采用边界定义,即区域边界上与边界外的象素取相同值,区域内部的点取不同值) 1、 四向连通区域:各象素在水平垂直四个方向是边通的。即从区域内任一点出发,可水平/垂直移动到达区 域内任一点。 2、 八向连通区域:各象素在水平、垂直、及四个对角线方向都是是边通的。即从区域内任一点出发,可水平、 垂直、及四个对角线方向移动到达区域内任一点。
x = xl; y = y + 1; while (x <= xr) { spanNeedFill = false; while (bitmap.GetPixel(g, x, y) == oldColor) {
spanNeedFill = true; x++; } if (spanNeedFill) { ptx = x - 1; pty = y; myStack.Push(ptx); myStack.Push(pty); spanNeedFill = false; } while (bitmap.GetPixel(g, x, y) != oldColor && x <= xr) { x++; } }
实 验 结 果
实 验 总 结
一、对四连通的递归区域填充算法的分析: 该算法也可以填充有孔区域。 优点:算法简单 缺点:递归执行,效率不高,要求很大的存储空间来实现堆栈。费时费内存。 改进:减少递归次数,提高效率。 二、扫描线种子填充算法 该算法对于每一个待填充区段,只需压栈一次;因此,扫描线种子填充算法提高了区域填充的 效率。
贵州大学实验报告
学院:计算机科学与信息学院 姓名 实验时间 实验项目名称 实 验 2013.4级: 101 实验组 4
指导教师
吴云
成绩
使学生掌握光栅显示系统中多边形的扫描转换和区域填充算法。掌握 4 连通区域的扩展性。 目 的 实 验 实现多边形的扫描转换算法和区域填充算法 要 求
x = xl; y = y - 2; while (x <= xr) { spanNeedFill = false;
while (bitmap.GetPixel(g, x, y) == oldColor) { spanNeedFill = true; x++; } if (spanNeedFill) { ptx = x - 1; pty = y; myStack.Push(ptx); myStack.Push(pty); spanNeedFill = false; } while (bitmap.GetPixel(g, x, y) != oldColor && x <= xr) { x++; } } }