1. 程式人生 > >計算機圖形學之畫線(DDA、Bresenham、中點畫線) 針對各種斜率

計算機圖形學之畫線(DDA、Bresenham、中點畫線) 針對各種斜率

      為什麼寫這篇文章?

       博主開始也是到處參考研究了很多程式碼,發現要考慮任意斜率的話,很多程式碼都是用if語句來分別討論的,其實其中有很多重複的程式碼部分,我覺得不程式碼不簡潔,就到處查詢參考思考才總結出一些比較簡潔的程式碼,希望大家喜歡,也期待大家有更好的方法分享。

     其中的程式碼我是用JavaScript寫的,但其中原理是相通的,基本改改語法就都能用。

      進入正文:

  • 數值微分法DDA:  其中看x的斜率來確定增加的方向,DrawPixel(x,y,color)為畫點個人函式。
 function DDA(x0, y0, x1, y1, color) {
      var dx, dy, m, k;
      var incX, incY, x, y;
      dx = x1 - x0; dy = y1 - y0;
      //正則表示式:其中?前條件為true則m=Math.abs(dx) ,反之m=Math.abs(dy)
      m = (Math.abs(dx) > Math.abs(dy)) ? Math.abs(dx) : Math.abs(dy);//Math.abs取絕對值

      incX = dx / m;
      incY = dy / m;
      x = x0; y = y0;
      for (k = 1; k < m; k++) {
          x += incX;
          y += incY;
          DrawPixel(Math.floor(x + 0.5), Math.floor(y + 0.5), color);//Math.floor向下取整
      }
}
  • Bresenham畫線演算法:以dx來決定每次增加還是減少,這樣就把k<0的情況考慮進去,當 |k|>1時,就交換兩點的XY座標,再進行繪製,需要注意的是呼叫繪製點的函式時,要記得同時調換XY座標。
function Bresenham(x0, y0, x1, y1, color) {
   var x, y, dx, dy, e, m;
   dx = x1 - x0; dy = y1 - y0;
   var flag = Math.abs(dx) - Math.abs(dy);//判斷斜率是否大於1
   if (flag < 0) {//斜率大於1則交換XY座標
       m = y0; y0 = x0; x0 = m;
       m = y1; y1 = x1; x1 = m;
   }

   dx = x1 - x0; dy = y1 - y0;
   e = 2 * Math.abs(dy) - Math.abs(dx);
   x = x0; y = y0;
   incX = (dx > 0) ? 1 : -1; //每次增加步長,避免<0的情況
   incY = dy / Math.abs(dy);//同上的另一種表達方式

   for (var i = 0; i < (Math.abs(dx)-1) ; i++) {
       x += incX;
       if (e < 0)
           e += 2 * Math.abs(dy);
       else {
           y += incY;
           e = e + 2 * (Math.abs(dy) - Math.abs(dx));
       }

       if (flag < 0)//斜率大於1則交換XY座標
           DrawPixel(y, x, color);
       else
          DrawPixel(x, y, color);
    }
}
  • 中點畫線法:考慮方式大致同Bresenham演算法
 function MiddlePiont(x0, y0, x1, y1, color) {
    var dx, dy, d1, d2, d, x, y, m;
    dy = y0 - y1; dx = x1 - x0;
    var flag = Math.abs(dx) - Math.abs(dy);//判斷斜率是否大於1
    if (flag < 0) {//斜率大於1則交換XY座標
        m = y0; y0 = x0; x0 = m;
        m = y1; y1 = x1; x1 = m;
    }

    dy = y0 - y1; dx = x1 - x0;
    d = 2 * dy + Math.abs(dx);
    d1 = 2 * dy; d2 = 2 * (Math.abs(dx) + dy);
    x = x0; y = y0;
    var incX = (dx > 0) ? 1 : -1;//每次增加步長,避免<0的情況
    var incY = (dy > 0) ? -1 : 1;
             
    for (var i = 0; i < Math.abs(dx) ; i++) {
         x += incX;
         if (d < 0) { 
             y += incY; d += d2; }
         else
             d += d1;

         if (flag < 0)//斜率大於1則交換XY座標
             DrawPixel(y, x, color);
         else
             DrawPixel(x, y, color);
     }}