日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

DDA算法、中点Bresenam算法,圆或椭圆的绘制

發布時間:2023/12/9 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 DDA算法、中点Bresenam算法,圆或椭圆的绘制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、調用畫點函數,實現任意斜率直線的繪制 (運用DDA算法、中點Bresenam算法實現并比較算法精度與效率)

② 基本論述
DDA算法又稱數值微分法,是計算機圖形學中一種基于直線的微分方程來生成直線的方法。 原理就是最直觀的根據斜率的偏移程度,決定是以x為步進方向還是以y為步進方向。然后在相應的步進方向上,每次增加一個像素,而另一個相關坐標變量則為Y k+1=Y k + m(以x為步進變量為例,m為斜率)
假定直線斜率k在0~1之間,當前象素點為(xp,yp),則下一個象素點有兩種可選擇點P1(xp+1,yp)或P2(xp+1,yp+1)。若P1與P2的中點(xp+1,yp+0.5)稱為M,Q為理想直線與x=xp+1垂線的交點。當M在Q的下方時,則取P2應為下一個象素點;當M在Q的上方時,則取P1為下一個象素點。這就是中點畫線法的基本原理
Bresenham算法:過各行、各列像素中心構造一組虛擬網格線,按直線從起點到終點的順序計算直線各垂直網格線的交點,然后確定該列像素中與此交點最近的像素。該算法的優點在于可以采用增量計算,使得對于每一列,只要檢查一個誤差項的符號,就可以確定該列所求的像素。

②算法
DDA算法描述:
m =直線的斜率
可通過計算由x方向的增量△x引起y的改變來生成直線:
xi+1=xi+△x
yi+1=yi+△y=yi+△x·m
也可通過計算由y方向的增量△y引起x的改變來生成直線:
yi+1=yi+△y
xi+1=xi+△x=xi+△y/m
以此類推。
中點Bresenam算法描述:
任意給定的兩點所繪制的線段斜率k可能有四種情況,分別是:0<k<1,k>=1,-1<k<0,
k<=-1。下面對這四種情況分別進行分析。

(一) 當0<k<1時1.算法原理的推導 (1) 構造中點誤差項為: di=F(xM,yM)=F(xi + 1,yi + 0.5)=yi + 0.5 –k(xi + 1) -b (2) 中點誤差的初始值是: d0=F(x0 + 1,y0 + 0.5)=y0 + 0.5 –k(x0 + 1) -b =y0 – kx0 – b – k +0.5 其中,因為(x0,y0)在直線上,所以y0-kx0-b=0,則:d0=0.5-k (3) 推導di+1 a. 當di>=0時;中點在直線上方,取下面的點(x i+1,yi) di+1 = F(xi+2,yi+0.5) =yi+0.5-k(xi+2)-b =di-k b. 當d<i0時;中點在直線下方,取下面的點(x i+1,yi+1) di+1 = F(xi+2,yi+1.5) =yi+1.5-k(xi+2)-b =di+1 - k (二) 當k>=1時1.算法原理的推導 (1) 構造中點誤差項 di=F(xM,yM)=F(xi + 0.5,yi +1)=yi + 1 –k(xi + 0.5) -b (2) 中點誤差的初始值 d0=F(x0 + 0.5,y0 + 1)=y0 + 1 –k(x0 + 0.5) -b =y0 – kx0 – b –0.5k+1 其中,因為(x0,y0)在直線上,所以y0-kx0-b=0,則:d0=1-0.5k ( 3 ) 推導di+1 a.當di>=0時;中點在直線左方,取右方的點(x i+1,yi+1) di+1 = F(xi+1.5,yi+2) =yi+2-k(xi+1.5)-b =di+1-k b.當d<i0時;中點在直線右方,取左方的點(x i+1,yi+1) di+1 = F(xi+0.5,yi+2) =yi+2-k(xi+0.5)-b =di+1 (三)當-1<k<0時 1.算法原理的推導 (1) 構造中點誤差項 di=F(xM,yM)=F(xi + 1,yi -0.5)=yi - 0.5 –k(xi + 1) -b (2) 中點誤差的初始值 d0=F(x0 + 1,y0 - 0.5)=y0 - 0.5 –k(x0 + 1) -b =y0 – kx0 – b – k -0.5 其中,因為(x0,y0)在直線上,所以y0-kx0-b=0,則:d0=-0.5-k ( 3 ) 推導di+1 a.當di>=0時;中點在直線上方,取下方的點(x i+1,yi-1) di+1 = F(xi+2.,yi-1.5) =yi+1.5-k(xi+2)-b =di-1-k b.當di<0時;中點在直線下方,取下方的點(x i+1,yi) di+1 = F(xi+2.,yi-0.5) =yi-0.5-k(xi+2)-b =di-k (四) 當k<=-1時1.算法原理的推導 (1) 構造中點誤差項 di=F(xM,yM)=F(xi + 0.5,yi -1)=yi - 1 –k(xi + 0.5) -b (2) 中點誤差的初始值 d0=F(x0 + 0.5,y0 - 1)=y0 - 1 –k(x0 + 0.5) -b =y0 – kx0 – b –0.5k-1 其中,因為(x0,y0)在直線上,所以y0-kx0-b=0,則:d0=0.5-k ( 3 ) 推導di+1 a.當di>=0時;中點在直線右方,取左方的點(x i,yi-1) di+1 = F(xi+0.5,yi-2) =yi-2-k(xi+0.5)-b =di-1 b.當d<i0時;中點在直線下方,取下方的點(x i+1,yi-1) di+1 = F(xi+1.5,yi-2) =yi-2-k(xi+1.5)-b =di-1-k

