计算机图形学MFC实验--画线、画圆、画椭圆、区域填充算法(C++)

计算机图形学画线画圆画椭圆区域填充C++ MFC程序设计实验
本文内容包括对三种画线方法、中点画圆、中点画椭圆、两种区域填充程序的预期功能、设计思路详细分析及运行结果展示

(代码详见:

【免费】计算机图形学画线画圆画椭圆区域填充C++MFC程序设计资源-CSDN文库)

1 实验任务及内容

基于MFC实现以下功能:

  1. 分别用中点画线算法、DDA画线算法、Bresenham画线算法绘制直线;
  2. 使用中点画圆算法绘制圆;
  3. 使用中点画椭圆算法绘制椭圆;
  4. 分别使用4邻域内点表示和边界表示法实现区域填充。

2 实验环境

Visual Studio 2019

3 实验成果

MFC窗口绘图菜单功能设计如下图所示:

图3-1 MFC绘图菜单功能设计

3.1三种画线算法

3.1.1 DDA画线算法

1.程序设计

预期功能:将输入参数起点坐标(x0,y0)、终点坐标(x1,y1)以及颜色color,通过DDA法画线函数DDA_Line()的编写,以及编辑主框架(IDR_MAINFRAME-Menu)、添加对应的事件处理程序,实现MFC窗口交互下的直线的绘制。

设计思路:1)根据输入的起始点坐标可确定该直线斜率;2)考虑y随x的变化规律:x每增加1,y递增k(直线斜率),通过前一步的增量计算该步x、y的值(增量算法);3)|k|<=1时,以x递增计算y,|k|>1时,以y递增计算x。

按照以上思路编写函数,程序计算流程及步骤如图3-2所示:

图3-2 DDA画线算法计算流程示意

事件处理程序:对应代码如图3-3所示:

图3-3 DDA画线事件处理程序部分代码截图

2.运行结果

DDA画线运行结果如图3-4所示:

图3-4 DDA画线运行结果

3.1.2 中点画线算法

1.程序设计

预期功能:将输入参数起点坐标(x0,y0)、终点坐标(x,y)以及颜色color,通过编写midpoint_Line()函数、编辑主框架(IDR_MAINFRAME-Menu)、添加对应的事件处理程序,实现MFC窗口交互下的直线的绘制。

设计思路:1)通过判断中点M与交点Q的位置关系,确定下一个需要点亮的像素;2)构造判别式;3)增量算法;4)判别式符号决定像素,2倍的判别式代替原来,摆脱小数运算,提高算法效率。

按上述思路编写函数,程序计算流程及步骤如图3-5所示:

图3-5 中点画线算法计算流程示意

事件处理程序:对应代码如图3-6所示:

图3-6 中点画线事件处理程序部分代码截图

2.运行结果

中点画线运行结果如图3-7所示:

图3-7 中点画线运行结果

3.1.3 Bresenham画线算法

1.程序设计

预期功能:将输入参数起点坐标(x0,y0)、终点坐标(x1,y1)以及颜色color,通过编写bresenham_line()函数、编辑主框架(IDR_MAINFRAME-Menu)、添加对应的事件处理程序,实现MFC窗口交互下的直线的绘制。

设计思路:1)|k|<=1时,以x递增为步长计算y,|k|>1时,以y递增为步长计算x;2)误差项d的计算:①初值为0 ②每走一步,d=d+k ③一旦y方向上前进一步,d=d-1;3)2倍的∆x∆y代替原来,摆脱小数运算,提高效率。

按上述思路编写函数,程序计算流程及步骤如图3-8所示:

图3-8 Bresenham画线算法计算流程示意

事件处理程序:对应代码如图3-9所示:

图3-9 Bresenham画线事件处理程序部分代码截图

2.运行结果

Bresenham画线运行结果如图3-10所示:

图3-10 Bresenham画线运行结果

3.2 中点画圆算法

1.程序设计

预期功能:输入半径r、颜色color,通过编写midpoint_circle()函数、编辑主框架(IDR_MAINFRAME-Menu)、添加对应的事件处理程序,实现MFC窗口交互下的圆的绘制。

设计思路:1)利用圆的对称性——八分法画圆;2)构造判别式,判断当前点与圆的关系(点在圆内、圆外、圆上);3)增量算法;4)判别式d的初值与更新规则。

按上述思路编写函数,程序计算流程及步骤如图3-11所示:

图3-11中点画圆计算流程示意

