1、绘制曲线
首先认为所有的线都是由点组成的,于是尝试采用直接绘制两点连接直线的方式来绘制曲线,代码如下
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing);
painter.setPen(QPen(Qt::red,2,Qt::SolidLine));
for(int i = 0; i < _lines.size(); ++i)
{
const QVector<QPointF> &line = _lines.at(i); //鼠标移动采集的点,通过引用取出, 确保操作的是同一块内存
for(int j = 1; j < line.size()-1; ++j)
{
QLineF lineF = QLineF(line.at(j), line.at(j + 1));
painter.drawLine(lineF);
}
}
但是仔细观察会发现每个点之间的连接处并不平滑,达不到平滑曲线的效果,于是采用另外一种实现方式,通过贝塞尔曲线来调整曲线
2、绘制贝塞尔曲线
在绘制贝塞尔曲线前需要学习了解一个关键类——QPainterPath
官方解释:QPainterPath类为绘制操作提供了一个容器,允许构造和重用图形形状。
画家路径是由许多图形构建块(如矩形、椭圆、直线和曲线)组成的对象。构建块可以在封闭的子路径中连接,例如作为一个矩形或椭圆。闭合路径的起点和终点是重合的。或者它们可以独立地作为未封闭的子路径存在,比如直线和曲线。
QPainterPath对象可用于填充、勾勒和剪裁。为给定的画家生成可填充的轮廓。
通过QPainterPath可以实现任意图形的绘制
painter.setPen(QPen(Qt::red,2,Qt::SolidLine));
for(int i = 0; i < _lines.size(); ++i)
{
QLineF prevLine;
const QVector<QPointF> &line = _lines.at(i); //鼠标移动采集的点,通过引用取出, 确保操作的是同一块内存
for(int j = 1; j < line.size()-1; ++j)
{
QPainterPath strokesPath;
prevLine = QLineF(line.at(j - 1), line.at(j)); //获取上一个线段
QLineF curLine(line.at(j), line.at(j + 1)); //获取当前线段
strokesPath.moveTo(prevLine.pointAt(0.5)); //将当前线段路径的起点移至上一线段的中点
strokesPath.quadTo(line.at(j), curLine.pointAt(0.5)); //将当前点设置为曲线控制点,当前线段的中点设置为曲线的结束点
painter.drawPath(strokesPath); //绘制曲线
}
}
绘制贝塞尔曲线采用的也是点对点拼接成曲线,不同的是拼接的点选取的是上一条绘制线段的中点,每次绘制是通过moveTo函数将绘制的起点移动到上一条线段的中点(pointAt(0.5);取值为0-1,0为线段起点,1位线段终点;);通过quadTo函数,在当前位置和给定端点之间添加一条二次贝塞尔曲线,控制点由c指定,第一个参数为控制点。添加曲线后,当前点被更新为曲线的结束点,第二个参数为结束点。
此处需要注意的是如果采用线段末端进行拼接的话,因为每次绘制曲线时都是只绘制了当前获取的两个点之间的线段,而上一条线段的终点一下一条线段的起点之间只是单纯的拼接,并没使用贝塞尔曲线的绘制。
(注:个人见解,如有异议,欢迎斧正)。