《计算机图形学》系统技术报告

欧阳鸿荣 161220096

(南京大学 计算机科学与技术系 南京 210093)

【摘要】:本绘图系统采用了面向对象设计,以 C++为基础,使用 Qt的GUI框架,完成了图形学实验中要求的所有功能。实现了直线、曲线、圆、椭圆和多边形的输入,编辑和平移、旋转缩放等变换功能,同时实现了直线的裁剪、任意区域的填充以及二维图形的存储功能,能够将绘制出来的图形保存为图像。并且支持三维模型的显示,能够载入并显示一个OFF格式的三维模型。

《计算机图形学》系统技术报告1.综述1.1 基本功能:1.2 扩展功能:1.3 演示2.算法介绍2.1 直线绘制算法2.11 算法一:DDA直线算法(1)基本原理(2)理论绘制过程(3)算法的C++实现2.11 算法二:Bresenham直线算法(1)基本原理(2)理论绘制过程(3)算法的C++实现2.2 曲线绘制算法贝塞尔曲线算法(1)基本原理(2)理论绘制过程(3)绘制的代码2.3 圆绘制算法2.31 算法一: 中点圆算法(1)基本原理(2)优点(3)理论绘制过程(4)算法的C++实现2.32 算法二: Bresenham 画圆算法(1)基本原理(2)理论绘制过程(3)算法的C++实现2.4 椭圆绘制算法中点椭圆算法(1)基本原理(2)理论绘制过程(3)算法的C++实现2.5 平移变换算法 (1)基本原理(2)算法实现(3)算法的C++实现2.6 旋转变换算法 (1)基本原理(2)算法实现(3) C++实现实现2.7 放缩变换算法 (1)基本原理(2)算法实现(3)算法的C++实现2.8 泛滥区域填充算法(1)基本定义(2)填充算法(3)C++代码实现2.8 直线裁剪算法梁友栋-Barsky参数裁剪算法(1)基本原理(2)优点——与Cohen-Sutherland算法的比较(3)算法过程(4)算法的C++实现3.系统介绍3.1 实验环境3.2 系统组织3.2.1 系统结构和类关系图3.2.2程序基本流程4.性能测试4.1 直线测试4.2 曲线测试4.3 圆测试4.4 椭圆测试4.5 多边形测试4.6 填充测试5.总结6.致谢7.参考文献

1.综述

系统名语言和框架IDE编译器
PaintYoungC++和Qt 5.11.2Qt CreatorMinGW 5.3.0

该系统按照最初预期实现了所有要求实现的功能

1.1 基本功能:

  1. 二维图形的输入功能:
    • 直线、曲线、圆、椭圆、多边形的输入实现

      • 类画图软件,用鼠标交互
      • 直线实现了Bresenham和DDA算法
      • 曲线实现了贝塞尔曲线
      • 圆实现了Bresenham和中点圆算法
      • 椭圆实现了中点椭圆算法
    • 填充区域的输入

      • 实现了类似油漆桶的功能,使用的是洪泛填充算法
      • 鼠标点击区域,洪泛填充与区域颜色相同的区域
  2. 二维图形的编辑功能:
    • 直线、曲线、圆,椭圆,多边形的编辑

      • 直线能编辑起点、终点
      • 曲线能编辑贝赛尔曲线的各个控制点
      • 圆能编辑半径
      • 椭圆能编辑长轴a和短轴b的长度
      • 多边形能编辑任意顶点
      • 鼠标点击拖动交互编辑,更加自由
  3. 二维图形的裁剪功能
    • 实现直线的裁剪

      • 使用梁友栋算法对直线进行裁剪
    • 裁剪窗口可用鼠标点击拖动输入

    • 裁剪后的图形仍然可以编辑

  4. 二维图形的变换功能
    • 直线、曲线、圆、椭圆、多边形的平移

    • 直线、曲线、圆、椭圆、多边形的旋转

      • 任意角度旋转

      • 直线、圆的旋转实现了精度控制

        • 旋转次数不多的情况下,长度/半径误差在1以内
    • 直线、曲线、圆、椭圆、多边形的缩放

    • 对变换后的图形仍然可以编辑

  5. 二维图形的存储功能
    • 可以将绘制出来的图形保存为图像
  6. 三维模型的显示功能
    • 可以载入并显示一个OFF格式的三维模型
    • 载入后可以通过键盘控制观察的视角和三维模型的旋转

