计算机图形学 | 基于MFC和二维变换的画图软件

我终于肝完了计算机图形学的作业,记录一下我的报告

  1. 关注我的博客https://blog.justlovesmile.top
  2. 我的这篇博客原文链接

报告里面没有代码,不过上传到github了

基于MFC和二维变换的画图软件

摘 要

本文描述了二维复合变换的基本方法和思想,根据鼠标位置坐标获取起始点pStart和终止点pEnd的坐标,设计实现每个基本图形的画图方法,根据pStart和pEnd即可确定基本图形的控制点,进而绘制对应图形。规范化齐次坐标以后,图形几何变换可以表示为图形控制点点集合的规范化齐次坐标矩阵与二维变换矩阵相乘的形式,分别设置二维变换矩阵的参数信息,设计实现对应的方法,即可实现图形的二维变换功能。

设 计

“基于二维复合变换的动画制作软件”的设计中包括以下几个部分:(1) 程序结构设计,(2)鼠标消息映射,(3) 图形绘制实现,(4) 图形变换,(5)动画扩展实现,(6)信息保存,(7)程序交互设计。

1 程序总体结构

1.1 总体结构设计
1.1.1 绘图设计

基本图形包括点,直线,曲线,自由画笔,矩形,圆形,椭圆,三角形,左箭头,上箭头,五角星,四角形,五边形共12钟类型,每个基本图形都有自己的编号,用户在选择基本图形后,被选择图形的编号信息保存到dstyle变量中,绘图模块即可根据dstyle中的编号绘制相应的图形。图形大小,位置信息由全局变量pStart和pEnd控制,pStart和pEnd分别为用户在窗口内拖动鼠标时的起点坐标和终点坐标。根据两个坐标确定一个矩形,按照比例,设置相应的控制点,再根据控制点即可绘制相应图形。绘图流程图见图1.1。

1.1.2 变换设计

图形变换包括图形移动,图形旋转,图形放缩。绘图模块绘制图形结束后,会将pStart,pEnd,style等基本信息存入图表中。例如,选择旋转类型后,执行对应函数,将图表中所有图形的位置信息修改,再执行重绘函数,按照点表内容依次重绘变换之后的图形,即可实现图形的旋转变换。变换流程图见图1.2。

图1.1 绘图流程图

图1.2 变换流程图

2 程序实现

2.1 鼠标绘图的消息映射

为了实现基本图形的绘制和组合,需要在项目的视图View类中定义鼠标左键按下OnLButtonDown,鼠标移动OnMouseMove,以及鼠标左键抬起OnLButtonUp的消息映射,以实现拖动鼠标绘图功能。当鼠标左键按下时,设置一个变量为true保存绘图状态并且记录按下时的点,记为pStart,只有当该变量为true时,鼠标移动时才会将绘图,当鼠标左键抬起时,该变量赋值为false,并保存此时的点,记为pEnd。
其中,在鼠标左键按下并移动时,使用橡皮筋技术,即移动过程中选用画笔颜色取反模式(SetROP2(R2_NOT)),即可消除移动过程中不断绘制的图形,在鼠标左键抬起时,设置画笔为颜色覆盖模式(SETROP2(R2_COPYPEN)),绘制最终的图形,并保存pStart点和pEnd点,以及笔的粗细,形状,颜色等其他信息。

2.2 图形绘制实现
2.2.1 点

由于单个点的像素太小,不利于在图形绘制中使用与观察。这里使用了画一个微型填充圆的方法代替原始像素点。

2.2.2 直线

从直线起的以下图形的绘制均为根据外接矩形绘制内部图形。绘制图形时,当点击鼠标左键时获取矩形起点,按住不放拖动鼠标直至放开左键,放开鼠标左键的位置记录为矩形的终点。直线的绘制则根据矩形起始点使用MoveTo()和LineTo()函数绘制。

2.2.3 等腰和直角三角形

在使用鼠标拉取的矩形中选取点位置并用画线函数连接点实现。三角形包括3个顶点。拉取矩形的起点坐标为(pStart.x,pStart.y),终点坐标为(pEnd.x,pEnd.y)。根据两种三角形在矩形中绘制时的对应比例,等腰三角形3个顶点坐标分别为:
P1 (pStart.x+pEnd.x)/2,pStart.y);
P2 (pStart.x,pEnd.y);
P3 (pEnd.x,pEnd.y);
直角三角形的三个顶点坐标为:
P1 (pStart.x,pStart.y);
P2 (pEnd.x,pEnd.y);
P3 (pStart.x,pEnd.y);

2.2.4 矩形和填充矩形

