计算机图形学 区域填充算法的实现

计算机图形学  区域填充算法的实现
计算机图形学  区域填充算法的实现

实验四区域填充算法的实现

班级:信计二班学号:20080502076 姓名:刘刚分数:

一实验目的和要求

1 理解区域的表示和类型,能正确区分四连通和八连通的区域,了解区域填充的实现原理

2掌握光栅图形显示基本原理

3 熟悉区域填充的算法

二实验内容

1 利用画线函数,在屏幕上定义一个封闭区域

2 编程实现扫描线多边形填充算法,边填充算法,种子填充算法

三实验结果分析

1 本算法通过使用栈结构主要的实现了扫描线多边形填充算法,成功绘制出了四连通区域。算法要求区域是连通的,因为只有在连通的区域中,才能将种子点的颜色扩展到区域内的其他点。

2程序代码:

(区域填充的每一过程,每按回车健一次,就描一个点,一直按回车,就慢慢的演示填充了。)#include "stdio.h"

#include"stdlib.h"

#include "math.h"

#define pi 3.14159265

#include "Conio.h"

#include "graphics.h"

#include "malloc.h"

#define closegr closegraph

#define max 400

typedef struct Edge{

int ymax;

float x,deltax;

struct Edge *nextEdge;

}Edge;

typedef struct {

char *s,*t,*w,*v,*v1;

}string;

Edge *ET[max];

void initgr(void) /* BGI初始化*/

{int gd=DETECT,gm=0; /* 和gd=VGA,gm=VGAHI是同样效果*/

registerbgidriver(EGA VGA_driver);/* 注册BGI后可以驱动不需要.BGI文件的支持运行*/

initgraph(&gd,&gm,"");

}

void GetST(float x[5],float y[5],float a[5],float b[5],float radius)

{int i;

float r;

setcolor(BLUE);

for(i=0;i<5;i++)

{x[i]=radius*cos(i*0.4*pi+0.05*pi)-radius*sin(i*0.4*pi+0.05*pi)+450;

y[i]=radius*sin(i*0.4*pi+0.05*pi)+radius*cos(i*0.4*pi+0.05*pi)+200;

getch();

circle(x[i],y[i],1); fillellipse(x[i],y[i],1,1);

}

r=sin(0.1*pi)*radius/sin(126.0/180.0*pi);

for(i=0;i<5;i++)

{a[i]=r*cos(i*0.4*pi+0.25*pi)-r*sin(i*0.4*pi+0.25*pi)+450;

b[i]=r*sin(i*0.4*pi+0.25*pi)+r*cos(i*0.4*pi+0.25*pi)+200;

getch();

circle(a[i],b[i],1);

}

/*得到五角星的10个顶点*/

}

void Del_Node(int left,int top,int right,int bottom)

{int a[8];

a[0]=left;a[1]=top;a[2]=left;a[3]=bottom;a[4]=right;a[5]=bottom;a[6]=right;a[7]=top;

setcolor(WHITE);

fillpoly(4,a);

}

void Node_Rect(int left,int top,int right,int bottom,string a,int flag)

{int m;

rectangle(left,top,right,bottom);

for(m=1;m<4;m++) line(left+m*30,top,left+m*30,bottom);

if(flag==0){outtextxy(left+2,top+7,a.w); outtextxy(left+30+2,top+7,a.v); outtextxy(left+60+5,top+2,a.s);outtextxy(left+60+7,top+4,"_");

outtextxy(left+60+5,top+15,a.t); }

else {outtextxy(left+2,top+7,a.w); outtextxy(left+30+2,top+7,a.v1); outtextxy(left+60+2,top+4,"-");

outtextxy(left+60+10,top+2,a.s);outtextxy(left+60+11,top+4,"_");outtextxy(left+60+10,top+1

5,a.t);}

}

void CreatET(float x[5],float y[5],float a[5],float b[5])

{int n;

Edge *e,*h;

n=(int)(y[3]+0.5);

e=(Edge*)malloc(sizeof(Edge));

e->ymax=(int)(b[3]+0.5);e->x=x[3];e->deltax=(a[3]-x[3])/(b[3]-y[3]); h=(Edge*)malloc(sizeof(Edge));

h->ymax=(int)(b[2]+0.5);h->x=x[3];h->deltax=(a[2]-x[3])/(b[3]-y[3]); e->nextEdge=h;h->nextEdge=NULL;

ET[n]=e;

n=(int)(b[2]+0.5);

e=(Edge*)malloc(sizeof(Edge));

e->ymax=(int)(b[1]+0.5);e->x=x[2];e->deltax=(a[1]-x[2])/(b[1]-y[2]); h=(Edge*)malloc(sizeof(Edge));

h->ymax=(int)(b[4]+0.5);h->x=x[4];h->deltax=(a[4]-x[4])/(b[4]-y[4]); e->nextEdge=h;h->nextEdge=NULL;

ET[n]=e;

n=(int)(b[1]+0.5);

e=(Edge*)malloc(sizeof(Edge));

e->ymax=(int)(y[1]+0.5);e->x=a[1];e->deltax=(x[1]-a[1])/(y[1]-b[1]); h=(Edge*)malloc(sizeof(Edge));

h->ymax=(int)(y[0]+0.5);h->x=a[4];h->deltax=(x[0]-a[4])/(y[0]-b[4]); e->nextEdge=h;h->nextEdge=NULL;

ET[n]=e;

n=(int)(b[0]+0.5);

e=(Edge*)malloc(sizeof(Edge));

e->ymax=(int)(y[1]+0.5);e->x=a[0];e->deltax=(x[1]-a[0])/(y[1]-b[0]); h=(Edge*)malloc(sizeof(Edge));

h->ymax=(int)(y[0]+0.5);h->x=a[0];h->deltax=(x[0]-a[0])/(y[0]-b[0]); e->nextEdge=h;h->nextEdge=NULL;

ET[n]=e;

}

void Free(float y[5],float b[5])

{int n;

n=(int)(y[3]+0.5);

ET[n]=NULL;

n=(int)(b[2]+0.5);

ET[n]=NULL;

n=(int)(b[1]+0.5);

ET[n]=NULL;

n=(int)(b[0]+0.5);

ET[n]=NULL;

}

