畫直線演算法
前段時間做了一下光柵直線生成演算法的研究,並且在vc下實現了dda
演算法、bresenham
演算法、對稱演算法、兩步演算法、及四步演算法。這裡給個總結,希望和大家交流。
主要研究的演算法主要有
dda演算法、
bresenham
演算法、對稱演算法、兩步演算法、及四步演算法,此外還對自適應多步位移碼畫線演算法進行了一定研究。其中,
dda、
bresenham
演算法都是單步畫線演算法,其它是多步畫線演算法。
dda演算法和bresenham
演算法是經典的畫線演算法,並且業已證明
bresenham
畫線演算法使用了最小的計算量,是最高效的單步畫線演算法,這裡不再對其進行說明。以下對其餘各個演算法進行必要的說明。
對稱直線生成演算法基於這樣乙個事實:直線以中點位界,其兩邊是對稱的。因而可以利用這個對稱性,對
bresenham
演算法進行改進,使得每進行一次判斷就可以生成相對於直線中點的兩個對稱點。如此以來,直線就由兩端向中間生成。演算法用
c++語言描述如下:
intx1 = m_start.m_x;//
起點x
int y1 = m_start.m_y;//
起點y
int x2 = m_end.m_x;//
終點x
int y2 = m_end.m_y;//
終點y
int dx = m_end.m_x - m_start.m_x;
int dy = m_end.m_y - m_start.m_y;
int dx2 = dx << 1;
int dy2 = dy << 1;
int e= dy2 - dx;//
決策量int half = (dx+1) >> 1;
for (int i=0; i
//始端x向加1,末端x向減1
x1++;
x2--;
e += dy2;
}
兩步畫線演算法每判斷一次就生成兩個點,這與對稱演算法相似,不同的是對稱演算法是從兩端向中間進行的,而該演算法是始終沿乙個方向進行的,一次生成2個連續的點。當斜率k滿足條件
0≤k<
1時,考慮當前點
p,如圖
1所示,直線與
ab的交點一定落在
ab區間的四等分中之一。 圖
1 下一待選點位置必在四個等分區間之一
實際上,兩個連續點可能出現的形式只有四種情況,即dd、
dx、xd和
xx。其中
x表示沿水平方向移動乙個畫素,
d表示沿對角方向移動乙個畫素,見圖2。
圖2 連續兩點可能出現的
4種形式
決策量e的初值為
e=4dy–dx
,對於pattern 1,e
的增量為
4dy-4dx;對於
pattern 2
和3,e的增量為4dy-2dx;對於pattern 4,e的增量為4dy。
演算法用c++
語言描述如下:
intx = m_start.m_x;//
起點x
int y = m_start.m_y;//
起點y
int dx = m_end.m_x - m_start.m_x;
int dy = m_end.m_y - m_start.m_y;
int dx2 = dx << 1;
int dy2 = dy << 1;
int dx4 = dx2 << 1;
int dy4 = dy2 << 1;
int inc4 = dy4 - dx4;
int inc2 = dy4 - dx2;
int e = dy4 - dx;
pdc->setpixel(x, y, color);
for (int i=0; i
// pattern 3
else
}else
// pattern 1
else
}}每計算一次e值就生成兩個點,從而提高畫線效率,但是要進行較多的判斷,所以效率提高並不明顯。
四步畫線演算法類似域兩步畫線演算法,不同的時每判斷一次,就生成四個點。如圖3所示,直線一次前進四個點的情形。
圖3 四步畫線演算法示意圖
對於四步畫線演算法,規的跟兩步演算法相似的表示方法,共有
14種形式,如圖4。
圖4 連續四點肯能出現的
14種形式 圖
4中,自底向上依次是
pattern 1
到pattern 14
,pattern 1
為***x
,pattern 2
為***d
,……,
pattern 14
為dddd。
初始時,
e=-dx
,pattern 1時e
的增量為
8dy;
pattern 2
到pattern 4時e
的增量為
8dy-2dx
;pattern 5
到pattern 8時e
的增量為
8dy-4dx
;pattern 9
到pattern 13時e
的增量為
8dy-6dx
;pattern 14時e
的增量為
8dy-8dx
。鑑於**過長,這裡不再給出。
與傳統的直線演算法不同,自適應多步位移碼畫線演算法首先將待繪製直線表達成一串由0和
1組成的位移碼,根據位移碼的特點,自適應的確定一次生成的畫素數目,從而獲得更高的繪製效率。這裡引入兩個引理: 引理
1 設有從(
x1, y1
)到(x2, y2)
的直線,
0<h=y2-y1<k=x2-x1。那麼在該直線的位移碼中,相鄰兩個1之間連續0的數目w為[(k-h)/h]或[k/h]。[a]表示對a取整。
引理2設有從(
x1, y1
)到(x2, y2)
的直線,
0<h=y2-y1<k=x2-x1。那麼在該直線的位移碼中,相鄰兩個0之間連續1的數目w為[h/(k-h)]或[k/(k-h)]。
證明略。
這裡給出自適應多步位移碼畫線演算法的偽**:
k = x2 – x1;
h = y2 – y1;
t = [(k – 1)/2] – h;
divide(h, k – h, n, tchg);
x = x1;
y = y1;
while x<= x2 do
if t<0 then
y = y +1;
xend = x+n;
while x
drawpixel(x, y);
x = x +1;
end while
t = t+tchg;
else
t = t – h;
drawpixel(x, y);
end if
x = x +1;
end while
從理論而言,該演算法根據直線斜率自適應地選擇乙個步長,
以一次判斷生成多個取樣點的方式對直線進行繪製,從而大大提供了繪製效率。但是實際上,連續兩個1(
0)中間0(
1)的個數雖然只在兩個整數上選擇,但是到底在哪一步是哪乙個難以判斷,所以實現起來並不容易,而且目前尚未有解決方法。
bresenham
對稱 兩步 四步
加法 1
0.5
1
1 比較
2
1
1.5
1.3
加法和比較 3
1.5
2.5
2.3 乘法
2
3
4
6
上表給出平均每步所進行的加法次數和比較次數,乘除次數是整演算法總共的次數。
dda演算法未在表中給出,它與
bresenham
相似,但使用了多次浮點乘除運算和取整運算,效率明顯低於其它演算法。
bresenham
與其它演算法相比,加法步驟相當(對稱演算法除外),但比較次數較多。理論上而言,後面的演算法效率較高。但是應該注意到多步演算法,如兩步和四步演算法,在進行迴圈之前要做很多的初始化工作,而且乘除次數大於
bresenham
演算法。在進行較短直線繪製時,效率反而不如
bresenham
演算法快。
(一些演算法的源程式較長,這裡未給出。)
DDA演算法畫直線
畫直線的 適合所有斜率的直線 void cmyview linedda cdc pdc,int x0,int y0,int x1,int y1,colorref clr while y ymax return if y0 y1 水平線 while x xmax return double dx x1...
dda演算法畫直線 再談繪製直線
之前已經在 從零開始計算機圖形學 之七畫線 寫過繪製直線了,現在再來仔細的看一下這個問題。tinyrenderer github.com void line int x0,int y0,int x1,int y1,tgaimage image,tgacolor color 這裡的問題有兩個 t取大了...
Bresenham快速畫直線演算法
一 演算法原理簡介 演算法原理的詳細描述及部分實現可參考 假設以 x,y 為繪製起點,一般情況下的直觀想法是先求m dy dx 即x每增加1,y的增量 然後逐步遞增x,設新的點為x1 x j,則y1 round y j m 可以看到,這個過程涉及大量的浮點運算,效率上是比較低的 特別是在嵌入式應用中...