在實驗課上用自己的算法畫直線被diss效率低
花了半天時間看了下Bresenham算法真🐮🍺
總結一下其中的精妙之處
Bresebham直線生成算法的基本原理是,每次在最大位移方向上走一步,而另一個方向是走步還是不走步取決於誤差項的判別。
聲明k為斜率
在0≤k<1的情況下,假設當前點是P(x1,y1),則下一個點在Pu(x1+1,y1+1)與Pd(x1+1,y1)中選一。
以M表示Pu與Pd的中點,即M(x1+1,y1+0.5)。設Q是理想直線與x=xi+1的交點;
顯然,若M在Q的下方,則Pu(x1+1,y1+1)離直線較近,應取為下一個像素;否則應取Pd(x1+1,y1)。
理解並不難 主要在於實現
依據該算法的原理基本能夠實現
窩先試着自己寫了一會
如果要實現各個方向的二維直線繪制
需要考慮多種情況 寫出來很不美觀
教材上給出了更好的解決方案:
同樣以0≤k<1為例
每次選取下個點時理想直線的y坐標都步進k個單位長度
累加值即為誤差項di
當di大於0.5時選取Pu否則選取Pd並使di-1
令ei=di-0.5
則ei>0時選取Pu否則選取Pd
經過改進,算法的效率大幅提升
但其中在計算斜率與誤差項時會用到小數和除法
並且下一步的選擇只與誤差項的符號有關
因此可以進一步改進:
可知ei的值由三種值組成:ei=-1/2(初始值)+(n個)y/x(步進值)-(m個)1(調整值)...
同乘2x即得2*x*ei=-x+(n個)2*y-(m個)2*x....
這樣即可得到僅由整數構成的算法
以上僅為對0≤k<1情況下的討論
其余的情況類似
附一段雜亂無章的代碼
1 point<Type> now_point = start; 2 point<Type> e_step, point_step; 3 e_step.x = abs(step.x); 4 e_step.y = abs(step.y); 5 glBegin(GL_POINTS); 6 if (step.x == 0 && step.y == 0) //No Step 7 return; 8 point_step.x = (step.x == 0) ? 1 : step.x / e_step.x; 9 point_step.y = (step.y == 0) ? 1 : step.y / e_step.y; 10 if (step.x == 0) { // k is endless 11 do{ 12 glVertex2i(now_point.x, now_point.y); 13 now_point.y += point_step.y; 14 } while (now_point.y != end.y); 15 } 16 else if (step.y == 0) { //k is zero 17 do { 18 glVertex2i(now_point.x, now_point.y); 19 now_point.x += point_step.x; 20 } while (now_point.x != end.x); 21 } 22 else if (abs(step.y / step.x) == 0) { // |k| < 1 23 Type e = -e_step.x; 24 do { 25 glVertex2i(now_point.x, now_point.y); 26 e += 2 * e_step.y; 27 now_point.x += point_step.x; 28 if (e > 0) { 29 now_point.y += point_step.y; 30 e -= 2 * e_step.x; 31 } 32 } while (now_point.x != end.x); 33 } 34 else { // |k| >= 1 35 Type e = -e_step.y; 36 do { 37 glVertex2i(now_point.x, now_point.y); 38 e += 2 * e_step.x; 39 now_point.y += point_step.y; 40 if (e > 0) { 41 now_point.x += point_step.x; 42 e -= 2 * e_step.y; 43 } 44 } while (now_point.y != end.y); 45 } 46 glEnd(); 47 glFlush();