③ 程序源代碼(是能直接運行的源代碼)

#include <conio.h> #include<stdio.h> #include <string.h> #include <queue> #include <windows.h> #include<iostream> #include<graphics.h> // 引用 EasyX 圖形庫 #include<time.h> #include<math.h> #include<stdlib.h> using namespace std;//(DDA算法實現) void DDA_Line(int x1,int y1,int x2,int y2) {float increx, increy, x, y, length;//定義變量int i;if (abs(x2 - x1) > abs(y2 - y1))//判斷以哪個可以作為增量length = abs(x2 - x1);elselength = abs(y2 - y1);increx = (x2 - x1) / length;//設置增量,分別為1和kincrey = (y2 - y1) / length;x = x1, y = y1;//這是起點for (i = 1; i <= length; i++) {putpixel(int(x + 0.5), int(y + 0.5), RED);//強制轉換為整型(因為像素點都是整個整個的)x += increx;// x加增量y += increy;// y加增量} }//(中點Bresenam算法實現) void Bresenham_line(int x0,int y0,int x1,int y1) {int x,y,dx,dy;float k,e; //定義變量dx=x1-x0;dy=y1-y0;k=dy/dx;//這是完成k值的初始化e=-0.5;x=x0;y=y0; for(int i=0;i<=dx;i++)//i每次加一個,直到終點,y選擇性加一或者不加{ putpixel(x,y,BLUE); //畫像素點x=x+1;e=e+k;if(e>=0) //這里e大于零就減一{y=y+1;e=e-1;}} }void main() //主函數測試調用算法 {int x0,y0,x1,y1;initgraph(640, 480); // 定義640 x 480的畫面setbkcolor(GREEN); //背景cleardevice();setcolor(BLACK);DDA_Line(100, 100, 640, 480);Bresenham_line(100, 100, 640, 480); getch(); // 按任意鍵繼續closegraph(); // 關閉圖形界面 }

關于二者效率和精度的研究:
bresenham算法的特點是:
1,不必計算直線之斜率,因此不做除法;
2,不用浮點數,只用整數;
3,只做整數加減法和乘2運算,而乘2運算可以用硬件移位實現.
DDA算法的特點:
浮點數運算
不易硬件實現
所以:Bresenham算法相比較于dda算法,速度很快,但是精度沒有dda高,適于用硬件實現.

3、圓或橢圓的繪制

①基本論述

中點畫圓法,考慮圓心在原點,半徑為R的圓在第一象限內的八分之一圓弧,從點(0, R)到點(R, R )順時針方向確定這段圓弧。

②算法
假定某點Pi(xi, yi)已經是該圓弧上最接近實際圓弧的點,那么Pi的下一個點只可能是正右方的P1或右下方的P2兩者之一
構造判別函數:
F(x, y)= x2 + y2 – R2

當F(x, y)= 0,表示點在圓上,當F(x, y)> 0,表示點在圓外,當F(x, y)< 0,表示點在圓內。如果M是P1和P2的中點,則M的坐標是(xi + 1, yi – 0.5),當F(xi + 1, yi – 0.5)< 0時,M點在圓內,說明P1點離實際圓弧更近,應該取P1作為圓的下一個點。同理分析,當F(xi + 1, yi – 0.5)> 0時,P2離實際圓弧更近,應取P2作為下一個點。當F(xi + 1, yi – 0.5)= 0時,P1和P2都可以作為圓的下一個點,算法約定取P2作為下一個點。

