logo资料库

计算机图形学实验报告(专业中南民大计科院).doc

第1页 / 共49页
第2页 / 共49页
第3页 / 共49页
第4页 / 共49页
第5页 / 共49页
第6页 / 共49页
第7页 / 共49页
第8页 / 共49页
资料共49页,剩余部分请下载后查看
组员 学号 姓名 实验名称 直线的扫描转换 实验室 9#204 实 验 目 的 或 要 求 1. 实验内容 用基本增量算法和 Bresenham 算法画直线 2.实验目的 1)理解在显示器上画图与在纸上画图的本质区别; 2)掌握直线的光栅扫描转换过程; 3)掌握不同算法绘制直线的思路和优缺点。 3. 实验要求 1)将像素网格表现出来,建立网格坐标系; 2)用橡皮筋的形式输入参数; 3)鼠标移动时,显示鼠标当前位置; 4)显示判别式的计算过程和下一点的选择策略; 5)记录生成点的坐标,建议用表的形式; 6)图形生成过程可以重复进行。
一、 生成直线的 DDA 算法 数值微分法即 DDA 法(Digital Differential Analyzer),是一种基于直线的微分方程来生成直线的方法。 设(x1,y1)和(x2,y2)分别为所求直线的起点和终点坐标,由直线的微分方程得 = m =直线的斜率 (2-1) 可通过计算由 x 方向的增量△x 引起 y 的改变来生成直线: (2-2) (2-3) (2-4) (2-5) 也可通过计算由 y 方向的增量△y 引起 x 的改变来生成直线: xi+1=xi+△x yi+1=yi+△y=yi+△x·m yi+1=yi+△y xi+1=xi+△x=xi+△y/m 式(2-2)至(2-5)是递推的。 选定 x2-x1 和 y2-y1 中较大者作为步进方向(假设 x2-x1 较大),取该方向上的增量为一个象素单位 (Δx=1),然后利用式(2-1)计算另一个方向的增量(Δy=Δx·m=m)。通过递推公式(2-2)至(2-5),把每次计 算出的(xi+1,yi+1)经取整后送到显示器输出,则得到扫描转换后的直线。 之所以取 x2-x1 和 y2-y1 中较大者作为步进方向,是考虑沿着线段分布的象素应均匀,这在下图中 可看出。 另外,算法实现中还应注意直线的生成方向,以决定Δx 及Δy 是取正值还是负值。 实 验 原 理 ( 算 法 基 本 思 想 )
实 验 原 理 ( 算 法 基 本 思 想 ) 二、 生成直线的 Bresenham 算法 它也是采用递推步进的办法,令每次最大变化方向的坐标步进一个象素,同时另一个方向的坐标依据 误差判别式的符号来决定是否也要步进一个象素。 首先讨论 m=△y/△x,当 0≤m≤1 且 x1
ε(xi+2)= yi+1+m-yir-0.5=ε(xi+1)+m (2-11') 初始时: ε(xs+1)=BC-AC=m-0.5 (2-12') 为了运算中不含实型数,同时不影响不等式的判断,将方程两边同乘一正整数。 令方程两边同乘 2·Δx,即 d=2·Δx·ε,则: 初始时: 递推式: d = 2·Δy-Δx (2-13') 当 d≥0 时:{ d=d+2·(Δy-Δx); 否则: y++; x++; } { d=d+2·Δy; x++; } (2-14') 实 验 原 理 ( 算 法 基 本 思 想 )
一、 直线扫描转换 DDA 算法和 Bresenham 算法公用函数部分 程 序 代 码 nod FixP(int x,int y) //坐标修正函数 { nod temp; int weight =x / 20; int height = y / 20; int m1 = x % 20; int m2 = y% 20; if (m1 >= 10) weight += 1; if (m2 >= 10) height += 1; temp.x=weight; temp.y=height; return temp; } void DrawRe()//网格绘制函数 { int height= Form1->Image1->Height; int width = Form1->Image1->Width; int temp=20; Form1->Image1->Canvas->Pen->Color =clBlack; Form1->Image1->Canvas->Pen->Width=1; Form1->Image1->Canvas->Brush->Color = clWhite; Form1->Image1->Canvas->Pen->Style = psSolid; Form1->Image1->Canvas->Rectangle(0,0,width,height); for(int i=1;i<20;i++) { Form1->Image1->Canvas->MoveTo(0,temp); //划横线 Form1->Image1->Canvas->LineTo(width,temp); Form1->Image1->Canvas->MoveTo(temp,0); Form1->Image1->Canvas->LineTo(temp,height); temp+=20; //划竖线 } } void LinePublic(int X,int Y)//绘制校正起始点直线 { nod temp; temp =FixP(x1,y1); x1=temp.x*20; y1=temp.y*20; source= temp; (接下页)
temp=FixP(X,Y); int XX =temp.x*20; int YY=temp.y*20; dest =temp; Form1->Image1->Canvas->Pen->Width=2; Form1->Image1->Canvas->Pen->Color=clBlue; //输出直线坐标 Form1->StatusBar1->Panels->Items[2]->Text= " 直 线 起 点 : "+ IntToStr(source.x)+ ":"+IntToStr(source.y); Form1->StatusBar1->Panels->Items[3]->Text= " 直 线 终 点 : "+ IntToStr(dest.x)+ ":"+IntToStr(dest.y); Form1->Image1->Canvas->MoveTo(x1,y1); Form1->Image1->Canvas->LineTo(XX,YY); Form1->Memo1->Clear(); Form1->Memo2->Clear(); } void LinePublic2(int X,int Y)//鼠标移动橡皮筋绘制直线 { if(md==1) { //重新绘制网格 DrawRe(); ClearB(); Line( X,Y); } } void ClearB()//第二次绘制图形时清空状态栏数据 { 程 序 代 码 Form1->Memo1->Clear(); Form1->Memo2->Clear(); Form1->StatusBar1->Panels->Items[2]->Text= " Form1->StatusBar1->Panels->Items[3]->Text= " Form1->StatusBar1->Panels->Items[5]->Text= " "; "; "; //把上次状态栏的东西清空 } void Line(int X,int Y)//绘制校正直线 { Form1->Image1->Canvas->Pen->Width=2; Form1->Image1->Canvas->Pen->Color=clOlive; Form1->Image1->Canvas->MoveTo(x1,y1); Form1->Image1->Canvas->LineTo(X,Y); }
二、 直线扫描转换 DDA 算法实现 void LineDDA() { //直线的变量初始化 k= abs(dest.x-source.x); if(abs(dest.y-source.y)>k) { "); k= abs(dest.y-source.y); Form1->Memo2->Lines->Add(" Form1->Memo2->Lines->Add("| 斜率 | > 1 , 沿着 Y 方向步进 "); Form1->Memo2->Lines->Add("************************************"); Form1->Memo2->Lines->Add(" Form1->Memo2->Lines->Add("***********************************"); Form1->Memo2->Lines->Add(" Y=Y+1"); X=X+1/k 递推公式: "); ; } else { } "); Form1->Memo2->Lines->Add(" Form1->Memo2->Lines->Add("| 斜率 | <= 1 , 沿着 X 方向步进 "); Form1->Memo2->Lines->Add("**********************************"); Form1->Memo2->Lines->Add(" Form1->Memo2->Lines->Add("***********************************"); Form1->Memo2->Lines->Add(" Y=Y+k"); 递推公式: X=X+1 "); ; dx =(dest.x-source.x)/float(k);// 斜 率 <1 dx=dx+1,dy=dy+KK; 斜 率 >1 dx=dx+1/KK,dy=dy+1; //DDA 核心算法 dy =(dest.y-source.y)/float(k); xi= source.x; yi= source.y; } 逐点扫描: if(m <= k) { 程 序 代 码 DrawPie((int)(xi+0.5),(int)(yi+0.5),4);//四舍五入 tx=AnsiString((int)(xi+0.5))+" : Form1->Memo1->Lines->Add(tx); xi+= dx; Form1->StatusBar1->Panels->Items[5]->Text= " Form1->StatusBar1->Panels->Items[5]->Text= yi+= dy; "+AnsiString((int)(yi+0.5)); "; " 下 一 个 点 : "+ IntToStr((int)(xi+0.5))+ ":"+IntToStr((int)(yi+0.5)); m++ ; } else ShowMessage("完毕");
三、 Bresenham 算法实现 void BresenhamLine( ) { if((dest.x!=source.x) && (dest.y!=source.y)) { "); Form1->Memo2->Lines->Add(" Form1->Memo2->Lines->Add("| 斜率 | > 1 , 沿着 Y 方向步进 "); Form1->Memo2->Lines->Add("**************************"); Form1->Memo2->Lines->Add(" "); Form1->Memo2->Lines->Add("**************************"); Form1->Memo2->Lines->Add(" d>=0:curx =curx -+1;cury = cury -+1"); 递推公式: Form1->Memo2->Lines->Add("d<0:|k|<1,curx=curx-+1;|k|>1,cury=cury-+1"); dx1 = abs(dest.x - source.x); if (dx1 < dy1) { //Y 方向长,|斜率|>1 dy1 = abs(dest.y- source.y); 程 序 代 码 int t =dx1; dx1 = dy1; dy1 =t; iFlag = 1; } else //X 方向长,|斜率|<=1 iFlag = 0; d0 = (dy1 << 1) - dx1; //判别式初始值 tx1 = (dest.x - source.x) > 0 ? 1 : -1; ty = (dest.y - source.y) > 0 ? 1 : -1; curx = source.x; cury = source.y;d1=dy1<<2; d2=(dy1 - dx1)<<2; DrawPie(source.x, source.y,4); tx=AnsiString(curx)+" Form1->Memo1->Lines->Add(tx); "+AnsiString(cury); : } if((dest.x == source.x) || (dest.y == source.y)) { Flag1=1; } } 逐点扫描: if(Flag1==1) { if(dest.y == source.y) //水平线 { Form1->Memo2->Clear(); Form1->Memo2->Lines->Add("Bresenham 画水平直线"); } if(dest.x == source.x) //垂直线 {
分享到:
收藏