在使用鼠标拉取的矩形中获取了起始点和终止点后用矩形函数实现。拉取矩形的起点坐标为(pStart.x,pStart.y),终点坐标为(pEnd.x,pEnd.y)。要绘制矩形由绘制矩形的函数实现pdc->Rectangle(pStart.x , pStart.y , pEnd.x, pEnd.y)。绘制填充矩形则在绘制前使用画刷以填充内部。

2.2.5 圆形和填充圆

在使用鼠标拉取的矩形中获取了起始点后。将两点间的距离作为要画圆的半径r。使用绘制圆函数进行绘制pdc->Ellipse(pStart.x-r,pStart.y-r , pStart.x+r , pStart.y+r)。绘制填充矩形则在绘制前使用画刷以填充内部。

2.2.6 自由画笔

在鼠标左键按下,并且移动的过程中,通过不断触发OnMouseMove消息映射,在移动中的点的位置和上一个位置间连线,即可实现自由画笔功能。

2.2.7 左箭头

在使用鼠标拉取的矩形中选取点位置并用画线函数连接点实现。左箭头包括7个顶点。拉取矩形的起点坐标为(pStart.x,pStart.y),终点坐标为(pEnd.x,pEnd.y)。根据左箭头在矩形中绘制时的对应比例,7个顶点坐标为:
P1 (pStart.x, pStart.y-dy/2);
P2 (pStart.x+dx/2),pStart.y);
P3 (pStart.x+dx/2), pStart.y-dy/4);
P4 (pEnd.x, pStart.y-dy/4);
P5 (pEnd.x, pStart.y-3*dy/4);
P6 (pStart.x+dx/2), pStart.y-3*dy/4);
P7 (pStart.x+dx/2),pEnd.y);
其中dy=pStart.y-pEnd.y;dx= pEnd.x-pStart.x

2.2.8 上箭头

在使用鼠标拉取的矩形中选取点位置并用画线函数连接点实现。上箭头包括7个顶点。拉取矩形的起点坐标为(pStart.x,pStart.y),终点坐标为(pEnd.x,pEnd.y)。根据上箭头在矩形中绘制时的对应比例,7个顶点坐标为:
P1 (pStart.x, pStart.y-dy0/2);
P2 ( (pStart.x+dx0/2,pStart.y);
P3 (pEnd.x, pStart.y-dy0/2);
P4 (pStart.x+3*dx0/4, pStart.y-dy0/2);
P5 (pStart.x+3*dx0/4,pEnd.y);
P6 (pStart.x+dx0/4,pEnd.y);
P7 (pStart.x+dx0/4, pStart.y-dy0/2);
其中dy0=pStart.y-pEnd.y;dx0=pEnd.x-pStart.x

2.2.9 五角星

在使用鼠标拉取的矩形中选取点位置并用画线函数连接点实现。五角星绘制包括5个顶点。拉取矩形的起点坐标为(pStart.x,pStart.y),终点坐标为(pEnd.x,pEnd.y)。根据五角星在矩形中绘制时的对应比例,5个顶点坐标为:
P1(pStart.x+pEnd.x)/2),pStart.y);
P2(pStart.x+RX*(sin(72*pi/180)cos(54*pi/180))/2/sin(72*pi/180)),pEnd.y);
P3(pEnd.x, pStart.y+RY*(1-cos(72*pi/180))/(1+sin(54*pi/180)));
P4(pStart.x, pStart.y+RY*(1-cos(72*pi/180))/(1+sin(54*pi/180)));
P5(pStart.x+RX*(sin(72*pi/180)+cos(54*pi/180))/2/sin(72*pi/180),pEnd.y);
其中pi = 3.1415926;RX = -(pStart.x-pEnd.x);RY = -(pStart.y-pEnd.y);

2.2.10 五边形

在使用鼠标拉取的矩形中选取点位置并用画线函数连接点实现。五边形包括5个顶点。拉取矩形的起点坐标为(pStart.x,pStart.y),终点坐标为(pEnd.x,pEnd.y)。根据五边形在矩形中绘制时的对应比例,5个顶点坐标为:
P1 (pStart.x+pEnd.x)/2,pStart.y);
P2 (pStart.x,(pEnd.y-pStart.y)*0.41+pStart.y);
P3 (pStart.x+(pEnd.x - pStart.x)*0.19,pEnd.y);
P4 (pStart.x+(pEnd.x - pStart.x)*0.81,pEnd.y);
P5 (pEnd.x, (pEnd.y-pStart.y)*0.41+pStart.y);

2.2.11 四角星

