计算机图形学常用算法实现1 DDA,中点画线法,bresenham算法

打算手动实现图形学中的绝大部分算法。
运行环境winform+c# (代码是通用的,如果在其他地方画图,只需要替换掉画点的函数即可)
我们的函数默认是按x坐标顺序递增传入的,因此在调用下面函数之前,需要保证p1.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;
                    }
                }
            }
        }

效果图如下所示:
计算机图形学常用算法实现1 DDA,中点画线法,bresenham算法_第1张图片

你可能感兴趣的:(图形学基础知识)