現在將M點坐標(xi + 1, yi – 0.5)帶入判別函數F(x, y),得到判別式d:
d = F(xi + 1, yi – 0.5)= (xi + 1)2 + (yi –0.5)2 – R2
若d < 0,則取P1為下一個點,此時P1的下一個點的判別式為:
d’ = F(xi + 2, yi – 0.5)= (xi + 2)2 + (yi –0.5)2 – R2

展開后將d帶入可得到的遞推關系:
d’ = d + 2xi + 3
若d > 0,則取P2為下一個點,此時P2的下一個點的判別式為:
d’ = F(xi + 2, yi – 1.5)= (xi + 2)2 + (yi –1.5)2 – R

展開后將d帶入可得到判別式的遞推關系:
d’ = d + 2(xi - yi) + 5
特別的,在第一個象限的第一個點(0, R)時,可以推倒出判別式d的初始值d0:
d0 = F(1, R – 0.5) = 1 – (R – 0.5)2 –R2 = 1.25 - R

③程序源代碼(是能直接運行的源代碼) //圓的繪制 #include<stdio.h> #include<graphics.h> // 引用 EasyX 圖形庫 #include<conio.h> #define x0 400 #define y0 400 //坐標軸中心(x0,y0) void draw_circle(int x1, int y1, int r) //定義中點畫圓方法 {int d0, x = 0, y = r;//d0為判別式的值d0 = 1.25 - r; //判別式的初始值,1.25可以改為1(方便計算)while (x < y) //{if (d0 >= 0) {d0 = d0 + 2 * (x - y) + 5; //這是d<0時,判別式的遞推關系x += 1; //因為x,y是上一個點,所以要更新坐標y -= 1;//這里體現八段畫法:putpixel(((x + x1) + x0), (y0 - (y + y1)), RED); //像素點(x,y)著色putpixel(((-x + x1) + x0), (y0 - (y + y1)), RED); //像素點(-x,y)著色putpixel(((y + x1) + x0), (y0 - (x + y1)), RED); //像素點(y,x)著色putpixel(((-y + x1) + x0), (y0 - (x + y1)), RED); //像素點(-y,x)著色putpixel(((x + x1) + x0), (y0 - (-y + y1)), RED); //像素點(x,-y)著色putpixel(((-x + x1) + x0), (y0 - (-y + y1)), RED); //像素點(-x,-y)著色putpixel(((y + x1) + x0), (y0 - (-x + y1)), RED); //像素點(y,-y)著色putpixel(((-y + x1) + x0), (y0 - (-x + y1)), RED); //像素點(-y,-x)著色Sleep(50); //休眠函數,作用是延時}else { d0 = d0 + 2 * x + 3; //這是d》0時,判別式的遞推關系x += 1;y = y; //更新坐標點putpixel(((x + x1) + x0), (y0 - (y + y1)), RED); //像素點(x,y)putpixel(((-x + x1) + x0), (y0 - (y + y1)), RED); //像素點(-x,y)putpixel(((y + x1) + x0), (y0 - (x + y1)), RED); //像素點(y,x)putpixel(((-y + x1) + x0), (y0 - (x + y1)), RED); //像素點(-y,x)putpixel(((x + x1) + x0), (y0 - (-y + y1)), RED); //像素點(x,-y)putpixel(((-x + x1) + x0), (y0 - (-y + y1)), RED); //像素點(-x,-y)putpixel(((y + x1) + x0), (y0 - (-x + y1)), RED); //像素點(y,-y)putpixel(((-y + x1) + x0), (y0 - (-x + y1)), RED); //像素點(-y,-x)Sleep(50);}} } void main() {int x1, y1, r;printf("輸入圓心坐標(x1,y1)和圓的半徑r:\n"); //用戶可以通過圓心坐標和圓的半徑來定義圓的形狀scanf("%d %d %d", &x1, &y1, &r); //輸入算法initgraph(x0 * 2, y0 * 2); //這是在初始化圖形窗口大小setbkcolor(GREEN); //背景為綠色cleardevice(); 這里插入圖片描述](https://img-blog.csdnimg.cn/20200730202245196.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3RvbWF0b2FhYWE=,size_16,color_FFFFFF,t_70)setcolor(BLUE); //坐標軸為藍色line(x0, 0, x0, y0 * 2); //這是描繪坐標軸Xline(0, y0, x0 * 2, y0); //這是描繪坐標軸Ydraw_circle(x1, y1, r); //中點畫圓算法調用_getch(); //等待一個任意輸入結束closegraph(); //關閉圖形窗口}

② 程序運行截圖(提交你的測試數據及運行結果)

加油加油!

總結

以上是生活随笔為你收集整理的DDA算法、中点Bresenam算法,圆或椭圆的绘制的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。