在使用鼠标拉取的矩形中选取点位置并用画线函数连接点实现。四角星包括8个顶点。拉取矩形的起点坐标为(pStart.x,pStart.y),终点坐标为(pEnd.x,pEnd.y)。根据四角星在矩形中绘制时的对应比例,8个顶点坐标为:
P1 ((pStart.x+pEnd.x)/2,pStart.y)
P2 (pStart.x+(pEnd.x-pStart.x)*3/8,(pEnd.y-pStart.y)* 3/8+pStart.y);
P3 (pStart.x,(pStart.y+pEnd.y)/2);
P4 (pStart.x+(pEnd.x-pStart.x)* 3/8,(pEnd.y-pStart.y)*6/8+pStart.y);
P5 ((pStart.x + pEnd.x)/2),pEnd.y);
P6 (pStart.x+(pEnd.x-pStart.x)* 6/8,(pEnd.y-pStart.y)*6/8+pStart.y);
P7 (pEnd.x,(pStart.y+pEnd.y)/2);
P8 (pStart.x+(pEnd.x-pStart.x)*6/8,(pEnd.y-pStart.y)*3/8+pStart.y);

2.2.12 弧线

在使用鼠标拉取的矩形中获取了起始点后,使用绘制椭圆弧线函数进行绘制pdc->Arc(pStart.x,pStart.y,pEnd.x,pEnd.y,int((pStart.x+pEnd.x)/2),pStart.y,pEnd.x,int((pStart.y+pEnd.y)/2));

2.3 图形变换实现
2.3.1 图形移动

图形移动包括包括左移,右移和上移,下移,点表中存有每个图形的pStart点,pEnd点和其他样式信息,绘图函数可根据这些信息重新绘制对应图形,所以只要调用transform.tranlate()函数将pStart,pEnd的x,y坐标同时增加减少相同数值即可完成图形的上下左右移动。

2.3.2 图形旋转

图形旋转包括顺时针旋转和逆时针旋转。与其他的变换不同的是,旋转需要定义一个旋转中心,默认为坐标系原点。如果没有设置旋转中心,旋转变换可能会导致图形变换到窗口之外,所以设置坐标点(pStart+pEnd)/2为旋转中心,调用Transform.Rotate()函数,即可实现在原位置旋转变换。

2.3.3 图形放缩

图形放大和缩小是由pStart和pEnd坐标的等比变换实现的。每次放大,将pStart和pEnd的x,y坐标放大两倍,每次缩小将pStart和pEnd的x,y坐标设置为原来的1/2。经过多次放缩后,可能导致图形太大或者太小而不能正常显示的问题,所以每次放缩判断pStart和pEnd之间的距离,如果距离大于窗口距离,或距离小于5个像素则终止放缩并给出相应提示。

2.4 图形变换扩展
2.4.1 动画设计

通过自定义文本对话框类(Cchoosedig),实现通过输入框输入获取复合图形变换运动时间的功能,基于原有的图形变化函数,增加根据输入时间循环移动以及延时(Sleep())的功能,即实现了自定义动画时间的动画制作。

2.4.2 自定义点表结构

由于动画制作需要修改组合复杂图形的所有点的信息,因此需要遍历点集,再重绘所有图形,因此,自定义了一个结构体,用来存储每一个图形的信息,其中信息包括:起始点,终止点,图形类型,画笔类型,画笔粗细,画笔颜色,结构体如图2.1,然后为这个结构体创建链表,再修改文档类的串行化Serialize函数即可。

图2.1 自定义结构体

2.4.3 运动时间设置

为了自定义运动时间,采用了文本对话框,通过输入运动时间,从对话框获取信息,保存到变量,再传递到View类,实现动画制作功能。时间设置效果如图2.2所示。

图2.2 运动时间设置

2.4.4 图形重绘

对于图形重绘,先暂存当前所选择的图形类型,画笔,颜色等信息,再获取点表的长度,然后循环遍历点表,取出点表中的数据,赋值给CDC类的指针对象pdc,根据图形类型和其他信息画出所有对应的图形。最后恢复之前暂存的信息,即可实现图形重绘功能,且不影响当前选择的样式。

2.5 程序交互实现
2.5.1 绘图类型选择

通过点击菜单栏的图标按钮,如图2.3所示,可以设置绘制图形的类型。具体实现是,当按钮被点击,调用相应的响应函数设置dstyle,并设置cclick为false即可。

图2.3 菜单栏中选择绘图类型的按钮

2.5.2 画笔颜色选择

颜色设置是调用系统自带的颜色对话框(CColorDialog)完成对画笔、画刷颜色的选择,同时选用该对话框能够实现自定义颜色。颜色选择对话框如图2.4所示。

图2.4 颜色选择对话框

2.5.3 画笔类型选择

在菜单栏中,有画笔形状和画笔粗细可以选择。其中,画笔形状包含包含直线(PS_SOLID),点线(PS_DOT),虚线(PS_DASH),画笔粗细包括粗线,标准线和细线。根据选择的画笔类型,设置type和thickness的值即可。其中,画笔形状中的虚线和点线只有在画笔粗细为细线的时候才能正常显示,当画笔粗细为标准或者粗线时,画出来的都是实线。