1.2 扩展功能:

  1. 画布的创建,多画布切换
  2. 颜色的选择
  3. 增加了画笔和笔刷的功能
  4. 清屏和撤销的功能
  5. 打开图片编辑的功能

1.3 演示

2.算法介绍

2.1 直线绘制算法

2.11 算法一:DDA直线算法

(1)基本原理

数值差分分析DDA(digital differential analyzer)算法:直接利用的线段扫描转换算法,利用光栅特性(屏幕单位网格表示像素列阵),使用方向单位增量(用)来离散取样,并逐步计算沿线路径各像素位置。在一个坐标轴上以单位间隔对线段离散取样,确定另一个坐标轴上最靠近线段路径的对应整数值。

(2)理论绘制过程

1.具有正斜率时

1.1 从左到右生成线段。

若斜率 ,在x方向以单位间隔取样,以增量形式顺序计算每个y值。下标k取整数值从k=1开始递增。为0与1间的任意实数,计算出的坐标值必须取整。

1.2 从右端点到左端点生成线段,取

1.3 若斜率m>1,从左到右生成线段。在y方向以单位间隔取样,顺序计算每个x值。下标取整数值从1开始递增,直至最后端点。计算出的坐标值必须取整。

1.4 若从右到左生成线段,取

2.具有负斜率时

2.1 假如斜率的绝对值小于1时,

2.2 假如斜率的绝对值大于1时,

(3)算法的C++实现

2.11 算法二:Bresenham直线算法

(1)基本原理

Bresenham直线算法是Bresenham提出的一种算法:采用整数增量运算,精确而有效的光栅设备线生成算法。它可用于其它曲线显示。根据光栅扫描原理(逐个像素和逐条扫描线显示图形),线段离散过程中的每一放样位置上只可能有两个像素更接近于线段路径。Bresenham算法引入一个整型参量来衡量“两候选像素与实际线路径点间的偏移关系”。Bresenham算法通过对整型参量值符号的检测,选择候选像素中离实际线路径近的像素作为线的一个离散点。

(2)理论绘制过程

假设直线由+1个点组成,且起点到终点的坐标分别为:,第步的决策参数为,则有纵坐标和决策参数的递推公式如下:

1.若斜率 ,则有

2.若斜率 ,则有

2.若斜率 ,则有

(3)算法的C++实现

2.2 曲线绘制算法

贝塞尔曲线算法

(1)基本原理

贝塞尔曲线是通过一组多边折线的各个顶点唯一定义出来的。曲线的形状趋近于多边折线的形状。贝塞尔曲线可以拟合任何数目的控制顶点。一般通过基函数多项式来描述贝赛尔曲线。

则可以通过递归定义得到贝塞尔曲线上点的坐标

其中,,

(2)理论绘制过程

这里我主要简述德卡斯特里奥(de Casteljau)算法:该算法描述从参数计算次曲线贝塞尔型值点的过程。对于某一个特定的参数,有计算公式如下:

则当时,计算结果为顶点本身。而曲线上的型值点为

