项目:图形编辑器
100011268-基于C++实现(界面)图形编辑器
一、架构图:
开发环境:
操作系统 | Windows 10 |
---|---|
编程语言 | C++ 11 |
外部库 | Qt 5.8,OpenGL |
编译器 | MinGW |
IDE | Qt Creator 4.2.1 |
二、功能:
- 新建文件,保存文件,打开文件
- 基本图形的绘制——直线、矩形、圆、椭圆、曲线、涂鸦笔
- 对图形的变换——平移、旋转、缩放
- 对图形的设置——颜色选择、线条粗细设置
- 对图形的修改——填充、删除、清除、撤销
- 文字编辑的插入(在代码内,但实验并不理想)
三、设计说明
3.1 矩形
矩形的类
矩形是Rectangular类和RectangularControl类来实现的,其中Rectangular类是继承SimpleFigure类,RectangularContro是继承FigureControl类。Rectangular类主要包含点的存储和矩形的底层绘图,RectangularContro类主要是存储所有的Rectangular类对象,并与qt进行交互,调用绘图界面。
矩形的生成算法
矩形的生成主要是两步:第一步是记录矩形的两个对角线角,第二步是通过两个对角线角点,来计算四条边上的像素点,再将所有像素点显示出来。
3.2 圆
Circle类继承SimpleFigure类和Area类。Circle类包含了圆的一些基本变量,圆心,半径,标记点,把手点,继承了SimpleFigure的轮廓点和Area类的填充点。Circle类提供了一些成员函数,能够对Circle对象进行一些操作,如平移,缩放,判断是否在圆上,删除,填充等。CircleControl类为操作Circle类提供了接口,实现鼠标,窗口工具栏对圆的操作,如在画布上画出图形,删除,清除,撤销等一系列操作功能。
绘制算法
圆轮廓的绘制:
3.3 椭圆
椭圆的类和数据结构
椭圆的实现是由MyEllipse和EllipseControl两个类来完成的,其中MyEllipse是继承于SimpleFigure类和Area类,ElllipseControl是继承于FigureControl类。MyEllipse类的主要功能在于数学和几何方面:计算椭圆圆周上的点并存在vector中;提供椭圆的缩放、旋转和平移功能。EllipseControl则是关于椭圆的编辑操作和用户交互:用vector保存所有画过的椭圆对象(MyEllipse是其成员变量),并基于用户鼠标操作生成椭圆、平移、旋转、缩放椭圆,删除和清空所有椭圆。
椭圆的几何特征是由其圆周上所有的点和其外接矩形的顶点确定的,这些点的指针均作为成员变量保存在MyEllipse类中的vector中,可以被遍历和查找。点的颜色和大小,决定了椭圆的颜色和椭圆圆周的粗细,由MyEllipse的基类SimpleFigure来设定。
椭圆生成算法
椭圆的生成是通过计算椭圆圆周上的像素点来实现的,采用了椭圆的bresenham 算法,该算法是一种生成椭圆的整数型算法,由于整个算法当中,均采用整数运算,生成椭圆的效率比较高。
由于椭圆是中心对称图形,我们只需要计算其1/4的部分,然后根据对称规律即可得到其他三部分的点。首先,将第一象限中的图形分为两部分,区域1是图形切线斜率大于-1的部分,区域2是图形切线斜率小于-1的部分,如图9所示。
(a)区域1 (b)区域2.
图1 第一象限分区示意图 图1 第一象限分区示意图
有了上述数学分析基础,接着进行下列bresenham算法(伪代码描述):
-
输入椭圆的中心点坐标和长短轴长度a,b;
-
得到中心在原点的椭圆上的第一个点坐标(0,b);
-
根据公式(1.2-1)来计算初始的D值;
-
在区域1中,从X0=0开始,不断递增至Xk,对于每个Xk位置,反复按照公式(1.2-2)或者公式(1.2-3)来计算决策参数Dk,若Dk小于0,则Yk不变,反之Yk要减小1。重复此过程,直到区域1边界点;
-
在区域2中,对于每个Yk位置,从k=0开始,反复按照公式(1.2-5)或者公式(1.2-6)计算决策参数Dk,若其小于0,则Xk减少1,反之则Xk保持不变,和Xk-1一样;
-
根据第一象限的点,对称求出其他三个象限的坐标点;
-
把所有的点存入vector当中。
3.4 曲线
曲线类和数据结构
曲线的实现是由Curve和CurveControl两个类来完成的,Curve类是继承于SimpleFigure类,CurveControl是继承于FigureControl类。Curve类的主要功能在于数学和几何方面:计算曲线上的点并存在vector中;提供缩放、旋转和平移功能。CurveControl则是关于曲线的编辑操作和用户交互:用vector保存所有画过的曲线对象,并基于用户鼠标操作生成曲线、平移、旋转、缩放曲线,删除和清空所有曲线。
曲线的几何特征是由其4个顶点确定的,这些点的指针均作为成员变量保存在Curve类中的vector中,可以被遍历和查找。点的颜色和大小,决定了曲线的颜色和曲线圆周的粗细,由基类SimpleFigure来设定。
曲线生成算法
在三阶Bézier曲线中有四个控制点,设第i个控制点为,则和分别为曲线的起点和终点。曲线上点的计算公式为:
将从0累计到1,从而可以计算得到曲线上从到的所有点。(其中每次增加0.001,以保证曲线的连续)
3.5 画笔
画笔的类和数据结构
画笔功能是通过Pen类和myPenControl类来实现的,其中Pen类是继承SimpleFigure类,myPenControl是继承FigureControl类。Pen类主要包含点的存储和线的底层绘图,myPenControl类主要是存储所有的Pen类对象,并与qt进行交互。
用户每次执行画笔功能,myPenControl便会鼠标的位置保存在Pen类对象当中,并将其显示在画布上,达到实时显示鼠标轨迹的效果。所有的Pen类对象的指针,存储在vector容器中,用于遍历、查找、删除等。
画笔的生成算法
画笔功能的算法,原理比较简单,即通过Qt捕捉鼠标移动轨迹上的点,将每个点的坐标存储在点的vector当中,然后,每保存一个点,便将所有的点遍历一遍,每两个点之间,用直线连接起来,这样就生成了一条实时的轨迹曲线。
3.6 文本框分析
文本框:如何在已有图层上插入文本是一个讨论点,我认为可以把文本框通过继承矩形类,来
- 数据结构
文本框的设计是通过继承矩形类,然后修改矩形的构造函数,通过键盘回调函数来输入文本,保存信息到文本框类中。
- 遇到的问题
其中思考过几种途径,包括通过模仿画笔,通过opengl库来绘制文本,但与画笔不同的是文本不能简单的通过点来制作;又思考到加载graphics库的文本绘制函数,但注意到了画布的问题。后面又考虑到QTextEdit库,但也不能输出到glwidget上来
最后采用的是Qt本身自带的QPainter来绘制,阅读说明,注意到QPainter的类构造函数中可以通过Qwidget的指针进行生成。本次项目的画布是GLWidget类的对象,是QWidget的派生类,但编译的时候一直报错,最后由于缺乏解决的渠道,未能解决这个问题。
体会:
首先由于我们的软件架构模式,我发现在矩形类对象生成的时候,根本无法找到画布GLwidget,这个问题在我们绘图,变换图形方面本身不是问题,但涉及到对画布本身进行操作的时候,感觉到了不如面向过程的编程方便,为解决这个问题,我不得不从glwidget的成员函数出发,向下一层一层的添加this指针指向glwidget。
四、使用说明
4.1 矩形
绘制
本程序绘制矩形的功能包括:根据用户鼠标拖动,生成对应的矩形,并可以设置矩形的外边框颜色、边框线条粗细。首先在已有画布的情况下,点击矩形功能,然后按下鼠标左键,并拖动,就可以得到相应的矩形,其中,鼠标移动的起点和终点是矩形的对角线角点,两点决定了矩形的位置和大小。
图x 矩形绘制实例
选中
只要用鼠标左键点击已有矩形的外边框,便可以选中矩形,选中的矩形,会显示四个角点,并用粉红色标记;显示中心点,用红色标记;显示把手点,用橘色标记。
平移
首先选中某个目标矩形,然后鼠标点击中心点,并拖动,则矩形将会沿着鼠标方向平移。
4.2 圆:
绘制圆
本程序可以绘制圆,在建立好画布的条件下,点击工具栏的“圆”,进入到圆绘制模式,通过点击鼠标左键,然后保持按下左键的同时拖动鼠标,松开鼠标左键后,即可画出一个圆。当拖动鼠标绘图时,鼠标拖动起始点为圆的圆心,同时生成圆的外接矩形,决定了圆的位置和大小,如图1所示。
该圆刚画出时,其外接矩形将会通过虚线标出,并显示其标记点(四个顶点、中心点和把手点),中心点和把手点之间有直线相连。
图1 绘制圆示意图
选中圆
当前刚绘制完的圆默认是被选中的状态,也可以选择其他已经画过的圆作为当前标记圆。选中的方法是用户的鼠标必须点击在某个圆的轮廓。
当某个圆被选中后,该圆的把手点用橘黄色标记,中心点用红色原点标记、外接矩形用蓝色虚线框显示、外接矩形四个顶点用紫色圆点显示,如图1所示。该圆会被置于所有图形的顶层。选中圆后,可以对其进行编辑操作。
圆编辑
选中某个圆后,可以对该圆进行编辑操作,包括:平移、旋转和缩放。
平移
当选中圆后,鼠标点击并拖动圆中心点,即可整体平移圆。鼠标移动的矢量即为圆的平移矢量。
缩放
用户选中目标圆后,点击圆外接矩形标记点,并移动鼠标,可以对当前圆进行放大或缩小,图2展示了缩放的示意图。
(a)选中的圆
(b)缩放之后的圆
图2 圆缩放示意图
填充:
选择想要填充的图形,(目前,圆,椭圆,矩形可以被填充),点击工具栏中的“填充”按钮,便能对图形填充颜色。颜色默认为绿色,若想改变颜色,则需在填充之前选择颜色。图3是填充功能的展示。
(a)选中的圆 (b)填充之后的圆
图3 填充示意图
4.3 椭圆
绘制椭圆
本程序可以绘制椭圆,在建立好画布的条件下,进入到椭圆绘制模式,通过点击鼠标左键,然后保持按下左键的同时拖动鼠标,松开鼠标左键后,即可画出一个椭圆。当拖动鼠标绘图时,鼠标拖动起始点和终止点构成了一个矩形的对角线顶点,该矩形为椭圆的外接矩形,决定了椭圆的位置和大小,如图1所示。
该椭圆刚画出时,其外接矩形将会通过虚线标出,并显示其标记点(四个顶点、中心点和把手点),中心点和把手点之间有直线相连。
图1 绘制椭圆示意图
选中椭圆
当前刚绘制完的椭圆默认是被选中的状态,也可以选择其他已经画过的椭圆作为当前标记椭圆。选中的方法是用户的鼠标必须点击在某个椭圆图形内部,或者是其标记点。
当某个椭圆被选中后,该椭圆的把手点用橘黄色标记,中心点用红色原点标记、外接矩形用蓝色虚线框显示、外接矩形四个顶点用紫色圆点显示,如图1所示。该椭圆会被置于所有图形的顶层。选中椭圆后,可以对其进行编辑操作。
椭圆编辑
选中某个椭圆后,可以对该椭圆进行编辑操作,包括:平移、旋转和缩放。
平移
当选中椭圆后,鼠标点击并拖动椭圆中心点,即可整体平移椭圆。鼠标移动的矢量即为椭圆的平移矢量。
旋转
选中目标椭圆,可以看到椭圆的把手点。点击并拖动这个把手点,就可以绕着椭圆中心旋转该椭圆。由于椭圆旋转后会变形,旋转功能只是实现90°旋转,即用户拖动把手点旋转,若拖动的角度小于90°则不旋转,大于90°则整个椭圆旋转90°。椭圆旋转操作示意图如图2所示。
(a)选中目标椭圆
(b)旋转后的椭圆
缩放
用户选中目标椭圆后,点击椭圆外接矩形标记点,并移动鼠标,可以对当前椭圆进行放大或缩小,图3展示了缩放的示意图。
(a)选中的椭圆 (b)缩放之后的椭圆
4.4 曲线
绘制曲线
本程序可以绘曲线,在建立好画布的条件下,点击工具栏的“曲线”,进入到曲线绘制模式,通过点击鼠标左键,然后在任意位置画下四个点,即可绘制出曲线。
该曲线刚画出时,其外接矩形将会通过虚线标出,并显示其标记点(四个顶点、中心点和把手点),中心点和把手点之间有直线相连。
选中曲线
当某个曲线被选中后,该曲线的把手点用橘黄色标记,中心点用红色原点标记、四个顶点用紫色圆点显示,如图1所示。该圆会被置于所有图形的顶层。选中圆后,可以对其进行编辑操作。
曲线编辑
选中某个曲线后,可以对该曲线进行编辑操作,包括:平移、旋转。
平移
当选中曲线后,鼠标点击并拖动中心点,即可整体平移。鼠标移动的矢量即为曲线的平移矢量。
4.5 画笔
本程序的画笔功能是:由鼠标操作,实现任意曲线的绘制。结合设定颜色和线宽,用户可以根据自己需要画出任意的曲线和曲线组合图案。
首先,在一块画布上,点击“画笔”工具,便开启了画笔模式,此后,按下鼠标左键,并拖动,就可以在画布上实时画出曲线。鼠标移动轨迹,即为线条的轨迹。若松开鼠标左键,则画笔功能停止;再次按下鼠标左键,可继续进行绘制轨迹曲线。如图4所示,使用画笔,可以画出鼠标移动轨迹。
由于画笔要实现的是画出任意轨迹曲线的功能,故没有选中、旋转和缩放功能。
图4 画笔使用实例
4.6 删除、清除、撤销:
在软件中,每一个生成的图像都作为一个Figure类保存在vector容器中,每一次删除操作,都把该图像从vector容器中删除,加入到另一个保存历史记录的vector中,以先进后出的原则实现撤销的操作。使用“清除”后,Figure类vector容器中所有的元素都被删除,所以无法被撤销。
删除:选中图形后,点击“删除”按钮,即可删除图形。
清除:点击“清除”按钮,即可清空画布上的所有图形。
撤销:在删除图形后,可点击工具栏中的“撤销”按钮,即可恢复上一次被删除后的图形。
“撤销”功能无法恢复被“清除”的图形。
具体操作可看操作视频。
五、测试分析
5.1 矩形
绘制
测试了矩形的绘制,不同的鼠标移动轨迹是否可以生成对应的矩形。同时测试了设定不同的颜色和宽度,发现都可以实现。测试表明矩形功能复合设计要求。
图10 矩形测试实例
平移
对原始矩形进行平移,如图所示。除了图中实例之外,我们还对目标矩形进行了多方向、连续移动,发现均能实现。在有多个矩形的画布中,也可以实现对选中矩形的平移。
(a)原始目标矩形 (b)平移后的矩形
图11 矩形平移测试实例
5.2 圆测试
绘制
鼠标点击拖动,绘制不同位置、不同形状、不同颜色和线宽的圆。如图3所示,根据测试,绘制圆功能正常。
(a)多个圆、任意位置和大小,不同线宽,颜色
平移
选中目标圆,对其进行平移操作,测试情况如图4所示。多次平移测试表明,圆可以实现任意平移操作,平移功能正常。
(a)目标圆 (b)平移后的圆
缩放
对目标椭圆进行缩放,如图5所示。对目标椭圆,可以进行任意放大和缩小,多次测试表明,缩放功能正常,填充图形也能正常缩放。
(a)目标圆1 (b)放大目标圆1
5.3 椭圆测试
绘制
鼠标点击拖动,绘制不同位置、不同形状、不同颜色和线宽的椭圆。如图4所示,根据测试,绘制椭圆功能正常。
(a)横向椭圆 (b)纵向椭圆
(c)多个椭圆、任意位置和大小 (d)多个椭圆,不同线宽、不同颜色
平移
选中目标椭圆,对其进行平移操作,测试情况如图5所示。多次平移测试表明,椭圆可以实现任意平移操作,平移功能正常。
(a)目标椭圆 (b)平移后的椭圆
旋转
对目标椭圆进行旋转操作,使得该椭圆旋转90°。经过对不同椭圆进行旋转测试,发现均可以实现正常的旋转功能。
(a)长轴水平的椭圆 (b)旋转之后的椭圆
(c)长轴竖直的椭圆 (d)旋转之后的椭圆
缩放
对目标椭圆进行缩放,如图7所示。对目标椭圆,可以进行任意放大和缩小,多次测试表明,缩放功能正常。
(a)目标椭圆 (b)缩小
(c)目标椭圆2 (d)放大目标椭圆2
5.3.1 曲线测试
绘制
鼠标点击拖动,绘制不同位置、不同形状、不同颜色和线宽的曲线。根据测试,绘制曲线功能正常。
平移
选中目标曲线,对其进行平移操作,测试情况如图所示。多次平移测试表明,曲线可以实现任意平移操作,平移功能正常。
旋转
对目标曲线进行旋转操作,使得该曲线旋转任意角度,发现均可以实现正常的旋转功能。
5.3.2 画笔
本程序画笔支持用户设定颜色、设定线宽,来画出曲线。如图8所示,可以用画笔功能画出任意曲线,也可以在同一画布当中画出多条曲线,并可以设定不同的颜色和线条宽度。测试表明,画笔可以实现设定功能。
(a)简单曲线 (b)多条曲线、多种颜色和线宽
总结:
经验:
本次大程序设计,能够帮助我们进一步地理解面向对象编程设计。在实现类的过程中,发现了类的设计需要提前精心的设计,在实现类的过程中了解到了类的设计和实现的不易,但在扩展性方面又有很大的便利。本次大程序的作业过程中,也让我们体会到了团队合作的重要性。
♻️ 资源
大小: 26.9MB
➡️ 资源下载:https://download.csdn.net/download/s1t16/87575070
注:如当前文章或代码侵犯了您的权益,请私信作者删除!