void Arrow_Line(int leftx,int lefty,int rightx,int righty)

{line(leftx,lefty,rightx,righty);

line(rightx-5,righty+5,rightx,righty);line(rightx-5,righty-5,rightx,righty);

}

void Fillin(Edge *AEL,int bottom,int top )

{

char *s;

string str;

Edge *e;

Edge *p,*q;

int n,m,i=0,j=0,a[8];

AEL=(Edge*)malloc(sizeof(Edge));AEL->x=-1;

AEL->nextEdge=NULL;

for(n=bottom;n

{p=ET[n];

while(p)

{ getch();

setcolor(BLUE);

switch(n)

{case 59:str.s="31";str.t="97";str.w="146";str.v="200";str.v1="200";break;

case 156:str.s="83";str.t="60";str.w="207";str.v="66";str.v1="334";break;

case 217:str.s="31";str.t="97";str.w="314";str.v="148";str.v1="251";break;

case 254:str.s="83";str.t="60";str.w="314";str.v="200";str.v1="200";break;

default:break;

}

if(i%2==0)

{ if(n==59||n==217){

if(n==217) {setcolor(WHITE); line(60,390,70,390);line(70,390,70,410);line(70,410,50,410);line(50,410,50,430);

Arrow_Line(50,430,60,430);}

setcolor(BLUE);

Arrow_Line(60,390,150,390);

Node_Rect(150,380,250,405,str,0);

Arrow_Line(245,392,420,392); }

if(n==156){ setcolor(WHITE) ;Arrow_Line(60,390,150,390);

setcolor(BLUE);line(60,390,70,390);line(70,390,70,410);line(70,410,50,410);line(50,410,50,43 0);

Arrow_Line(50,430,60,430);

Node_Rect(60,420,160,445,str,0);Arrow_Line(155,430,490,430); }

if(n==254){setcolor(WHITE);Arrow_Line(245,392,420,392);

setcolor(BLUE);

line(245,390,260,390);line(260,390,260,410);line(260,410,210,410);line(210,410,210,430);

Arrow_Line(210,430,220,430);

Node_Rect(220,420,320,445,str,0); Arrow_Line(315,430,330,430);

}

Del_Node(10,j*80+70,119,j*80+95);}

else if(i%2!=0)

{ if(n==59)Node_Rect(420,380,520,405,str,1);

if(n==156) Node_Rect(490,420,590,445,str,1);

if(n==217)

{Node_Rect(420,380,520,405,str,1);line(515,390,530,390);line(530,390,530,410);

line(530,410,480,410);line(480,410,480,430);

Arrow_Line(480,430,490,430);}

if(n==254) {Node_Rect(330,420,430,445,str,1);

line(425,430,440,430);line(440,430,440,410);line(440,410,410,410);line(410,410,410,390);

Arrow_Line(410,390,420,390); }

Del_Node(120,j*80+70,220,j*80+95);

j+=1;}

i+=1;

e=AEL; q=AEL->nextEdge;

while(q)

{if(p->xx)break;

q=q->nextEdge;

e=e->nextEdge;}

q=p->nextEdge;

p->nextEdge=e->nextEdge;

e->nextEdge=p;

p=q;

}

p=AEL;q=AEL->nextEdge;

m=1;

getch();

while(q)

{ if(q->ymax==n)

{ /*outtextxy(2,i+10,"ScanLine have reached");

i+=10;

outtextxy(2,i+10,"one elem'ymax of AEL;");

i+=10;

outtextxy(2,i+10,"remove it from AEL;"); i+=20; */

setcolor(WHITE);

if(n==156){Del_Node(420,380,520,405);

getch();Arrow_Line(245,392,420,392);Del_Node(150,380,250,405); }

if(n==217) {Del_Node(490,420,590,445);line(515,390,530,390);line(530,390,530,410);

line(530,410,480,410);line(480,410,480,430);

Arrow_Line(480,430,490,430); getch();Arrow_Line(155,430,490,430); Del_Node(60,420,160,445);}

if(n==314)

{Del_Node(420,380,520,405);line(425,430,440,430);line(440,430,440,410);line(440,410,410,41 0);

line(410,410,410,390);Arrow_Line(410,390,420,390);

getch();Del_Node(330,420,430,445);Arrow_Line(315,430,330,430);getch();

Del_Node(220,420,320,445);

line(245,390,260,390);line(260,390,260,410);line(260,410,210,410);line(210,410,210,430);

Arrow_Line(210,430,220,430); getch();

Del_Node(150,380,250,405); Arrow_Line(60,390,150,390);}

i-=1;

p->nextEdge=q->nextEdge;

e=q;

q=q->nextEdge;free(e);

}

else{

if(p!=AEL&&m%2==0)

{setcolor(RED);

line((int)(p->x+0.5),n,(int)(q->x+0.5),n);

p->x+=p->deltax;

q->x+=q->deltax;}

p=p->nextEdge;

q=q->nextEdge;

m++;}

}

}

}

main()

{ char *s,*t,*w,*v,*v1;

string str;

int n,m ,i;

float x[5],y[5],a[5],b[5],r;

Edge *AEL;

initgr();/* BGI初始化*/

setbkcolor(WHITE);

setcolor(BLUE);

outtextxy(1,1,"Show Pentagram");

GetST(x,y,a,b,100); /*得到五角星的顶点*/ setcolor(9);

for(i=0;i<4;i++)

{getch();

line(x[i],y[i],a[i],b[i]);getch();

line(a[i],b[i],x[i+1],y[i+1]);

}

getch();

line(x[4],y[4],a[4],b[4]); getch();

line(a[4],b[4],x[0],y[0]);

/*画出五角星*/

getch();

line(x[3]-170,10,x[3]+170,10);

line(x[3]+170-5,5,x[3]+170,10);

line(x[3]+170-5,15,x[3]+170,10);

line(x[3]-170,10,x[3]-170,360);

line(x[3]-170-5,355,x[3]-170,360);

line(x[3]-170+5,355,x[3]-170,360); outtextxy(x[3]-170-5,5,"0"); /*画坐标*/ for(i=10;i<350;i+=10)

{if(i%50==0)

{

line(x[3]-170+i,10,x[3]-170+i,20);

if(i==50) s=ecvt(i,2,1,1);

else s=ecvt(i,3,1,1);

outtextxy(x[3]-170-25,i-5,s);}

else

line(x[3]-170+i,10,x[3]-170+i,15);

}

for(i=10;i<350;i+=10)

{if(i%50==0)

{line(x[3]-170,i,x[3]-170+15,i);

if(i==50) s=ecvt(i,2,1,1);

else s=ecvt(i,3,1,1);

outtextxy(x[3]-170+i-10,2,s);

}

else

line(x[3]-170,i,x[3]-170+5,i);

}

/*标坐标轴刻度*/

setcolor(RED);

getch();

outtextxy(x[3]-170-20,58,"49"); getch();

line(x[3]-170,58,x[3]+100,58); outtextxy(x[3]+102,58,"ET[49]"); getch();

outtextxy(x[3]-170-25,156,"146"); getch();

line(x[3]-170,156,x[3]+150,156); outtextxy(x[3]+132,148,"ET[146]"); getch();

outtextxy(x[3]-170-25,217,"207"); getch();

line(x[3]-170,217,x[3]+100,217); outtextxy(x[3]+102,217,"ET[207]"); getch();

outtextxy(x[3]-170-25,254,"244"); getch();

line(x[3]-170,254,x[3]+120,254); outtextxy(x[3]+122,254,"ET[244]"); getch();

/*划分类边*/

getch();

outtextxy(10,20,"Edge Table:"); getch();

for(i=0;i<4;i++)

{ rectangle(10,40+i*80,80,i*80+60);

line(70,i*80+50,90,i*80+50);line(90,i*80+50,90,i*80+65);

line(90,i*80+65,20,i*80+65);

line(20,i*80+65,20,i*80+70);

line(18,i*80+68,20,i*80+70);line(22,i*80+68,20,i*80+70);

}

outtextxy(15,45,"ET[49]"); outtextxy(15,125,"ET[146]");

outtextxy(15,205,"ET[207]"); outtextxy(15,285,"ET[244]");

for(i=0;i<4;i++)

{switch(i)

{case 0:str.s="31";str.t="97";str.w="146";str.v="200";str.v1="200";break;

case 1:str.s="83";str.t="60";str.w="207";str.v="66";str.v1="334";break;

case 2:str.s="31";str.t="97";str.w="314";str.v="148";str.v1="251";break;

case 3:str.s="83";str.t="60";str.w="314";str.v="200";str.v1="200";break;

default:break;

}

Node_Rect(10,i*80+70,110,i*80+95,str,0);

line(105,i*80+85,120,i*80+85);line(118,i*80+83,120,i*80+85);line(118,i*80+87,120,i*80+85); Node_Rect(120,i*80+70,220,i*80+95,str,1);

}

/*画分类表*/

n=(int)(y[3]+0.5);

m=(int)(y[1]+0.5);

getch();

CreatET(x,y,a,b);

setcolor(BLUE); outtextxy(10,360,"Active Edge List:");

rectangle(20,380,60,400); outtextxy(25,385,"AEL");

Fillin(AEL,n,m); /*填充*/

outtextxy(200,400,"Fillin Finished!");

getch();

closegr(); /* 恢复TEXT屏幕模式*/

}

3运行结果:

计算机图形学 区域填充算法的实现

实验四区域填充算法的实现 班级 08信计2班学号 20080502088 姓名许延恒分数 一、实验目的和要求: 1、理解区域的表示和类型。 2、能正确区分四连通和八连通的区域 3、了解区域填充的实验原理。 4、利用C++实现区域填充的递归算法。 二、实验内容: 1假设在多边形内有一像素已知,由此出发利用连通性找到区域内所有像素。 2 取(x,y)为种子点将整个区域填充为新的颜色。 3 进行递归填充。 三、实验结果分析 区域填充属性包括填充样式,填充颜色和填充图案的类型。C语言中定义了某种图形后,即可调用-floodfill函数,对指定区域进行填充 . 程序代码 #include #include #include void floodfill4(int x,int y,int oldcolor,int newcolor) { if(getpixel(x,y)==oldcolor) { putpixel(x,y,newcolor); Sleep(1); floodfill4(x,y+1,oldcolor,newcolor); floodfill4(x,y-1,oldcolor,newcolor); floodfill4(x-1,y,oldcolor,newcolor); floodfill4(x+1,y,oldcolor,newcolor); } } main() { int a,b,c,d,i,j; int graphdriver=DETECT; int graphmode=0; initgraph(&graphdriver,&graphmode,"");

扫描线填充算法讲解

扫描线算法(S c a n-L i n e F i l l i n g) 扫描线算法适合对矢量图形进行区域填充,只需要直到多边形区域的几何位置,不需要指 定种子点,适合计算机自动进行图形处理的场合使用,比如电脑游戏和三维CAD软件的渲染等等。 对矢量多边形区域填充,算法核心还是求交。《计算几何与图形学有关的几种常用算法》 一文给出了判断点与多边形关系的算法――扫描交点的奇偶数判断算法,利用此算法可以 判断一个点是否在多边形内,也就是是否需要填充,但是实际工程中使用的填充算法都是 只使用求交的思想,并不直接使用这种求交算法。究其原因,除了算法效率问题之外,还 存在一个光栅图形设备和矢量之间的转换问题。比如某个点位于非常靠近边界的临界位置,用矢量算法判断这个点应该是在多边形内,但是光栅化后,这个点在光栅图形设备上看就 有可能是在多边形外边(矢量点没有大小概念,光栅图形设备的点有大小概念),因此, 适用于矢量图形的填充算法必须适应光栅图形设备。 2.1扫描线算法的基本思想 扫描线填充算法的基本思想是:用水平扫描线从上到下(或从下到上)扫描由多条首尾相 连的线段构成的多边形,每根扫描线与多边形的某些边产生一系列交点。将这些交点按照 x坐标排序,将排序后的点两两成对,作为线段的两个端点,以所填的颜色画水平直线。 多边形被扫描完毕后,颜色填充也就完成了。扫描线填充算法也可以归纳为以下4个步骤:(1)求交,计算扫描线与多边形的交点 (2)交点排序,对第2步得到的交点按照x值从小到大进行排序; (3)颜色填充,对排序后的交点两两组成一个水平线段,以画线段的方式进行颜色填充; (4)是否完成多边形扫描?如果是就结束算法,如果不是就改变扫描线,然后转第1步 继续处理; 整个算法的关键是第1步,需要用尽量少的计算量求出交点,还要考虑交点是线段端点的 特殊情况,最后,交点的步进计算最好是整数,便于光栅设备输出显示。 对于每一条扫描线,如果每次都按照正常的线段求交算法进行计算,则计算量大,而且效 率底下,如图(6)所示: 图(6)多边形与扫描线示意图

计算机图形学裁剪算法详解

裁剪算法详解 在使用计算机处理图形信息时,计算机部存储的图形往往比较大,而屏幕显示的只是图的一部分。因此需要确定图形中哪些部分落在显示区之,哪些落在显示区之外,以便只显示落在显示区的那部分图形。这个选择过程称为裁剪。最简单的裁剪方法是把各种图形扫描转换为点之后,再判断各点是否在窗。但那样太费时,一般不可取。这是因为有些图形组成部分全部在窗口外,可以完全排除,不必进行扫描转换。所以一般采用先裁剪再扫描转换的方法。 (a)裁剪前 (b) 裁剪后 图1.1 多边形裁剪 1直线段裁剪 直线段裁剪算法比较简单,但非常重要,是复杂图元裁剪的基础。因为复杂的曲线可以通过折线段来近似,从而裁剪问题也可以化为直线段的裁剪问题。常

用的线段裁剪方法有三种:Cohen-Sutherland,中点分割算法和梁友栋-barskey 算法。 1.1 Cohen-Sutherland裁剪 该算法的思想是:对于每条线段P1P2分为三种情况处理。(1)若P1P2完全在窗口,则显示该线段P1P2简称“取”之。(2)若P1P2明显在窗口外,则丢弃该线段,简称“弃”之。(3)若线段既不满足“取”的条件,也不满足“弃”的条件,则在交点处把线段分为两段。其中一段完全在窗口外,可弃之。然后对另一段重复上述处理。 为使计算机能够快速判断一条直线段与窗口属何种关系,采用如下编码方法。延长窗口的边,将二维平面分成九个区域。每个区域赋予4位编码CtCbCrCl.其中各位编码的定义如下:

图1.2 多边形裁剪区域编码图5.3线段裁剪 裁剪一条线段时,先求出P1P2所在的区号code1,code2。若code1=0,且code2=0,则线段P1P2在窗口,应取之。若按位与运算code1&code2≠0,则说明两个端点同在窗口的上方、下方、左方或右方。可判断线段完全在窗口外,可弃之。否则,按第三种情况处理。求出线段与窗口某边的交点,在交点处把线段一分为二,其中必有一段在窗口外,可弃之。在对另一段重复上述处理。在实现本算法时,不必把线段与每条窗口边界依次求交,只要按顺序检测到端点的编码不为0,才把线段与对应的窗口边界求交。 Cohen-Sutherland裁减算法 #define LEFT 1 #define RIGHT 2 #define BOTTOM 4

区域填充算法运行代码

///

///扫描线填充算法填充触发事件 /// /// /// private void scanLineFillingToolStripMenuItem_Click(object sender, EventArgs e) { slf.ScanLinePolygonFill(P,g,XiangSu); } private void label2_Click(object sender, EventArgs e) { } private void四联通填充ToolStripMenuItem_Click(object sender, EventArgs e) { tempp.X = tempP[3].X + XiangSu;//选取第4个点内侧(随机猜测) tempp.Y = tempP[3].Y + XiangSu; checkBox.Enabled = false;//让绘制过程中不能改变选择 do_check();//也要检查一遍,不然会出现错误 FloodSeedFill(tempp); checkBox.Enabled = true;//恢复 } /// ///初始化新边表 ///算法通过遍历所有的顶点获得边的信息,然后根据与此边有关的前后两个顶点的情况 ///确定此边的ymax是否需要-1修正。ps和pe分别是当前处理边的起点和终点,pss是起 ///点的前一个相邻点,pee是终点的后一个相邻点,pss和pee用于辅助判断ps和pe两个 ///点是否是左顶点或右顶点,然后根据判断结果对此边的ymax进行-1修正,算法实现非 ///常简单,注意与扫描线平行的边是不处理的,因为水平边直接在HorizonEdgeFill() ///函数中填充了。 /// private void InitScanLineNewEdgeTable(List[] NET, List Q, int ymin, int ymax) { List temp = new List(); EDGE e; for (int i = 0; i < Q.Count; i++) { Point ps = Q[i];

《计算机图形学》有序边表填充算法

实验报告 一、实验目的 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为空。 ●将新边表ET中对应y值的新边节点插入到AET表。 ●遍历AET表,将两两配对的交点之间填充给定颜色值。 ●遍历AET表,将 ymax= y的边节点从AET表中删除,并将ymax> y的各边节点 的x值递增Δx;并重新排序。 ●y增加1。 三、程序源代码 #include "graphics.h" #define WINDOW_HEIGHT 480 #define NULL 0 #include "alloc.h" #include "stdio.h" #include "dos.h" #include "conio.h" typedef struct tEdge /*typedef是将结构定义成数据类型*/ { int ymax; /* 边所交的最高扫描线号 */

实验三 区域填充算法的实现

实验三区域填充算法的实现 一、实验目的和要求: 1、掌握区域填充算法基本知识 2、理解区域的表示和类型,能正确区分四连通和八连通的区域 3、了解区域填充的实现原理,利用Microsoft Visual C++ 6.0或win-TC实现区 域种子填充的递归算法。 二、实验内容: 1、编程完成区域填色 2、利用画线函数,在屏幕上定义一个封闭区域。 3、利用以下两种种子填充算法,填充上述步骤中定义的区域 (1)边界表示的四连通区域种子填充的实现 (2)内点表示的四连通区域种子填充的实现 4、将上述算法作部分改动应用于八连通区域,构成八连通区域种子填充算法, 并编程实现。 三、实验结果分析 四连通图的实现: 程序代码: #include #include #include #include void BoundaryFill4(int x,int y,int Boundarycolor,int newcolor) { if(getpixel(x,y) != newcolor && getpixel(x,y) !=Boundarycolor) { putpixel(x,y,newcolor); Sleep(1); BoundaryFill4(x-1,y,Boundarycolor,newcolor); BoundaryFill4(x,y+1,Boundarycolor,newcolor); BoundaryFill4(x+1,y,Boundarycolor,newcolor); BoundaryFill4(x,y-1,Boundarycolor,newcolor); } } void polygon(int x0,int y0,int a,int n,float af) { int x,y,i; double dtheta,theta;

区域填充算法的实现

实验四区域填充算法的实现 一、实验目的和要求: 1、掌握区域填充算法基本知识 2、理解区域的表示和类型,能正确区分四连通和八连通的区域 3、了解区域填充的实现原理,利用Microsoft Visual C++ 6.0(及EasyX_2011版) 实现区域种子填充的递归算法。 二、实验内容: 1、编程完成区域填色 2、利用画线函数,在屏幕上定义一个封闭区域。 3、利用以下两种种子填充算法,填充上述步骤中定义的区域 (1)边界表示的四连通区域种子填充的实现 (2)内点表示的四连通区域种子填充的实现 4、将上述算法作部分改动应用于八连通区域,构成八连通区域种子填充算法, 并编程实现。 三、实验结果分析 1、以上各种算法相应代码及运行结果如下: 程序代码: #include #include #include void FloodFill4(int x,int y,int oldcolor,int newcolor) { if(getpixel(x,y)==oldcolor) { putpixel(x,y,newcolor); Sleep(1); FloodFill4(x-1,y,oldcolor,newcolor); FloodFill4(x,y+1,oldcolor,newcolor); FloodFill4(x+1,y,oldcolor,newcolor); FloodFill4(x,y-1,oldcolor,newcolor); } } void main() { int a,b,c,d,i,j; int graphdriver=DETECT; int graphmode=0; initgraph(&graphdriver,&graphmode," "); cleardevice();

计算机图形学图形的几何变换的实现算法

实验二图形的几何变换的实现算法 班级 08 信计 学号 59 姓名 _____ 分数 _____ 一、 实验目的和要求: 1、 掌握而为图形的基本几何变换,如平移,旋转,缩放,对称,错切变换;< 2、 掌握OpenG 冲模型变换函数,实现简单的动画技术。 3、 学习使用OpenGL 生成基本图形。 4、 巩固所学理论知识,加深对二维变换的理解,加深理解利用变换矩阵可 由简单图形得到复杂图形。加深对变换矩阵算法的理解。 编制利用旋转变换绘制齿轮的程序。编程实现变换矩阵算法,绘制给出形体 的三视图。调试程序及分析运行结果。要求每位学生独立完成该实验,并上传实 验报告。 二、 实验原理和内容: .原理: 图像的几何变换包括:图像的空间平移、比例缩放、旋转、仿射变换和图像插值。 图像几何变换的实质:改变像素的空间位置,估算新空间位置上的像素值。 图像几何变换的一般表达式:[u,v ]=[X (x, y ),Y (x, y )],其中,[u,v ]为变换后图像 像素的笛卡尔坐标, [x, y ]为原始图像中像素的笛卡尔坐标。这样就得到了原始图像与变 换后图像的像素的对应关系。 平移变换:若图像像素点(x, y )平移到(x x 。,y ■ y 。),则变换函数为 u = X (x, y ) =x 沟, v 二丫(x, y ) = y ■ y 。,写成矩阵表达式为: 比例缩放:若图像坐标 (x,y )缩放到(S x ,s y )倍,则变换函数为: S x ,S y 分别为x 和y 坐标的缩放因子,其大于1表示放大, 小于1表示缩小。 旋转变换:将输入图像绕笛卡尔坐标系的原点逆时针旋转 v 角度,则变换后图像坐标为: u COST 内容: :u l :Sx k ;0 其中,x 0和y 0分别为x 和y 的坐标平移量。 其中,

多边形区域填充算法

13. 设五边形的五个顶点坐标为(10, 10),(15, 5),(12, 5),(8, 2)和(4, 5),利用多边形区域填充算法,编一程序生成一个实心图。 解:假设以上五个顶点依次对应编号A-B-C-D-E,首先计算得到ET表: 6-10 5 4 3 2 1 该多边形的AET指针的内容为: 1 AET为空 2 3 4 1 2 3 4 5 6 7 8 9 10 01234567891011121314 1516

5 6 7 8 9 10 具体编程实现如下: 第1步:(1) 根据输入的五个顶点坐标找到y 值最小的点(例如点D ,此时y=2),并找到与D 有边关系的两个顶点(此时为E 和C),在y=2处建立ET 边表记录(ymax 、xi 和m 值均可通过顶点坐标间的计算得到,例如DE 边的建立,特别注意:当D 点和E 点y 坐标值相同时,也即是DE 与x 轴平行,该边不能计入ET 边表),之后标记D 点被访问过;(2) 排除访问过的点以及和该点相关联的边,重复(1)直至将ET 表建立完善。 [注]边关系的建立可通过邻接矩阵的数据结构实现,权值可以为该矩阵行编号对应点的y 坐标值,ET 边表采用邻接表的数据结构 第2步:根据ET 表构建AET 表,并逐行完成多边形填充,具体的C++代码如下: (1) 建立头文件base_class.h ,主要是边表结点结构体和ET 边表类的实现 enum ResultCode{Success, Failure}; template struct Enode { Enode() {next=NULL;} Enode(T pymax, float pxi, float pm, Enode *pnext) { ymax=pymax; xi=pxi; m=pm; next=pnext; } T ymax, xi; //ymax 表示最大的y 值,xi 表示最底端点的x 坐标值 float m; //m 表示斜率的倒数 Enode *next; }; //定义了ET 表和AET 表中结点的结构体

计算机图形学必考知识点

Phong Lighting 该模型计算效率高、与物理事实足够接近。Phong模型利用4个向量计算表面任一点的颜色值,考虑了光线和材质之间的三种相互作用:环境光反射、漫反射和镜面反射。Phong模型使用公式:I s=K s L s cosαΦα:高光系数。计算方面的优势:把r和v归一化为单位向量,利用点积计算镜面反射分量:I s=K s L s max((r,v)α,0),还可增加距离衰减因子。 在Gouraud着色这种明暗绘制方法中,对公用一个顶点的多边形的法向量取平均值,把归一化的平均值定义为该顶点的法向量,Gouraud着色对顶点的明暗值进行插值。Phong着色是在多边形内对法向量进行插值。Phong着色要求把光照模型应用到每个片元上,也被称为片元的着色。 颜色模型RGB XYZ HSV RGB:RGB颜色模式已经成为现代图形系统的标准,使用RGB加色模型的RGB三原色系统中,红绿蓝图像在概念上有各自的缓存,每个像素都分别有三个分量。任意色光F都可表示为F=r [ R ] + g [ G ] + b [ B ]。RGB颜色立方体中沿着一个坐标轴方向的距离代表了颜色中相应原色的分量,原点(黑)到体对角线顶点(白)为不同亮度的灰色 XYZ:在RGB 系统基础上,改用三个假想的原色X、Y、Z建立了一个新的色度系统, 将它匹配等能光谱的三刺激值,该系统称为视场XYZ色度系统,在XYZ空间中不能直观地评价颜色。 HSV是一种将RGB中的点在圆柱坐标系中的表示法,H色相S饱和度V明度,中心轴为灰色底黑顶白,绕轴角度为H,到该轴距离为S,沿轴高度为S。 RGB优点:笛卡尔坐标系,线性,基于硬件(易转换),基于三刺激值,缺点:难以指定命名颜色,不能覆盖所有颜色范围,不一致。 HSV优点:易于转换成RGB,直观指定颜色,’缺点:非线性,不能覆盖所有颜色范围,不一致 XYZ:覆盖所有颜色范围,基于人眼的三刺激值,线性,包含所有空间,缺点:不一致 交互式计算机程序员模型 (应用模型<->应用程序<->图形库)->(图形系统<->显示屏).应用程序和图形系统之间的接口可以通过图形库的一组函数来指定,这和接口的规范称为应用程序编程人员接口(API),软件驱动程序负责解释API的输出并把这些数据转换为能被特定硬件识别的形式。API提供的功能应该同程序员用来确定图像的概念模型相匹配。建立复杂的交互式模型,首先要从基本对象开始。良好的交互式程序需包含下述特性:平滑的显示效果。使用交互设备控制屏幕上图像的显示。能使用各种方法输入信息和显示信息。界面友好易于使用和学习。对用户的操作具有反馈功能。对用户的误操作具有容忍性。Opengl并不直接支持交互,窗口和输入函数并没有包含在API中。 简单光线跟踪、迭代光线跟踪 光线跟踪是一种真实感地显示物体的方法,该方法由Appel在1968年提出。光线跟踪方法沿着到达视点的光线的相反方向跟踪,经过屏幕上每一象素,找出与视线所交的物体表面点P0,并继续跟踪,找出影响P0点光强的所有的光源,从而算出P0点上精确的光照强度。光线跟踪器最适合于绘制具有高反射属性表面的场景。优缺点:原理简单,便于实现,能生成各种逼真的视觉效果,但计算量开销大,终止条件:光线与光源相交光线超出视线范围,达到最大递归层次。一般有三种:1)相交表面为理想漫射面,跟踪结束。2)相交表面为理想镜面,光线沿镜面反射方向继续跟踪。3)相交表面为规则透射面,光线沿规则透射方向继续跟踪。 描述光线跟踪简单方法是递归,即通过一个递归函数跟踪一条光线,其反射光想和折射光线再调用此函数本身,递归函数用来跟踪一条光线,该光线由一个点和一个方向确定,函数返回与光线相交的第一个对象表面的明暗值。递归函数会调用函数计算指定的光线与最近对象表面的交点位置。 图形学算法加速技术BVH, GRID, BSP, OCTree 加速技术:判定光线与场景中景物表面的相对位置关系,避免光线与实际不相交的景物表面的求交运算。加速器技术分为以下两种:Bounding Volume Hierarchy 简写BVH,即包围盒层次技术,是一种基于“物体”的场景管理技术,广泛应用于碰撞检测、射线相交测试之类的场合。BVH的数据结构其实就是一棵二叉树(Binary Tree)。它有两种节点(Node)类型:Interior Node 和Leaf Node。前者也是非叶子节点,即如果一个Node不是Leaf Node,它必定是Interior Node。Leaf Node 是最终存放物体/们的地方,而Interior Node存放着代表该划分(Partition)的包围盒信息,下面还有两个子树有待遍历。使用BVH需要考虑两个阶段的工作:构建(Build)和遍历(Traversal)。另一种是景物空间分割技术,包括BSP tree,KD tree Octree Grid BSP:二叉空间区分树 OCTree:划分二维平面空间无限四等分 Z-buffer算法 算法描述:1、帧缓冲器中的颜色设置为背景颜色2、z缓冲器中的z值设置成最小值(离视点最远)3、以任意顺序扫描各多边形a) 对于多边形中的每一个采样点,计算其深度值z(x,y) b) 比较z(x, y)与z缓冲器中已有的值zbuffer(x,y)如果z(x, y) >zbuffer(x, y),那么计算该像素(x, y)的光亮值属性并写入帧缓冲器更新z缓冲器zbuffer(x, y)=z(x, y) Z-buffer算法是使用广泛的隐藏面消除算法思想为保留每条投影线从COP到已绘制最近点距离,在投影后绘制多边形时更新这个信息。存储必要的深度信息放在Z缓存中,深度大于Z缓存中已有的深度值,对应投影线上已绘制的多边形距离观察者更近,故忽略该当前多边形颜色,深度小于Z缓存中的已有深度值,用这个多边形的颜色替换缓存中的颜色,并更新Z缓存的深度值。 void zBuffer() {int x, y; for (y = 0; y < YMAX; y++) for (x = 0; x < XMAX; x++) { WritePixel (x, y, BACKGROUND_VALUE); WriteZ (x, y, 1);} for each polygon { for each pixel in polygon’s projection { //plane equation doubl pz = Z-value at pixel (x, y); if (pz < ReadZ (x, y)) { // New point is closer to front of view WritePixel (x, y, color at pixel (x, y)) WriteZ (x, y, pz);}}}} 优点:算法复杂度只会随着场景的复杂度线性增加、无须排序、适合于并行实现 缺点:z缓冲器需要占用大量存储单元、深度采样与量化带来走样现象、难以处理透明物体 着色器编程方法vert. frag 着色器初始化:1、将着色器读入内存2、创建一个程序对象3、创建着色器对象4、把着色器对象绑定到程序对象5、编译着色器6、将所有的程序连接起来7、选择当前的程序对象8、把应用程序和着色器之间的uniform变量及attribute变量关联起来。 Vertex Shader:实现了一种通用的可编程方法操作顶点,输入主要有:1、属性、2、使用的常量数据3、被Uniforms使用的特殊类型4、顶点着色器编程源码。输入叫做varying变量。被使用在传统的基于顶点的操作,例如位移矩阵、计算光照方程、产生贴图坐标等。Fragment shader:计算每个像素的颜色和其他属性,实现了一种作用于片段的通用可编程方法,对光栅化阶段产生的每个片段进行操作。输入:Varying 变量、Uniforms-用于片元着色器的常量,Samples-用于呈现纹理、编程代码。输出:内建变量。 观察变换 建模变换是把对象从对象标架变换到世界标架 观察变换把世界坐标变换成照相机坐标。VC是与物理设备无关的,用于设置观察窗口观察和描述用户感兴趣的区域内部分对象,观察坐标系采用左手直角坐标系,可在用户坐标系中的任何位置、任何方向定义。其中有一坐标轴与观察方向重合同向并与观察平面垂直。观察变换是指将对象描述从世界坐标系变换到观察坐标系的过程。(1):平移观察坐标系的坐标原点,与世界坐标系的原点重合,(2):将x e,y e轴分别旋转(-θ)角与x w、y w轴重合。 规范化设备坐标系 规范化设备坐标系是与具体的物理设备无关的一种坐标系,用于定义视区,描述来自世界坐标系窗口内对象的图形。 光线与隐式表面求交 将一个对象表面定义为f(x,y,z)=f(p)=0,来自P0,方向为d的光线用参数的形式表示为P(t)=P0+td. 交点位置处参数t的值满足:f(P0+td)=0,若f是一个代数曲面,则f是形式为X i Y j Z k的多项式之和,求交就转化为寻求多项式所有根的问题,满足的情况一:二次曲面,情况二:品面求交,将光线方程带入平面方程:p*n+c=0可得到一个只需做一次除法的标量方程p=p0+td。可通过计算得到交点的参数t的值:t=(p0*n+c)/(n*d). 几何变换T R S矩阵表示 三维平移T 三维缩放S旋转绕z轴Rz( ) 100dx 010dy 001dz 0001 Sx000 0Sy00 00Sz0 0001 cos-sin00 sin cos00 0010 0001 θθ θθ 旋转绕x轴Rx(θ) 旋转绕y轴Ry(θ) 1000 0cos-sin0 0sin cos0 0001 θθ θθ cos0sin0 0100 -sin0cos0 0001 θθ θθ 曲线曲面 Bezier曲线性质:Bezier曲线的起点和终点分别是特征多边形的第一个顶点和最后一个顶点。曲线在起点和终点处的切线分别是特征多边形的第一条边和最后一条边,且切矢的模长分别为相应边长的n倍;(2)凸包性;(3)几何不变性(4)变差缩减性。端点插值。 均匀B样条曲线的性质包括:凸包性、局部性、B样条混合函数的权性、连续性、B样条多项式的次数不取决于控制函数。 G连续C连续 C0连续满足:C1连续满足: (1)(0) p(1)=(1)(0)(0) (1)(0) px qx py q qy pz qz == ???? ???? ???? ???? (1)(0) p'(1)=(1)'(0)(0) (1)(0) p x q x p y q q y p z q z == ???? ???? ???? ???? C0(G0)连续:曲线的三个分量在连接点必须对应相等 C1连续:参数方程和一阶导数都对应相等 G1连续:两曲线的切线向量成比例 三维空间中,曲线上某点的导数即是该点的切线,只要求两个曲线段连接点的导数成比例,不需要导 数相等,即p’(1)=aq’(0) 称为G1几何连续性。将该思想推广到高阶导数,就可得到C n和G n连续性。

计算机图形学 直线的生成算法的实现

实验二 直线的生成算法的实现 班级 08信计2班 学号 59 姓名 分数 一、实验目的和要求 1.理解直线生成的基本原理。 2.掌握几种常用的直线生成算法。 3.利用Visual C++实现直线生成的DDA 算法。 二、实验内容 1.了解直线的生成原理,尤其是Bresenham 画线法原理。 2.掌握几种基本的直线生成算法:DDA 画线法、Bresenham 画线法、中点画线法。 3.利用Visual C++实现直线生成的DDA 算法,在屏幕上任意生成一条直线。 三、实验步骤 1.直线的生成原理: (1)DDA 画线法也称数值微分法,是一种增量算法。是一种基于直线的微分方程来生成直线的方法。 (2)中点画线法原理 以下均假定所画直线的斜率[0,1]k ∈,如果在x 方向上的增量为1,则y 方向上的增量只能在01 之间。中点画线法的基本原理是:假设在x 坐标为p x 的各像素点中,与直线最近者已经确定为(,)p p P x y ,用小实心圆表示。那么,下一个与直线最近的像素只能是正右方的1(1,)p p P x y +,或右上方的2(1,1)p p P x y ++,用小空心圆表示。以M 为1P 和2P 的中点,则M 的坐标为(1,0.5)p p x y ++。又假设Q 是理想直线与垂直线1p x x =+的交点。显然,若M 在Q 的下方,则2P 离直线近,应取2P 为下一像素点;若M 在Q 的上方,则1P 离直线近,应取1P 为下一像素点。 (3)B resenham 画线法原理 直线的中点Bresenham 算法的原理:每次在主位移方向上走一步,另一个方向上走不走步取决于中点偏差判别式的值。 给定理想直线的起点坐标为P0(x0,y0),终点坐标为P1(x1,y1),则直线的隐函数方程为: 0b kx y y)F(x,=--= (3-1) 构造中点偏差判别式d 。 b x k y y x F y x F d i i i i M M -+-+=++==)1(5.0)5.0,1(),(

扫描线填充算法讲解

扫描线算法(Scan-Line F illing) 扫描线算法适合对矢量图形进行区域填充,只需要直到多边形区域的几何位置,不需要指定种子点,适合计算机自动进行图形处理的场合使用,比如电脑游戏 和三维CAD软件的渲染等等。 对矢量多边形区域填充,算法核心还是求交。《计算几何与图形学有关的几种 常用算法》一文给出了判断点与多边形关系的算法――扫描交点的奇偶数判断 算法,利用此算法可以判断一个点是否在多边形内,也就是是否需要填充,但 是实际工程中使用的填充算法都是只使用求交的思想,并不直接使用这种求交 算法。究其原因,除了算法效率问题之外,还存在一个光栅图形设备和矢量之 间的转换问题。比如某个点位于非常靠近边界的临界位置,用矢量算法判断这 个点应该是在多边形内,但是光栅化后,这个点在光栅图形设备上看就有可能 是在多边形外边(矢量点没有大小概念,光栅图形设备的点有大小概念),因此,适用于矢量图形的填充算法必须适应光栅图形设备。 2.1扫描线算法的基本思想 扫描线填充算法的基本思想是:用水平扫描线从上到下(或从下到上)扫描由 多条首尾相连的线段构成的多边形,每根扫描线与多边形的某些边产生一系列 交点。将这些交点按照x坐标排序,将排序后的点两两成对,作为线段的两个 端点,以所填的颜色画水平直线。多边形被扫描完毕后,颜色填充也就完成了。扫描线填充算法也可以归纳为以下4个步骤: (1)求交,计算扫描线与多边形的交点 (2)交点排序,对第2步得到的交点按照x值从小到大进行排序; (3)颜色填充,对排序后的交点两两组成一个水平线段,以画线段的方式进 行颜色填充; (4)是否完成多边形扫描?如果是就结束算法,如果不是就改变扫描线,然 后转第1步继续处理; 整个算法的关键是第1步,需要用尽量少的计算量求出交点,还要考虑交点是 线段端点的特殊情况,最后,交点的步进计算最好是整数,便于光栅设备输出 显示。

计算机图形学-区域填充的扫描线算法

计算机图形学——区域填充的扫描线算法 一.实验名称: 区域填充的扫描线算法 二.实验目的: 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 #include #include #include #define Stack_Size 100 //栈的大小常量 //定义结构体,记录种子点 typedef struct{ int x; int y; }Seed; //定义顺序栈(种子点) typedef struct { Seed Point[Stack_Size]; int top;

区域填充的扫描线算法

计算机图形学 ——区域填充的扫描线算法 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上、下相邻的两条

《计算机图形学》实验报告——区域填充和剪裁

实验报告模板 《计算机图形学》实验报告 区域填充算法、裁剪算法 一、实验目的及要求 上机用所学的算法来填充多边形区域,在所给的区域里面剪裁所给出的线段。 二、理论基础 区域填充:区域填充所采用的算法是种子天填充算法。算法的主要思想是在所给定的区域类取一点作为种子,然后向种子坐标的上下左右,或者上下左右,左上,左下,右上,右下八个方向进行填充,从而达到填充整个区域的目地。但是由于在上述的算法中其他的新种子呀进行入栈,就会使得很多用过的种子从新入栈,使效率不高。所以重新设计了一下算法,采用取一点先横向填充,即(x0,y0)y0,不变x0++或者x0--,在所给定的范围之类填充完了之后再采用y+1,y-1.上下两个方向进行填充。 剪裁:选用了Cohe-SutherLand算法,剪裁算法的主体思想是先将整个区域分成9个区域。如图所示 1001 1000 1010 0001 0000 0010 0101 0100 0110 其中0000里面是所需要的剪裁的部分。在一条直线在这个区域里面。它的两个端点将会落在上面的区域中的任何一个区域中。1) 当线段完全在框里面,取这个两个端点;2) 当这条直线明显在区域外面,则抛弃;3) 如果不满足上面的2个条件,则把线段分成两段,其中一段在外面,则放弃,在里面则保留。通过上面的标记来判断端点是否在区域里面。 三、算法设计与分析 剪裁: void COpenglForMFCView::OnAreaCut() { // TODO: Add your command handler code here m_bClip = !m_bClip ; if( !m_bClip ) return ; // 直线端点集合数组一定为端点对偶数个点坐标和裁剪准备时数据一致 int nvLines[8][2] = {{0,0},{100,100},{10,201},{-200,-50},{-50,-140},{-50,140},{-80,10},{240,270}}; // 裁剪窗口边界坐标上下左右

计算机图形学 圆周算法的实现

《计算机图形学实验报告》样例 实验名称:圆周画法的实现 1.实验内容 1.画出圆心坐标为(75,90)和半径为50的红色圆周 2.画出圆心坐标为(‐40,‐80)和半径为60的蓝色圆周 2.程序的基本思路和功能 先用MFC构建界面外观,然后在相应位置分别用Bresenham和DDA编辑画圆的程序然后编译运行。 3.关键代码及说明 void Circle::circleMinPoint(CDC* pDC) { xCenter = (float)(400 + x); yCenter = (float)(300 - y); //绘制圆心 drawCenter(pDC); //r = 50; //设置颜色 color = RGB(red,green,blue); float m_x = 0; float m_y = r; float d = 1.25 - r; circlePoint(m_x,m_y,pDC);

while(m_x <= m_y){ if(d<=0){ d = d + 2 * m_x + 3; }else{ d = d + 2 * ( m_x - m_y ) + 5; m_y = m_y - 1; } m_x = m_x + 1; circlePoint(m_x,m_y,pDC); } } void Circle::circleBresenham(CDC* pDC) { //确认圆心坐标 xCenter = (float)(400 + x); yCenter = (float)(300 - y); //绘制圆心 drawCenter(pDC); //r = 50; //设置颜色 color = RGB(red,green,blue); float m_x = 0; float m_y = r;

相关文档
最新文档