(二)计算机图形学基本图形的生成(直线DDA算法,直线中点算法,Bresenham画圆算法)--附源码

系列文章:

(一)计算机图形学实验平台的建立--附源码

(二)计算机图形学基本图形的生成(直线DDA算法,直线中点算法,Bresenham画圆算法)--附源码

(三)计算机图形学基本图形的生成(二维图形裁剪Cohen-Sutherland算法+图形平移算法+图形旋转算法)--附源码

(四)计算机图形学基本图形的生成(扫描线填充算法+图形缩放算法+对称变换算法+消隐算法+金刚石图案算法)--附源码

环境:Win10+Visual Studio 2022 Community

在本次实验中需要用到上一篇文章实验内容的代码及环境,详情请见:传送门

目录

一、实验目的

二、实验过程

1.生成直线的DDA算法

(3)运行结果

2.生成直线的中点算法

(5)运行结果

3.生成圆的Bresenham算法

(6)运行结果


一、实验目的

1、熟练掌握生成直线的DDA算法

2、熟练掌握生成直线的中点算法

3、熟练掌握生成圆的Bresenham算法

二、实验过程

1.生成直线的DDA算法

(1)利用已经建立好的DDA直线操作框架,用DDA算法生成直线函数替换系统提供的画线函数g.DrawLine

private void Form1_MouseClick(object sender, MouseEventArgs e)
{
    Graphics g = CreateGraphics();  //创建图形设备
    Pen MyPen = new Pen(Color.Red, 1);
    if (MenuID == 1)
    {
        if (PressNum == 0)          //第一点,保留
        {
            FirstX = e.X;
            FirstY = e.Y;
            OldX = e.X;
            OldY = e.Y;
        }
        else                        //第二点,画线
        {
            DDALine1(FirstX, FirstY, e.X, e.Y);
        }
        PressNum++;
        if (PressNum >= 2)
        {
            PressNum = 0;           //画线完毕,清零,为画下一条线做准备
        }
    }
}

(2)建立DDALine1函数实现DDA直线算法

        private void DDALine1(int x0, int y0, int x1, int y1)
        {
            int x, flag;
            float m, y;
            Graphics g = CreateGraphics();  //创建图形设备
            if (x0 == x1 && y0 == y1) return;   //端点重叠,不画。这种情况不可忽略,否则程序有缺陷
            if (x0 == x1)   //垂直线
            {
                if (y0 > y1)    //保证y0为最小
                {
                    x = y0;
                    y0 = y1;
                    y1 = x;
                }
                for (x = y0; x <= y1; x++)
                {
                    g.DrawRectangle(Pens.Red, x1, x, 1, 1); //画点函数,在(x1,x)处画红点
                }
                return;
            }
            if (y0 == y1)   //水平线
            {
                if (x0 > x1)
                {
                    x = x0; x0 = x1; x1 = x;
                }
                for (x = x0; x <= x1; x++)
                {
                    g.DrawRectangle(Pens.Red, x, y0, 1, 1);
                }
                return;
            }
            if (x0 > x1)    //按照算法,(x0,y0)是左端点。如果不满足,就将(x0,y0)、(x1,y1)互换
            {
                x = x0; x0 = x1; x1 = x;
                x = y0; y0 = y1; y1 = x;
            }
            flag = 0;   //记录线段种类
            if (x1 - x0 > y1 - y0 && y1 - y0 > 0) flag = 1; //第一种线段,不做转化工作
            if (x1 - x0 > y0 - y1 && y0 - y1 > 0)   //第二种线段,转化
            {
                flag = 2;
                y0 = -y0;
                y1 = -y1;   //关于X轴对称,图形点Y坐标加负号
            }
            if (y1 - y0 > x1 - x0)  //第三种线段,关于y=x对称,图形点坐标x,y互换位置
            {
                flag = 3;
                x = x0; x0 = y0; y0 = x;
                x = x1; x1 = y1; y1 = x;
            }
            if (y0 - y1 > x1 - x0)  //第四种线段转化为第一种线段
            {
                flag = 4;
                x = x0; x0 = -y0; y0 = x;
                x = x1; x1 = -y1; y1 = x;
            }
            m = (float)(y1 - y0) / (float)(x1 - x0);
            for (x = x0, y = (float)y0; x <= x1; x++, y += m)
            {
                if (flag == 1) g.DrawRectangle(Pens.Red, x, (int)(y + 0.5), 1, 1);
                if (flag == 2) g.DrawRectangle(Pens.Red, x, -(int)(y + 0.5), 1, 1);
                if (flag == 3) g.DrawRectangle(Pens.Red, (int)(y + 0.5), x, 1, 1);
                if (flag == 3) g.DrawRectangle(Pens.Red, (int)(y + 0.5), -x, 1, 1);
            }
        }

(3)运行结果

2.生成直线的中点算法

(1)在Form1. cs[设计]页面中,点击、展开菜单项“基本图形生成”,选中子菜单项“中点直线”,并将子菜单项“中点直线”的Name属性值改为"MidLine"

