这篇文章主要讲解了“Qt 如何实现钢笔画线效果的编写方法讲解及原理介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Qt 如何实现钢笔画线效果的编写方法讲解及原理介绍”吧!
成都创新互联-专业网站定制、快速模板网站建设、高性价比五通桥网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式五通桥网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖五通桥地区。费用合理售后完善,十余年实体公司更值得信赖。
前言
上一篇文章:Qt 实现画线笔锋效果详细原理,根据这篇介绍的实现笔锋效果的原理,我们很容易实现另外一种笔效:钢笔。
所谓的钢笔笔效,就是真实还原钢笔书写出来的线条效果,其特征就是:根据笔的绘制速度而线条的宽度会逐渐变化,写得越快,线条越细,并且在收笔时带有笔锋效果。
那么,在上一篇文章的基础上,稍微修改一下,就可以实现这个效果,看下效果图:
实现原理
从上一篇文章我们知道,绘制的曲线是通过每两个点形成一条贝塞尔曲线,所以在不松手的情况下连续画线,整条线段是包含很多条path组合而成的。而要实现钢笔效果的关键,是要让线条的粗细跟随绘制的速度来变化。
之前看过很多Android上实现钢笔或者毛笔的算法,都是需要计算去画线速度,根据速度来动态改变线条的粗细。但是我这里没有计算速度,而是直接通过每一段path的长度来计算一个合理的宽度值出来。
众所周知,长度(也就是距离)= 速度*时间,在单位时间内,速度和距离是成正比的,所以我们通过两点间的距离来做判断也是一样的,没多大区别,并且还不用单独去计算速度了,简单省事儿。
那么,我们要实现的效果是,画线速度越快线条会越细,而画线速度越快,所采集到的两点间的距离就会越大,而我们是通过两点间距离来做参考依据,也就是说,两点间距和线条粗细是成反比的,两点间距越长,对应的这条path就越细,距离越短,path就越粗,二者是线性关系。当然,这里path的宽度会有一个最大值和最小值,需要在实际的场景中进行调试。
OK,根据以上分析,我们可以得到以下的示意图:
每条path都是通过两个坐标点实时生成的贝塞尔曲线。
在绘制这条曲线的时候,先获取到曲线的长度,然后线性计算出一个宽度值。
如何获取path的长度呢?
这个好办,QPainterPath有自带的接口length()
:
计算曲线的宽度,我写了一个简单的计算方法:
qreal WbCanvasItem::calPathWidth(QPainterPath path) { qreal length = path.length(); qreal width = PENWIDTH; qreal t = length/10. - 1; width = PENWIDTH - t; if(width < 3){ //最小宽度 width = 3; } return width; }
PENWIDTH是一个宏定义,曲线最大宽度;
根据以上步骤,我们来看一下效果:
为了方便看效果,每条path用了不同的颜色来区分。我们可以很明显的看到,path的宽度是不一样的,并且每条path的连接处的宽度变化非常明显,那么要怎么使其连接处变得平滑呢?
这时候就要用到上一篇介绍的方法进行补点了。这里的补点比上一篇文章中说的稍微麻烦点,需要将中间那根线条的两头都要补充点,其原理是一样的。
看一下示意图:
以上红色圈圈部分,就是补充的点。
从以上图可以看到,path3是倒数第二条path,path4是最后一条path。
需要注意的是,图中补充的两个地方,并不是同一时间补充的,当有新的path到来,只需要判断最新的path和上一个path的宽度,从而决定是补充到上一个path还是当前最新的path上。
这段话有点拗口,拆解一下:
假如这里path3是最后的一条path,而path2是倒数第二条,判断出来path3宽度笔path2小,那么就在path3的路径上补充点;
再看一种情况:
同样,这里path3是最后的一条path,而path2是倒数第二条,判断出来path3宽度笔path2大,那么就在path2的路径上补充点;
这样描述就很容易理解了。
OK,我们看一下补充点的代码:
void WbCanvasItem::drawPatchPoint2(QPainter *painter, QPainterPath lastPath, QPainterPath curPath, qreal lastWidth, qreal curWidth) { qreal tPatchLength = 100.; if(lastWidth < curWidth){ tPatchLength = calPatchLength(curPath.length()); qreal temp = (curWidth-lastWidth)/tPatchLength; int k = 0; for (qreal i = 1;i > (100-tPatchLength)/100.; i-=0.01) { k++; painter->setPen(QPen(Qt::black,curWidth-temp*k, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter->drawPoint(lastPath.pointAtPercent(i)); } } else if(lastWidth > curWidth){ tPatchLength = calPatchLength(curPath.length()); qreal temp = (lastWidth-curWidth)/tPatchLength; int k = 0; for (qreal i = 0;i < tPatchLength/100.; i+=0.01) { k++; painter->setPen(QPen(Qt::black,lastWidth-temp*k, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter->drawPoint(curPath.pointAtPercent(i)); } } }
看一下补充点后的效果:
这里的黑色部分就是动态补充上去的点。
好了, 整理原理分析完成,其实和前面一篇文章原理差不多,只是多了一步判断距离然后计算线宽的过程。
感谢各位的阅读,以上就是“Qt 如何实现钢笔画线效果的编写方法讲解及原理介绍”的内容了,经过本文的学习后,相信大家对Qt 如何实现钢笔画线效果的编写方法讲解及原理介绍这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!