事件处理程序:对应代码如图3-12所示:

图3-12 中点画圆事件处理程序部分代码截图

2.运行结果

中点画圆运行结果如图3-13所示:

图3-13 中点画圆运行结果

3.3 中点画椭圆算法

1.程序设计

预期功能:输入长半轴ry、短半轴ry、颜色color,通过编写mid_point_ellip ()函数、编辑主框架(IDR_MAINFRAME-Menu)、添加对应的事件处理程序,实现MFC窗口交互下的椭圆的绘制。

设计思路:1)与中点画圆法类似,可以利用椭圆的对称性——四分法画椭圆;2)构造判别式,判断当前点与椭圆的关系(点在椭圆内、椭圆外、椭圆上);3)同一四分之一椭圆上,x、y方向上变化速度的关系是分类讨论的关键;4)判别式p的初值与更新规则。

按上述思路编写函数,程序计算流程如图3-14所示:

图3-14 中点画椭圆计算流程示意

事件处理程序:对应代码如图3-15所示:

图3-15 中点画椭圆事件处理程序代码截图

2.运行结果

中点画椭圆运行结果如图3-16所示:

图3-16 中点画椭圆运行结果

3.4 区域填充—深度递归的种子填充算法

基本原理:从已知种子点出发,每填充一点,在其周围寻找新的种子点,重复该操作,直至无未填充的点,因此漫水法又称泛滥算法,递归深度大。

3.4.1 四邻域填充内点表示法

1.程序设计

预期功能:输入初始种子点坐标(x,y)、填充颜色newcolor,通过编写flood_fill4()函数、编辑主框架(IDR_MAINFRAME-Menu)、添加对应的事件处理程序,以中点画圆算法绘制的圆形为例,实现MFC窗口交互下圆域的填充。

设计思路:1)充分利用堆栈结构“先进后出”的特点,完成区域内部点的递归搜索及对应操作,保证栈中元素均为未判断的像素点,当前已判断或填充的元素均已出栈;2)可通过考察当前像素点颜色是否为填充颜色newcolor,来判断当前像素是否被填充。

搜索步骤:1)种子点入栈;2)判断栈是否非空;3)栈非空时,栈顶元素出栈,若为未填充的内部点,则将其以newcolor填充,继续考察与其连通的点,若均为未填充的内部点,则该点入栈;4)继续按照2)、3)进行判断和操作,直至栈空。

具体判断思路及递归搜索步骤见3-17:

图3-17 4邻域区域填充内点表示法流程示意

事件处理程序:对应代码如图3-18所示:

图3-18 4邻域区域填充内点表示法事件处理程序代码截图

2.运行效果

4邻域区域填充内点表示法运行结果如图3-19所示:

图3-19 4邻域区域填充内点表示法运行结果

3.4.2 四邻域填充边界表示法

1.程序设计

预期功能:输入初始种子点坐标(x,y)、边界颜色b_color、填充颜色newcolor,通过编写boundary_fill4()函数、编辑主框架(IDR_MAINFRAME-Menu)、添加对应的事件处理程序,以中点画圆算法绘制的圆形为例,实现MFC窗口交互下圆域的填充。

设计思路:1)沿用内点表示法的递归搜索思路;2)可通过考察当前像素点颜色是否为边界颜色和填充颜色newcolor,来判断当前像素是否被填充,保证填充内部像素的同时边界颜色不被覆盖。

具体判断思路及递归搜索步骤见图3-20:

图3-20 4邻域区域填充边界表示法流程示意

具体实现:对应代码如图3-21所示:

图3-21 4邻域区域填充边界表示法代码截图

事件处理程序:对应代码如图3-22所示:

图3-22 4邻域区域填充边界表示法事件处理程序代码截图

2.运行效果

4邻域区域填充边界表示法运行结果如图3-23所示:

图3-23 4邻域区域填充边界表示法运行结果

  1. 实验成果分析

本次实验中“像素点”被放大了10倍(具体代码见图4-1),像素颜色获取函数get_pixel()和像素颜色填充函数set_pixel()均以10倍的像素大小进行读、写操作(具体代码见图4-2、4-3),画布上的网格格外大,因此,“走样”现象也被放大,锯齿状边缘非常明显,以下内容将围绕同一图形的不同算法运行结果展开对比,进行浅析。

图4-1 网格绘制(网格大小放大10倍)

图4-2 像素颜色读取函数

图4-3 像素颜色填充函数

4.1 三种直线算法效果对比