(2)双击“中点直线”菜单项,系统自动建立菜单响应函数MidLine_Click,在该函数中插入如下语句

        private void MidLine_Click(object sender, EventArgs e)
        {
            MenuID = 2; PressNum = 0;
            Graphics g = CreateGraphics();  //创建图形设备
            g.Clear(BackColor1);    //设置背景色
        }

(3)因为中点直线的操作方法与DDA直线操作方法完全一样,因此只要能够对两者加以区分,就可以借用DDA直线鼠标操作实现程序部分。为此,做如下修改

private void Form1_MouseClick(object sender, MouseEventArgs e)
        {
            Graphics g = CreateGraphics();  //创建图形设备
            Pen MyPen = new Pen(Color.Red, 1);
            if (MenuID == 1 || MenuID == 2)
            {
                if (PressNum == 0)          //第一点,保留
                {
                    FirstX = e.X;
                    FirstY = e.Y;
                    OldX = e.X;
                    OldY = e.Y;
                }
                else                        //第二点,画线
                {
                    if (MenuID == 1)
                        DDALine1(FirstX, FirstY, e.X, e.Y);
                    if (MenuID == 2)
                        MidLine1(FirstX, FirstY, e.X, e.Y);
                }
                PressNum++;
                if (PressNum >= 2)
                {
                    PressNum = 0;           //画线完毕,清零,为画下一条线做准备
                }
            }
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            Graphics g = CreateGraphics();  //创建图形设备
            Pen BackPen = new Pen(BackColor1, 1);
            Pen MyPen = new Pen(ForeColor1, 1);
            if ((MenuID == 1 || MenuID == 2) && PressNum == 1)
            {
                if (!(e.X == OldX && e.Y == OldY))
                {
                    g.DrawLine(BackPen, FirstX, FirstY, OldX, OldY);
                    g.DrawLine(MyPen, FirstX, FirstY, e.X, e.Y);
                    OldX = e.X;
                    OldY = e.Y;
                }
            }
        }

(4)建立MidLine1函数实现中点直线算法

        private void MidLine1(int x0, int y0, int x1, int y1)
        {
            int x, y, d, flag;
            Graphics g = CreateGraphics();  //创建图形设备
            if (x0 == x1 && y0 == y1) return;   //端点重叠,不画
            if (x0 == x1)   //垂直线
            {
                if (y0 > y1)
                {
                    x = y0;
                    y0 = y1;
                    y1 = x;
                }
                for (y = y0; y <= y1; y++)
                {
                    g.DrawRectangle(Pens.Red, x1, y, 1, 1); //画点函数,在(x1,y)处画红点
                }
                return;
            }
            if (y0 == y1)   //水平线
            {
                if (x0 > x1)
                {
                    x = x0; x0 = x1; x1 = x;
                }
                for (x = x0; x <= x1; x++)
                {
                    g.DrawRectangle(Pens.Red, x, y0, 1, 1);//画点函数,在(x,y0)处画红点
                }
                return;
            }
            if (x0 > x1)    //起点(x0,y0)是左端点,如果不满足,就将(x0,y0)、(x1,y1)互换
            {
                x = x0; x0 = x1; x1 = x;
                x = y0; y0 = y1; y1 = x;
            }
            flag = 0;   //直线类别标记
            if (x1 - x0 > y1 - y0 && y1 - y0 > 0) flag = 1; //第一种线段,不做转化工作
            if (x1 - x0 > y0 - y1 && y0 - y1 > 0)   //第二种线段转化为第一种线段
            {
                flag = 2;
                y0 = -y0;
                y1 = -y1;
            }
            if (y1 - y0 > x1 - x0)  //第三种线段转化为第一种线段
            {
                flag = 3;
                x = x0; x0 = y0; y0 = x;
                x = x1; x1 = y1; y1 = x;
            }
            if (y0 - y1 > x1 - x0)  //第四种线段转化为第一种线段
            {
                flag = 4;
                x = x0; x0 = -y0; y0 = x;
                x = x1; x1 = -y1; y1 = x;
            }
            x = x0; y = y0; d = (x1 - x0) - 2 * (y1 - y0);
            while (x < x1 + 1)
            {
                if (flag == 1) g.DrawRectangle(Pens.Red, x, y, 1, 1);
                if (flag == 2) g.DrawRectangle(Pens.Red, x, -y, 1, 1);
                if (flag == 3) g.DrawRectangle(Pens.Red, y, x, 1, 1);
                if (flag == 3) g.DrawRectangle(Pens.Red, y, -x, 1, 1);
                x++;
                if (d > 0)
                {
                    d = d - 2 * (y1 - y0);
                }
                else
                {
                    y++;
                    d = d - 2 * ((y1 - y0) - (x1 - x0));
                }
            }
        }

(5)运行结果

3.生成圆的Bresenham算法

(1)在“基本图形生成”菜单项下选中子菜单“Bresenham圆”,将子菜单的Name属性值改为“BresenhamCircle”

