1. 程式人生 > >計算機圖形常用演算法實現1 DDA,中點畫線法,bresenham演算法

計算機圖形常用演算法實現1 DDA,中點畫線法,bresenham演算法

打算手動實現圖形學中的絕大部分演算法。
執行環境winform+c# (程式碼是通用的,如果在其他地方畫圖,只需要替換掉畫點的函式即可)
我們的函式預設是按x座標順序遞增傳入的,因此在呼叫下面函式之前,需要保證p1.x<p2.x(可以減少討論數量)

		    Point pp = new Point();
                    if (p1.X > p2.X)
                    {
                        pp = p1;
                        p1 = p2;
                        p2 = pp;
                    }

1.DDA演算法
根據-0.5,0,0.5分割斜率,可以把直線分成四個部分,這個演算法本質比較簡單,注意討論好這四個方向的直線也沒多大問題。

void DDADrawLine(Point p1,Point p2)
        {   
           
            Graphics g = this.CreateGraphics();
            Brush p = new SolidBrush(Color.Red);
            int dx = p2.X - p1.X;
            int dy = p2.Y - p1.Y;
            float x, y;
            float k;
            if (Math.Abs(dx) > Math.Abs(dy))
            {
                k = (float)dy / dx;
                x = p1.X;
                y = p1.Y;
                for (int i = 0; i <= Math.Abs(dx); i++)
                {
                    g.FillRectangle(p, new RectangleF(x, (int)(y + 0.5), 1, 1));
                    y += k;
                    x++;
                }
            }
            else if (Math.Abs(dx) < Math.Abs(dy))
            {
                k = (float)dx / dy;
                x = p1.X;
                y = p1.Y;
                for (int i = 0; i <= Math.Abs(dy); i++)
                {
                    g.FillRectangle(p, new RectangleF((int)(x + 0.5), y, 1, 1));
                    if (p1.Y < p2.Y)
                    {
                        y++;
                        x += k;
                    }
                    else
                    {
                        y--;
                        x -= k;
                    }
                }
            }
        }

2.中點畫線法 還是根據上述討論分割四個部分,然後四個部分的引數都有些許不同,需要重新推導,具體每個方向的增量可以參考程式碼部分,程式碼的長度實際上是可以優化的,但是這樣寫容易理解一點。

       void MidPointDrawLine(Point p1, Point p2)
        {
            //分四種情況討論
            Graphics g = this.CreateGraphics();
            Brush p = new SolidBrush(Color.Red);
            int a = p1.Y - p2.Y;
            int b = p2.X - p1.X;
            int d;
            int d1;
            int d2;
            int x = p1.X;
            int y = p1.Y;
            if (Math.Abs(b) > Math.Abs(a))
            {
                //case1 
                if (p1.Y < p2.Y)
                {
                    d = 2 * a + b;
                    d1 = 2 * a;
                    d2 = 2 * a + 2 * b;
                    for (; x < p2.X; x++)
                    {
                        g.FillRectangle(p, new RectangleF(x, y, 1, 1));
                        if (d < 0)
                        {
                            y++;
                            d += d2;
                        }
                        else
                            d += d1;
                    }
                }
                //case2
                else
                {
                    a = -a;
                    b = -b;
                    d = 2 * a - b;
                    d1 = 2 * a;
                    d2 = 2 * a - 2 * b;
                    for (; x < p2.X; x++)
                    {
                        g.FillRectangle(p, new RectangleF(x, y, 1, 1));
                        if (d < 0)
                        {
                            y--;
                            d += d2;
                        }
                        else
                            d += d1;
                    }
                }

            }
            else
            {
                //case3
                if(y < p2.Y)
                {
                    a = -a;
                    b = -b;
                    d = 2 * b + a;
                    d1 = 2 * b;
                    d2 = 2 * a + 2 * b;
                    for (; y < p2.Y; y++)
                    {
                        g.FillRectangle(p, new RectangleF(x, y, 1, 1));
                        if (d < 0)
                        {
                            d += d2;
                            x++;
                        }
                        else
                        {
                            d += d1;
                        }
                    }
                }
                else
                {
                    d = a - 2 * b;
                    d1 = -2 * b;
                    d2 = 2 * a - 2 * b;
                    for (; y > p2.Y; y--)
                    {
                        g.FillRectangle(p, new RectangleF(x, y, 1, 1));
                        if (d < 0)
                        {
                            d += d2;
                            x++;
                        }
                        else
                        {
                            d += d1;
                        }
                    }
                }
            }
        }

3.bresenham演算法,也是不同方向的引數不同,具體推導結果可以參照下面(建議每個方向都手動推導一遍,加深對演算法的理解)

      void BresenhamDrawLine(Point p1, Point p2)
        {
            //分四種情況討論
            Graphics g = this.CreateGraphics();
            Brush p = new SolidBrush(Color.Red);
            int dx = p2.X - p1.X;
            int dy = p2.Y - p1.Y;
            int e;
            int x = p1.X;
            int y = p1.Y;
            //case 1: 
            if (Math.Abs(dx) > Math.Abs(dy) && p1.Y < p2.Y)
            {
                e = -dx;
                for (int i = 0; i <= dx; i++)
                {
                    g.FillRectangle(p, new RectangleF(x, y, 1, 1));
                    x++;
                    e += 2 * dy;
                    if (e > 0)
                    {
                        y++;
                        e -= 2 * dx;
                    }
                }
            }
            //case2
            if (Math.Abs(dx) < Math.Abs(dy) && p1.Y < p2.Y)
            {
                e = -dy;
                for (int i = 0; i <= dy; i++)
                {
                    g.FillRectangle(p, new RectangleF(x, y, 1, 1));
                    y++;
                    e += 2 * dx;
                    if (e > 0)
                    {
                        x++;
                        e -= 2 * dy;
                    }
                }
            }
            //case 3: 
            if (Math.Abs(dx) > Math.Abs(dy) && p1.Y > p2.Y)
            {
                e = dx;
                for (int i = 0; i <= dx; i++)
                {
                    g.FillRectangle(p, new RectangleF(x, y, 1, 1));
                    x++;
                    e += 2 * dy;
                    if (e < 0)
                    {
                        y--;
                        e += 2 * dx;
                    }
                }
            }
            //case4
            if (Math.Abs(dx) < Math.Abs(dy) && p1.Y > p2.Y)
            {
                e = dy;
                for (int i = 0; i <= Math.Abs(dy); i++)
                {
                    g.FillRectangle(p, new RectangleF(x, y, 1, 1));
                    y--;
                    e += 2 * dx;
                    if (e > 0)
                    {
                        x++;
                        e += 2 * dy;
                    }
                }
            }
        }

效果圖如下所示:
在這裡插入圖片描述