下图分别为∆y∆x为0.857(上)、0.545(下)时三种画线算法生成的直线(颜色由浅到深依次为:DDA画线、中点画线、Bresenham画线生成的直线):

图4-4 斜率为0.857(上)和0.545(下)

由图,三种画线算法生成同一斜率的直线时,直线形状与走样趋势(锯齿形状)无明显区别。

4.2 四邻域填充内点表示和边界表示对比

下图分别为内点表示(左)和边界表示(右)的四邻域圆域填充:

图4-5 四邻域填充内点表示(左)和边界表示(右)

从图中看,内点表示和边界表示的区别仅限于:边界表示法区域边界颜色不同于区域内部颜色(填充颜色),更能突出边界。

程序代码详见:

【免费】计算机图形学画线画圆画椭圆区域填充C++MFC程序设计资源-CSDN文库

  • 20
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
中点画线算法是一种经典的直线绘制算法,其基本思路是利用笔在像素点中移动来绘制直线,具体实现如下: 在MFC中,可以通过CPoint类来表示像素点,CPoint类包含x和y两个成员变量,分别表示像素点在横向和纵向上的坐标。因此,中点画线算法的实现可以分为以下步骤: 1. 定义起点和终点的坐标。 2. 计算直线的斜率k和截距b。 3. 根据起点和终点的坐标值,确定直线的起点和终点。 4. 设置笔的颜色和宽度。 5. 在起点处绘制像素点,并根据斜率k的正负值决定每次在横向或纵向上移动一个像素点。 6. 根据斜率k的大小关系,计算出下一个像素点的坐标,并在该点绘制像素。 7. 重复执行步骤6,直到终点被绘制。 以下是一个简单的MFC程序,使用中点画线算法绘制一条直线: ```cpp void CMyView::OnDraw(CDC* pDC) { // 定义起点和终点的坐标 CPoint ptStart(100, 100); CPoint ptEnd(200, 200); // 计算直线的斜率k和截距b double k = (double)(ptEnd.y - ptStart.y) / (double)(ptEnd.x - ptStart.x); double b = ptStart.y - k * ptStart.x; // 根据起点和终点的坐标值,确定直线的起点和终点 int x0 = ptStart.x; int y0 = ptStart.y; int x1 = ptEnd.x; int y1 = ptEnd.y; // 设置笔的颜色和宽度 CPen pen(PS_SOLID, 1, RGB(255, 0, 0)); pDC->SelectObject(&pen); // 在起点处绘制像素点,并根据斜率k的正负值决定每次在横向或纵向上移动一个像素点 int x = x0; int y = y0; pDC->SetPixelV(x, y, RGB(255, 0, 0)); if (k >= 0 && k <= 1) { int d = 2 * (y1 - y0) - (x1 - x0); while (x < x1) { if (d > 0) { y++; d += 2 * ((y1 - y0) - (x1 - x0)); } else { d += 2 * (y1 - y0); } x++; pDC->SetPixelV(x, y, RGB(255, 0, 0)); } } else if (k > 1) { int d = 2 * (x1 - x0) - (y1 - y0); while (y < y1) { if (d > 0) { x++; d += 2 * ((x1 - x0) - (y1 - y0)); } else { d += 2 * (x1 - x0); } y++; pDC->SetPixelV(x, y, RGB(255, 0, 0)); } } else if (k < 0 && k >= -1) { int d = 2 * (y1 - y0) + (x1 - x0); while (x < x1) { if (d < 0) { y--; d += 2 * ((y1 - y0) + (x1 - x0)); } else { d += 2 * (y1 - y0); } x++; pDC->SetPixelV(x, y, RGB(255, 0, 0)); } } else if (k < -1) { int d = 2 * (x1 - x0) + (y1 - y0); while (y > y1) { if (d < 0) { x++; d += 2 * ((x1 - x0) + (y1 - y0)); } else { d += 2 * (x1 - x0); } y--; pDC->SetPixelV(x, y, RGB(255, 0, 0)); } } } ``` 在上述代码中,我们首先定义了起点和终点的坐标,然后计算出直线的斜率k和截距b,并根据起点和终点的坐标值确定直线的起点和终点。接着,我们设置笔的颜色和宽度,并在起点处绘制像素点。最后,我们根据斜率k的正负值和大小关系使用中点画线算法绘制直线,直到终点被绘制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

i-17

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

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

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

打赏作者

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

抵扣说明:

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

余额充值