2.5.4 清屏

在清屏时,首先会有弹窗提示是否确定清屏,点击“否”则取消操作,点击“是”则进行清屏。清屏功能的具体操作是先调用RedrawWindow()函数清屏,然后清空点表MyList并设置dstyle和cclick分别为初始值0和false即可。

2.5.5 回退

由于本项目把每个图形外接矩形的一对顶点保存在了点表MyList中的一个自定义的节点结构体中,所以在回退时,我们只需要删除点表中的最后一个节点,然后根据点表重新绘图即可。

3 程序运行效果

3.1 基本图形实现

设计实现了包含点,直线段,椭圆弧线,矩形,填充矩形,等腰三角形,直角三角形,椭圆,圆,填充圆,五边形,五角星,四角星,箭头等多种基础图形,并且实现画图以及选择画笔类型功能,初始窗口如图3.1所示,基础图形效果如图3.2所示。

图3.1 初始窗口

图3.2 基础图形效果

3.2 组合复杂图形以及整体变换

实现了基本图形组合成复杂图形的功能,并且具有回退,清空画布,颜色等功能,具有包含平移,旋转,放大缩小,输入动画时长的功能。组合复杂图形以及变换效果如图3.3所示。

图3.3 组合复杂图形及变换

  • 15
    点赞
  • 109
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
### 回答1: 计算机图形学是研究计算机如何生成、处理和显示图像的学科。基于MFC(Microsoft Foundation Class)的三维图形开发代码是指使用MFC技术来实现三维图形的生成和展示。 MFC是一种开发Windows图形界面应用程序的框架,通过封装和封装许多常用的Windows API,提供了一个方便易用的开发环境。在三维图形开发中,MFC可以用来处理图形窗口的创建与管理、鼠标与键盘事件的响应以及图形对象的绘制等。 在基于MFC的三维图形开发中,需要先创建一个图形窗口来展示图形结果。可以利用MFC提供的类和函数来实现窗口的创建和设置。然后,可以使用OpenGL或DirectX等图形库来进行三维图形的渲染。 在绘制三维图形时,可以定义图形的各种属性,比如顶点位置、颜色、纹理贴图等。通过MFC的消息机制,可以响应用户的输入事件,比如鼠标点击、键盘输入等,从而实现与三维图形互动。 除了渲染图形,还可以利用MFC的辅助类来实现其他图形处理功能,比如图像的加载、保存、旋转、缩放等。此外,还可以通过MFC提供的文件操作函数来读取和写入三维模型的数据。 在进行三维图形开发时,需要掌握MFC图形库的相关知识,比如MFC的消息机制、图形对象的管理、着色器编程等。还需要了解三维图形的基本原理和算法,比如物体的变换、投影、光照等。只有全面掌握这些技术,才能编写出高效、稳定且具有交互性的三维图形开发代码。 总之,基于MFC的三维图形开发代码是利用MFC框架和图形库来实现三维图形的生成、处理和展示。通过合理利用MFC提供的类和函数,完成图形窗口的创建、事件的响应以及图形对象的绘制等功能,实现高质量的三维图形开发。 ### 回答2: 计算机图形学是研究计算机如何生成、处理和显示图形的学科。基于MFC(Microsoft Foundation Class)的三维图形开发主要涉及使用MFC框架与相关库来实现三维图形的创建、修改和显示等功能。 MFC 是一种用于开发 Windows 程序的 C++ 类库,它提供了一整套类用来操作窗口、控制界面和处理消息等,通过使用 MFC,我们可以方便地创建出包含三维图形的 Windows 应用程序。 基于 MFC 的三维图形开发主要包括以下几个方面的代码编写: 1. 应用程序初始化:使用 MFC 提供的类和函数,通过创建应用程序对象、主窗口对象,并初始化相关设置,例如窗口标题、刷新率等。 2. 三维场景设置:通过使用相关库,例如 DirectX、OpenGL 等,创建三维场景,包括设置场景的大小、灯光、材质等。 3. 三维模型加载:通过使用相关库提供的函数,将三维模型从外部文件加载到内存中,并创建相应的数据结构,例如顶点缓冲区、纹理坐标等。 4. 三维模型渲染:通过使用 MFC 提供的窗口对象,将三维模型绘制到窗口上,并实现交互功能,例如鼠标控制模型旋转、键盘控制模型移动等。 5. 窗口消息处理:通过重写 MFC 提供的窗口消息处理函数,处理用户输入、窗口重绘等消息,并调用相关函数更新三维场景或模型。 以上是基于 MFC 的三维图形开发的基本代码流程。在实际开发中,还需了解相关库的具体使用方法,以及三维图形开发的基本原理,才能编写出功能完善且高效的代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JUST LOVE SMILE

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

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

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

打赏作者

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

抵扣说明:

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

余额充值