Bresenham直線演演算法

2021-04-22 10:16:49 字數 3765 閱讀 8261

法,它會算出一條線段在 n 維光柵上最接近的點。這個演演算法只會用到較為快速的整數加法、減法和位元移位,常用於繪製電腦畫面中的直線。是計算機圖形學中最先發展出來的演演算法。

經過少量的延伸之後,原本用來畫直線的演演算法也可用來畫圓。且同樣可用較簡單的算術運算來完成,避免了計算二次方程式或三角函式,或遞迴地分解為較簡單的步驟。

以上特性使其仍是一種重要的演演算法,並且用在繪圖儀、繪圖卡中的繪圖晶元,以及各種圖形程式庫。這個演演算法非常的精簡,使它被實作於各種裝置的韌體,以及繪圖晶元的硬體之中。

bresenham直線演演算法描繪的直線。

假設我們需要由 (x

y0) 這一點,繪畫一直線至右下角的另一點(x

y1),x,y分別代表其水平及垂直座標。在此我們使用電腦系統常用的座標系,即x座標值沿x軸向右增長,y座標值沿y軸向下增長。

因此x及y之值分別向右及向下增加,而兩點之水平距離為x1x

0且垂直距離為y

1-y0。由此得之,該線的斜率必定介乎於1至0之間。而此演算法之目的,就是找出在x0與x

1之間,第x行相對應的第y列,從而得出一畫素點,使得該畫素點的位置最接近原本的線。

對於由(x

y0)及(x

y1)兩點所組成之直線,公式如下:

因此,對於每一點的x,其y的值是

因為x及y皆為整數,但並非每一點x所對應的y皆為整數,故此沒有必要去計算每一點x所對應之y值。反之由於此線之斜率介乎於1至0之間,故此我們只需要找出當x到達那乙個數值時,會使y上公升1,若x尚未到此值,則y不變。至於如何找出相關的x值,則需依靠斜率。斜率之計算方法為m1y

0) / (x1x

0)。由於此值不變,故可於運算前預先計算,減少運算次數。

要實行此演算法,我們需計算每一畫素點與該線之間的誤差。於上述例子中,誤差應為每一點x中,其相對的畫素點之y值與該線實際之y值的差距。每當x的值增加1,誤差的值就會增加m。每當誤差的值超出0.5,線就會比較靠近下乙個映像點,因此y的值便會加1,且誤差減1。

下列偽程式碼是這演算法的簡單表達(其中的plot(x,y)繪畫該點,abs返回的是絕對值)。雖然用了代價較高的浮點運算,但很容易就可以改用整數運算(詳見最佳化一節):

functionline(x0, x1, y0, y1)

int deltax := x1 - x0

int deltay := y1 - y0

real error := 0

real deltaerr := deltay / deltax // 假設 deltax != 0 (非垂直線),

// 注意:需保留除法運算結果的小數部份

int y := y0

forxfromx0tox1

plot(x,y)

error := error + deltaerr

ifabs(error) ≥ 0.5then

y := y + 1

error := error - 1.0

雖然以上的演演算法只能繪畫由右上至左下,且斜率小於或等於1的直線,但我們可以擴充套件此演演算法,使之可繪畫任何的直線。第乙個擴充套件是繪畫反方向,即由左下至右上的直線。這可以簡單地透過在x0 > x1時交換起點和終點來做到。第二個擴充套件是繪畫斜率為負的直線。可以檢查y0y

xy,並一併將plot的引數順序交換。擴充套件後的偽程式碼如下:

functionline(x0, x1, y0, y1)

boolean steep := abs(y1 - y0) > abs(x1 - x0)

ifsteepthen

swap(x0, y0)

swap(x1, y1)

ifx0 > x1then

swap(x0, x1)

swap(y0, y1)

int deltax := x1 - x0

int deltay := abs(y1 - y0)

real error := 0

real deltaerr := deltay / deltax

int ystep

int y := y0

ify0 < y1thenystep := 1elseystep := -1

forxfromx0tox1

ifsteepthenplot(y,x)elseplot(x,y)

error := error + deltaerr

iferror ≥ 0.5then

y := y + ystep

error := error - 1.0

以上的程式可以處理任何的直線,實作了完整的bresenham直線演演算法。

以上的程式有乙個問題:電腦處理浮點運算的速度比較慢,而errordeltaerr的計算是浮點運算。此外,error的值經過多次浮點數加法之後,可能有累積誤差。使用整數運算可令演演算法更快、更準確。只要將所有以上的分數數值乘以deltax,我們就可以用整數來表示它們。唯一的問題是程式中的常數0.5—我們可以透過改變error的初始方法,以及將error的計算由遞增改為遞減來解決。新的程式如下:

functionline(x0, x1, y0, y1)

boolean steep := abs(y1 - y0) > abs(x1 - x0)

ifsteepthen

swap(x0, y0)

swap(x1, y1)

ifx0 > x1then

swap(x0, x1)

swap(y0, y1)

int deltax := x1 - x0

int deltay := abs(y1 - y0)

int error := deltax / 2

int ystep

int y := y0

ify0 < y1thenystep := 1elseystep := -1

forxfromx0tox1

ifsteepthenplot(y,x)elseplot(x,y)

error := error - deltay

iferror < 0then

y := y + ystep

error := error + deltax

jack e. bresenham於2023年在ibm發明了此演演算法。據他本人表示,他於2023年在丹佛舉行的美國計算機協會全國大會上發表了該演演算法,論文則登載於2023年的《ibm系統期刊》 (ibm systems journal) 之中。[1]

bresenham直線演演算法其後被修改為能夠畫圓,修改後的演演算法有時被稱為「bresenham畫圓演演算法」或中點畫圓演演算法。

^dictionary of algorithms and data structures,

美國國家標準與技術研究院.http://www.nist.gov/dads/html/bresenham.html

快速演演算法

package paul title 快速演演算法 description 快速排序法的基本精神是在?盜兄姓頁鯗m?的?s心,然後?盜幸環?槎?分?e?筮?c右?盜羞m行排序,而影?快速排序法效率的正是?s心的?x?瘛?下面介紹了三種方法,從理論分析效率遞增,但是沒有用大陣列來進行測試 author...

爬蟲 RSA加密演演算法

公鑰與金鑰的產生 假設alice想要通過乙個不可靠的 接受bob的一條私人訊息。她可以用以下的方式來產生乙個公鑰和乙個私鑰 隨意選擇兩個大的質數p和q,p不等於q,計算n pq 根據尤拉函式 r n 其中r是小於或等於n的正整數中與n 互質的數的數目 求得r n p q p 1 q 1 選擇乙個小於...

直線掃瞄 Bresenham演算法

計算機掃瞄直線原理 直線方程 y kx b y kx b 0 在第一象限畫線 x0,y0 x1,y1 當前點pi xi yi 則下一點必為p1 xi 1,yi 或 p2 xi 1,yi 1 理想直線靠近哪個點,就取那個點。推導 令f x,y y kx b,那麼理想直線上方有f 0,下方f 0.取p1...