如上图是三次贝塞尔曲线在某个值下的计算过程(的变化生成多个离散型值点:

由此,只需令在0到1之间变化,则可以根据该原理绘制贝塞尔曲线。

(3)绘制的代码

由于曲线的代码量较大,因此这里没有直接给出。总的来说,用户从鼠标输入曲线的各个控制点并且选择曲线的绘制后,则对参数,使得的,递增步长为的初始情况下,对每个的控制点使用德卡斯特里奥算法,对个控制点则通过轮的递归,从而找到型值点。然后将各个型值点之间用直线连接做近似得到曲线。(修改的递增步长,曲线会更为精准,但是与之相对的是速度更加缓慢)。效率与精度,这是一个值得思考的问题。

2.3 圆绘制算法

2.31 算法一: 中点圆算法

(1)基本原理

中点圆算法通过决策参数,在候选像素中选择接近圆周的像素。避免平方根运算,直接采用像素与圆距离的平方作为判决依据。通过检验两候选像素中点与圆周边界的相对位置关系(圆周边界的内或外)来选择像素。

(2)优点

适应性强:易应用于其它圆锥曲线。误差可控:对于整数圆半径,生成与Bresenham算法相同的像素位置。且所确定像素位置误差限制在半个像素以内。

(3)理论绘制过程

根据圆的对称性,只绘制了八分之一圆,其余部分通过对称性即可得到坐标。使用经过改良的中点圆算法,使用递推,减少了计算量,并且避免了浮点运算。算法过程如下:

  1. 输入圆半径r和圆心,并得到圆心在原点的圆周上的第一点为

  2. 计算圆周点的初始决策参数值为:

  3. 从k=0开始每个取样位置位置处完成下列检测

    • ,选择像素位置:;且
    • ,选择像素位置:;且
    • 其中有:
  4. 确定在其它七个八分圆中的对称点

  5. 将计算出的像素位置移动到中心在的圆路径上,即:对像素位置进行平移

    重复步骤3到5,直到

(4)算法的C++实现

2.32 算法二: Bresenham 画圆算法

(1)基本原理

利用圆的对称性,我们只需要对一个八分圆进行扫描转换。如下图,如下图,在 的 1/8 圆周上,像素坐标 值单调增加, 值单调减少。设第步已确定是要画圆上的象素点,看第步象素点应如何确定。下一个象素点只能是中的一个

(2)理论绘制过程

有判别式如下:

则根据判别式,可以得到如下结果:

根据递推公式有:

因此我们可以得到如下常规画法: 做判别量

(3)算法的C++实现

2.4 椭圆绘制算法

中点椭圆算法

(1)基本原理

考虑椭圆沿长轴和短轴不同而修改圆生成算法来实现椭圆生成。

给定长短轴参数(假设)和椭圆中心位置,利用平移:先确定中心在原点的标准位置的椭圆点;然后将点变换为圆心在的点。再利用对称性:生成第一象限内的椭圆弧,再利用对称性求出其它三个象限的对应点。

 

(2)理论绘制过程

根据椭圆的对称性,只绘制四分之一椭圆,其余部分通过对称性即可得到坐标。算法过程如下

  1. 输入和中心,得到中心在原点的椭圆上的第一个点:

  2. 计算区域1中决策参数的初值为:

  3. 在区域1中每个位置处,从k=0开始,完成下列测试

    • ,椭圆的下一个离散点为, 且:
    • ,椭圆的下一个离散点为, 且:
    • 其中有:
    • 循环到:
  4. 使用区域1中最后点计算区域2参数初值为

  5. 在区域2的每个位置处,从k=0开始,完成下列检测

    • •假如,椭圆下一点选为且:,
    • •否则,沿椭圆的下一个点为, 且:
    • 使用与区域1中相同的x和y增量计算
    • 循环直至
  6. 确定其它三个像限中对称的点。

  7. 将每个计算出的像素位置的椭圆轨迹上,并且按照坐标之绘点

(3)算法的C++实现

2.5 平移变换算法

(1)基本原理

平移是将物体沿着直线路径从一个坐标位置到另一个坐标位置重定位。对于原始位置平移 到新位置 的移动满足

(2)算法实现

给每一个图形都定义一个中心点(一般是对称中心或外接矩形的中心),绘制时加粗显示辅助,用户通过鼠标拖动中心点得到偏移量dx和dy。对于不同图形的平移,采取不同的实现方法:

  1. 直线:对线上的起始点和顶点平移dx和dy,然后重新绘制
  2. 圆:平移圆心和圆周上的点(决定半径),然后重新绘制
  3. 椭圆:平移中心和外界矩形的一个顶点(决定a、b),然后重新绘制
  4. 多边形:平移所有的顶点,然后重新绘制
(3)算法的C++实现

这里以直线的平移代码做例子,曲线、圆、椭圆和多边形原理相同。

用户实际使用时通过拖动图形的中心点进行平移。鼠标移动时,计算中心点横坐标和纵坐标的变化量,从而将图形中各个点都平移相同的偏差值,由此实现整个图形的平移。

2.6 旋转变换算法

(1)基本原理

旋转是沿平面内圆弧路径重定位。指定旋转基准点位置旋转角,对任意基准位置的旋转

(2)算法实现

给每一个图形都定义一个旋转点,绘制时加粗显示辅助,用户通过鼠标拖动中心点得到旋转角

对于不同图形的旋转,采取不同的实现方法:

  1. 直线:直线的旋转点定义为四等分点。

    • 用户操作旋转点,得到旋转角,然后对直线的两端点旋转,然后重新绘制
  2. :圆的旋转点定义为在的位置。(圆的旋转没必要就是了)

    • 用户操作旋转点,得到旋转角,然后对圆周上的点旋转,然后重新绘制
  3. 椭圆:椭圆的旋转点相对于其他图形略有不同。

    • 由于椭圆的中点椭圆算法只能实现对称轴垂直或者平行坐标轴的椭圆,因此在不引入其他算法的情况下,椭圆的旋转我定义了一个“偏向角”来付诸实现。

      • 的初始值为0,为了方便叙述,假设椭圆中心为,对旋转点,为向量的夹角,而实际处理时为了方便,当夹角超过时,对取负
      • 从而每次旋转时,只是对椭圆的旋转角做出了改变,但是实际上椭圆Ellipse类的对象中椭圆的关键信息并没有改变,只是每次绘制时,对椭圆的每个顶点都旋转角,这样就实现了旋转。与此同时,编辑的时候对编辑点也通过转化为未旋转前椭圆的编辑,这样让旋转后的椭圆也能够编辑
      • 但是此方法有一个缺陷,就是椭圆的旋转由于是对点的旋转实现的,因此椭圆会变得稀疏,或者说变成不连续的椭圆。我解决这个的办法是每次绘图时画2个像素增加椭圆边界的宽度。
  4. 多边形和曲线:多边形和曲线的旋转点定义与椭圆类似,但是也有区别

    • 由于多边形的绘制是对各个端点连线,曲线的绘制是由各个控制点决定的(因为我实现的是贝赛尔曲线),因此每次都对图形旋转的差值,但是旋转时保持旋转中心不动
(3) C++实现实现

这里主要介绍旋转时用到的一些辅助函数

(1) 角度函数:对于点A绕着点CENTER旋转到点B的情况,用余弦定理得到角

(2) 顺逆时针判断函数这并不是真正的旋转角,故通过判断顺逆时针来对进行修正得到角(通过线性规划)

根据旋转方向对处理得到旋转角,便可以对点进行旋转

(3) 旋转误差修正函数

这是在实现圆的旋转后(虽然圆的旋转并无意义,但是起码放大了精度损失这个问题)发现的,由于旋转具有一定的精度损失(像素点都是整数的坐标),因此当精度累积后,可能会导致旋转失真甚至图形不断放大或者缩小。因此我采取了3个措施来实现旋转误差的修正:

(1)旋转时,在double转int时加上修正参数0.5

(2)其中ROTATE_ACCURACY是误差的容许值,ridus是旋转前圆的半径,x,y分别是旋转后的点。由于绕着圆心旋转,因此就寻找以的附近在点集的范围内到圆心距离与原半径误差最小的点。这样确保了误差不会太大

(3)由于半径的计算也有误差,因此在一次旋转中,对每次求得的半径取平均,以求达到稳定。

基于上述算法,后期对于直线的旋转也进行了相应的校正处理

2.7 放缩变换算法

(1)基本原理

我实现的是相对于原点的缩放。将每个顶点坐标乘以缩放系数到得到新坐标 的移动满足

(2)算法实现
  1. 直线:对线上的起始点和顶点放缩,然后重新绘制
  2. :放缩圆心和圆周上的点(决定半径),然后重新绘制
  3. 椭圆:放缩中心和外界矩形的一个顶点(决定a、b),然后重新绘制
  4. 多边形和曲线:放缩所有的顶点,然后重新绘制
(3)算法的C++实现

这里采用直线的做例子,其中ZOOM_INZOOM_OUT是缩放参数,在constparam.h中定义,两者互为倒数。这里对于自定义的Point类重载了其乘法,得以直接对坐标进行变换

2.8 泛滥区域填充算法

(1)基本定义

泛滥填充算法:区域内部用单一颜色定义的区域填充。通过替换指定的内部颜色来对这个区域着色(填充)。

(2)填充算法

从种子点开始,按像素连通定义,递归检测和扩展区域内部像素,并将填充颜色赋给这些像素,直到所有内部点均被着色。

(3)C++代码实现

泛滥填充算法实际上思路很简单,我目前实现是类似windows画图程序的油漆桶功能,即鼠标点击一个点,则按照4连通定义,递归检测,对其连通区域中与颜色相同的像素点赋予用户选择颜色。

但是泛滥填充算法的效率和对于栈的要求比较高,因此我对其进行了一些优化

(1)定义bool processed[]数组,大小为整个区域,表示是否处理过,这样对于处理过的点可以不在判断

(2) 改递归为循环,用一个栈stack存储待处理的点,处理后将未处理过的且四连通的的颜色与底色相同的点入栈,每次对出栈的点处理,一直填充直到栈为空

(3) 将栈stack定义在堆区,减少对系统栈的使用负担

2.8 直线裁剪算法

梁友栋-Barsky参数裁剪算法

(1)基本原理

对于直线段,可以用参数方程形式表示

若有位于由所构成的裁剪窗口内,则有下式成立

这四个不等式可以表达为

其中,被定义为

则有以下结论:

平行于窗口某边界的直线,其值对应于相应的边界(对应于左、右、下、上边界)。

  1. 如果 ,则线段完全在边界外,应舍弃该线段。
  2. 如果 ,则线段平行于窗口某边界并在窗口内。
  3. 如果 ,则线段从裁剪边界延长线的外部延伸到内部;
  4. 如果 ,则线段从裁剪边界延长线的内部延伸到外部

  1. 对于左边界,线段从左边界的外部到内部;
  2. 对于右边界,线段从右边界的内部到外部

  1. 对于下边界,线段从下边界的内部到外部;
  2. 对于上边界,线段从上边界的外部到内部

时,可以计算出参数u的值,它对应于无限延伸的直线与延伸的窗口边界k的交点

对于每条直线,可以计算出参数,该值定义了位于窗口内的线段部分:

  1. 的值由线段从外到内遇到的矩形边界所决定,对这些边界计算取0和各个值之中的最大值。
  2. 的值由线段从内到外遇到的矩形边界所决定,对这些边界计算取1和各个值之中的最小值。
  3. 如果,则线段完全落在裁剪窗口之外,应当被舍弃;否则,被裁剪线段的端点可以由计算出来。
(2)优点——与Cohen-Sutherland算法的比较

与Cohen-Sutherland算法相比,梁友栋-Barsky算法减少了交点计算次数:

(1)梁友栋-Barsky

(2)Cohen-Sutherland算法

(3)算法过程
  1. 参数初始化:线段交点初始参数分别为:

  2. 定义判断函数

    • 来判断:是舍弃线段?还是改变交点参数r

      • ,参数用于更新
      • ,参数用于更新
    • 更新后的判断

      • 若更新后,使,则舍弃该线段
      • 否则,更新值仅仅是求出交点、缩短线段
  3. 求解交点参数

    • 测试四个值后,若该线段被保留,则裁剪线段的端点由值决定
    • 时,舍弃该线段
  4. 反复执行上述过程,计算各裁剪边界的值进行判断。

(4)算法的C++实现

3.系统介绍

3.1 实验环境

操作系统(运行平台)Windows 10
开发语言C++
开发环境Qt Creator
编译环境MinGW 5.3.0

3.2 系统组织

本系统使用Qt提供图形界面,通过Qt集成的QOpenGLWidget类来提供画布,实验主要分为以下类(PDF版本中表格在下一页,可能有些影响阅读体验,还请见谅)

类名继承于类功能
MainWindowQMainWindow提供整个系统的框架,并提供基础功能,如选择绘图类型(目前是直线,圆,椭圆),撤销,清屏,新建图像,保存图像等选项,是交互的窗口。
Canvas_GLQOpenGLWidget每个Canvas_GL类都是一个绘图的画布,用户在上面绘图
Canvas_3DGLCanvas_GL每个Canvas_3DGL类提供3D图形的显示和控制功能
ColorPanelQWidget尚未完全实现,用于提供更为便捷的功能选择
FigureController 图形控制的接口,用于定义绘图行为(目前只有绘制,后期预计在此接口上实现更多功能)
LineControllerFigureController控制直线的输入和编辑,实现了DDA直线算法
CycleControllerFigureController控制圆的输入和编辑,实现了中点圆和Bresenham画圆法
EllipseControllerFigureController控制椭圆的输入和编辑,实现了中点点椭圆绘制算法
PolygonControllerFigureController控制了多边形输入和编辑
CurveControllerFigureController控制了曲线的输入和编辑
Figure 图形类的基类,用于记录画过的图形,便于后期操作
LineFigure直线,记录了直线的起点和终点
CycleFigure圆,记录了圆心和半径(实际上是圆周的任意一点)
EllipseFigure椭圆,记录了代表长短轴的矩形(其实是中心和矩形顶点)
PolygonFigure多边形,记录了多边形的各个顶点坐标
CurveFigure曲线,记录了曲线的各个顶点坐标
Point 点,集成了QPoint,对于关于点的一些常用操作进行抽象集成
PointD 和Point类相似,区别在于其坐标为浮点,用于精度的控制

3.2.1 系统结构和类关系图

 

为了实现对图形的编辑,我定义了FigureController类和Figure类,并由这两个类继承衍生出具体图形和其控制器。Figure用于图元的存储,FigureController用于图元的编辑等一系列操作。

这里给出FigureController的定义,用了许多虚函数,这样利于在Canvas中统一操作,优化代码结构

3.2.2程序基本流程

  1. 系统主题框架类:MainWindow,内集成一个画布类Canvas_GL的数组

  2. 每次创建新画布,就显示新创建的画布

    • 画布可以自由切换
    • 选择功能时,对所有的画布都生效
    • 每个画布中都集成了各种图形的Controller
    • 撤销、清空、保存功能都对当前活动的画布(活动窗口)处理,不影响其他窗口
  3. 画布接受事件输入

    • 对于工具栏的输入,由最外层的MainWindow向当前活跃状态的Canvas_GL传递相应消息。

    • 通过接受鼠标事件,对基本图形输入,编辑

      • 共性通过对应图形的Controller的对应函数来处理,这里用到了动态绑定来精简代码

        • mousePressEvent
        • mouseMoveEvent
        • mouseReleaseEvent
      • 对图形的特殊性质特别处理

    • 对于画笔和笔刷,将每次move的点通过直线连起来

    • 填充功能直接对鼠标点击区域填充

    • 裁剪目前只对直线有效,鼠标输入裁剪框,点击裁剪按钮即可裁剪

  4. 3D画布

4.性能测试

为了更好地展现测试效果,我采用GIF图的形式。但是PDF不能显示GIF,因此还麻烦助教能够打开我提供的markdown版本或者html版本查看更为详细的报告。如有不便,十分抱歉。

对于性能测试,我主要对基本图形和填充功能进行测试。

4.1 直线测试

4.2 曲线测试

4.3 圆测试

4.4 椭圆测试

4.5 多边形测试

4.6 填充测试

5.总结

本绘图系统名为YoungPaint,基于C++和Qt 5.11.2,于Qt Creator上开发,编译环境为MinGW 5.3.0

在9-10月关于图形学的学习中,基于我在课上所学的理论知识,以及课外对于Qt的交互、界面设计的学习,在截止10月底的系统中,我实现了二维图形中直线,圆以及椭圆的输入,并且实现创建多个窗口,画笔颜色的选择,绘画的撤销以及图像的保存功能。

在11月的学习中,我增加了多边形的输入,增加了直线、圆、椭圆的编辑、平移、旋转、放缩功能,实现了填充和直线的裁剪。完善了图片打开的接口,并且优化了系统结构和UI设计,并增加了一些说明。

这次实验是我第一次写具有图形交互的的实验,感觉十分有趣。把图形学课上的理论同实践相结合并且不断探索,不断阅读各种文档资料学习新知识的感觉也不错。尤其是双缓冲绘图的实现,起初我为了实现类似画图程序的动态效果而自己实现了一个,后来听同学说这就是双缓冲技术,独立探索出了这样的技巧让我感觉我的确是有在学习东西的,这也让我对于该实验有着更大的兴趣。尽管由于其他原因,10月份的程序不能说尽善尽美,但是基于我对于程序的理解,一遍上着《高级程序设计》课学习C++各种高级性质,我尽可能把我的知识和设计体现在代码上。11月份中,基于《高级程序设计》课上的知识,对系统的结构进行了优化,定义了一些继承和抽象关系,让程序更加面向对象,也相对更好维护一些。同时,Figure类的定义,对后期保存所有图形并对其进行处理提供了可能。

12月中,主要增加了曲线的绘制和3D图形功能,同时针对之前系统的各种不稳定状态做了微型调整,使得系统的鲁棒性和可用性更高。整个实验过程中,各种技术和知识的学习贯穿其中。绘制算法的学习和编程语言和框架的学习,我尽可能将我所学用在了我的程序中,这个大作业也算是我的知识的结晶了。

6.致谢

感谢孙正兴老师和张岩老师的辛勤教学,感谢各位助教在百忙之中解答我的各种疑惑,感谢我的舍友和系友们在关于大作业的各种问题给我的指导和帮助。

7.参考文献

[1] 孙正兴,周良,郑洪源,谢强.计算机图形学教程.北京:机械工业出版社,2006.

[2] 陈家骏,郑滔.程序设计教程用 C++语言编程(第 3 版).北京:机械工业出版社,2015.

(附其他参考资料)

[3] Qt学习社区上的《Qt基础教程之Qt学习之路》

[4] Qt官方文档

[5] Qt5.9.4利用QOpenGLWidget类进行opengl绘图 https://blog.csdn.net/cpwwhsu/article/details/79773235

[6] Qt学习之路-简易画板3(双缓冲绘图) https://blog.csdn.net/u012891055/article/details/41727391?utm_source=blogxgwz0

[7]c++实现图像旋转任意角度 https://blog.csdn.net/wonengguwozai/article/details/52049092

[8]openGL-读取off、stl、obj文件https://blog.csdn.net/OOFFrankDura/article/details/80203664

[9]DeCasteljau's 算法http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/de-casteljau.html