(2)双击子菜单项“Bresenham圆”,在系统生成的菜单响应函数BresenhamCircle_Click中增添如下内容

        private void BresenhamCircle_Click(object sender, EventArgs e)
        {
            MenuID = 5; PressNum = 0;
            Graphics g = CreateGraphics();  //创建图形设备
            g.Clear(BackColor1);            //设置背景色
        }

(3)和直线生成一样,这里的响应函数只是做一个基本图形生成的类型标识,真正的图形生成操作在鼠标操作中完成。鼠标画圆的操作方式确定为:先用鼠标确定圆心,再用鼠标确定圆上任意一点。在鼠标点击响应函数中插人如下语句

        private void Form1_MouseClick(object sender, MouseEventArgs e)
        {
            Graphics g = CreateGraphics();  //创建图形设备
            Pen MyPen = new Pen(Color.Red, 1);
            if (MenuID == 1 || MenuID == 2)
            {
                if (PressNum == 0)          //第一点,保留
                {
                    FirstX = e.X;
                    FirstY = e.Y;
                    OldX = e.X;
                    OldY = e.Y;
                }
                else                        //第二点,画线
                {
                    if (MenuID == 1)
                        DDALine1(FirstX, FirstY, e.X, e.Y);
                    if (MenuID == 2)
                        MidLine1(FirstX, FirstY, e.X, e.Y);
                }
                PressNum++;
                if (PressNum >= 2)
                {
                    PressNum = 0;           //画线完毕,清零,为画下一条线做准备
                }
            }
            if (MenuID == 5) //画圆部分
            {
                if (PressNum == 0)    //圆心,保留
                {
                    FirstX = e.X;
                    FirstY = e.Y;
                }
                else //圆上任意一点,确定半径
                {
                    if (FirstX == e.X && FirstY == e.Y) return;
                    BresenhamCircle1(FirstX, FirstY, e.X, e.Y);
                }
                PressNum++;
                if (PressNum >= 2)
                {
                    PressNum = 0;           //画圆完毕,清零,为画下一个圆做准备
                }
            }
        }

(4)在鼠标移动响应函数中插入如下语句

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            Graphics g = CreateGraphics();  //创建图形设备
            Pen BackPen = new Pen(BackColor1, 1);
            Pen MyPen = new Pen(ForeColor1, 1);
            if ((MenuID == 1 || MenuID == 2) && PressNum == 1)
            {
                if (!(e.X == OldX && e.Y == OldY))
                {
                    g.DrawLine(BackPen, FirstX, FirstY, OldX, OldY);
                    g.DrawLine(MyPen, FirstX, FirstY, e.X, e.Y);
                    OldX = e.X;
                    OldY = e.Y;
                }
            }
            if (MenuID == 5 && PressNum == 1)
            {
                if (!(e.X == OldX && e.Y == OldY))
                {
                    //求圆半径
                    double r = Math.Sqrt((FirstX - OldX) * (FirstX - OldX) + (FirstY - OldY) * (FirstY - OldY));
                    int r1 = (int)(r + 0.5);    //取整
                    g.DrawEllipse(BackPen, FirstX - r1, FirstY - r1, 2 * r1, 2 * r1);//擦除旧圆
                    //求圆半径
                    r = Math.Sqrt((FirstX - e.X) * (FirstX - e.X) + (FirstY - e.Y) * (FirstY - e.Y));
                    r1 = (int)(r + 0.5);     //取整
                    g.DrawEllipse(MyPen, FirstX - r1, FirstY - r1, 2 * r1, 2 * r1);
                }
            }
        }

(5)g.DrawEllipse函数是系统提供的画椭圆函数,这里借助它,通过画一个长短轴相等的椭圆,实现画圆的橡皮筋。BresenhamCircle1函数是真正用圆的算法实现画圆的函数,还没建立。在程序Form1.cs程序中建立BresenhamCircle1函数如下

        private void BresenhamCircle1(int x0, int y0, int x1, int y1)
        {
            int r, d, x, y;
            Graphics g = CreateGraphics();  //创建图形设备
            r = (int)(Math.Sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) + 0.5);
            x = 0; y = r; d = 3 - 2 * r;
            while (x < y || x == y)
            {
                g.DrawRectangle(Pens.Blue, x + x0, y + y0, 1, 1);
                g.DrawRectangle(Pens.Red, -x + x0, y + y0, 1, 1);
                g.DrawRectangle(Pens.Green, x + x0, -y + y0, 1, 1);
                g.DrawRectangle(Pens.Yellow, -x + x0, -y + y0, 1, 1);
                g.DrawRectangle(Pens.Black, y + x0, x + y0, 1, 1);
                g.DrawRectangle(Pens.Red, -y + x0, x + y0, 1, 1);
                g.DrawRectangle(Pens.Red, y + x0, -x + y0, 1, 1);
                g.DrawRectangle(Pens.Red, -y + x0, -x + y0, 1, 1);
                x++;
                if (d < 0 || d == 0)
                {
                    d = d + 4 * x + 6;
                }
                else
                {
                    y = y - 1;
                    d = d + 4 * (x - y) + 10;
                }
            }
        }

(6)运行结果

  • 7
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

juechen333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值