2025年qpainter画曲线图(qpainter画平滑曲线)

qpainter画曲线图(qpainter画平滑曲线)得到曲线上的点 画出曲线 这是一个很常见的需求 画曲线嘛 当然难不住我们 用 QPainter drawLine 把曲线上的点连起来不就好了 So easy 轻轻松松搞定 开开心心的交任务去了 正在聚精会神炒股的老板一瞅 气不打一处来 你这画的是什么鬼 这个线直来直去的 太不专业了 抬头指着屏幕上的炒股软件 瞅着迷离的眼神 看看人家的这个曲线 就像少女的皮肤般那么的柔顺 平滑

大家好,我是讯享网,很高兴认识大家。



得到曲线上的点,画出曲线,这是一个很常见的需求。画曲线嘛,当然难不住我们,用 QPainter::drawLine() 把曲线上的点连起来不就好了?So easy,轻轻松松搞定,开开心心的交任务去了。


讯享网

正在聚精会神炒股的老板一瞅,气不打一处来:“你这画的是什么鬼,这个线直来直去的,太不专业了”,抬头指着屏幕上的炒股软件,瞅着迷离的眼神:“看看人家的这个曲线,就像少女的皮肤般那么的柔顺、平滑”,口气马上一百八十度大转弯:“在看看你的,像八十岁老头的那样全是褶皱!” 擦完脸上的口水,赶快想办法去吧。

创建平滑曲线,有很多种方式,可以使用现成的库,例如 QWT,QCustomPlot 等,也可以研究平滑曲线的理论,实现平滑曲线的插值函数。这里我们提供二个实现,利用 QPainterPath,根据曲线上的点创建平滑曲线,他们各有利弊,使用分三步:

 
讯享网 <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div></pre> </td><td> <pre> <div> <span>// [1] 把曲线上的点放到 QList 里</span> </div> <div> QList&lt;QPointF&gt; knots; </div> <div> knots &lt;&lt; QPointF(x1, y1); </div> <div> ... </div> <div> knots &lt;&lt; QPointF(xn, yn); </div> <div></div> <div> <span>// [2] 创建平滑曲线</span> </div> <div> QPainterPath smoothCurve1 &#61; SmoothCurveGenerator1::generateSmoothCurve(knots); </div> <div> QPainterPath smoothCurve2 &#61; SmoothCurveGenerator2::generateSmoothCurve(knots); </div> <div></div> <div> <span>// [3] 绘制曲线</span> </div> <div> painter.drawPath(smoothCurve1); </div> <div> painter.drawPath(smoothCurve2); </div></pre> </td></tr></tbody></div> 
最后画出来的曲线效果如下,这次应该不会被喷了吧:
Qt 中可以使用  函数实现绘制平滑曲线,绘制平滑曲线的关键是控制点的计算,sp 为线段的起始点,ep 为线段的终点,c1,c2 为贝塞尔曲线的控制点,其坐标计算如下 类 SmoothCurveGenerator1 使用上面的原理生成平滑曲线
 
讯享网 <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div></pre> </td><td> <pre> <div> <span>#<span>ifndef</span> SMOOTHCURVEGENERATOR1_H</span> </div> <div> <span>#<span>define</span> SMOOTHCURVEGENERATOR1_H</span> </div> <div></div> <div> <span>#<span>include</span> <span>&lt;QList&gt;</span></span> </div> <div> <span>#<span>include</span> <span>&lt;QPointF&gt;</span></span> </div> <div> <span>#<span>include</span> <span>&lt;QPainterPath&gt;</span></span> </div> <div></div> <div> <span><span>class</span> <span>SmoothCurveGenerator1</span> {</span> </div> <div> <span>public</span>: </div> <div> <span>/</span> </div> <div> * 传入曲线上的点的 list&#xff0c;创建平滑曲线 </div> <div> * </div> <div> * &#64;param points - 曲线上的点 </div> <div> * &#64;return - 返回使用给定的点创建的 QPainterPath 表示的平滑曲线 </div> <div> */ </div> <div> <span><span>static</span> QPainterPath <span>generateSmoothCurve</span><span>(<span>const</span> QList&lt;QPointF&gt; &amp;points)</span></span>; </div> <div> }; </div> <div></div> <div> <span>#<span>endif</span> <span>// SMOOTHCURVEGENERATOR1_H</span></span> </div></pre> </td></tr></tbody></div> 
 
      
        
      
1
讯享网 <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> <div> 20 </div> <div> 21 </div> <div> 22 </div></pre> </td><td> <pre> <div> <span>#<span>include</span> <span>&#34;SmoothCurveGenerator1.h&#34;</span></span> </div> <div></div> <div> QPainterPath SmoothCurveGenerator1::generateSmoothCurve( <span>const</span> QList&lt;QPointF&gt; &amp;points) { </div> <div> <span>if</span> (points.size() &#61;&#61; <span>0</span>) { </div> <div> <span>return</span> QPainterPath(); </div> <div> } </div> <div></div> <div> <span>QPainterPath <span>path</span><span>(points[<span>0</span>])</span></span>; </div> <div></div> <div> <span>for</span> ( <span>int</span> i &#61; <span>0</span>; i &lt; points.size() - <span>1</span>; &#43;&#43;i) { </div> <div> <span>// 控制点的 x 坐标为 sp 与 ep 的 x 坐标和的一半</span> </div> <div> <span>// 第一个控制点 c1 的 y 坐标为起始点 sp 的 y 坐标</span> </div> <div> <span>// 第二个控制点 c2 的 y 坐标为结束点 ep 的 y 坐标</span> </div> <div> QPointF sp &#61; points[i]; </div> <div> QPointF ep &#61; points[i&#43; <span>1</span>]; </div> <div> QPointF c1 &#61; QPointF((sp.x() &#43; ep.x()) / <span>2</span>, sp.y()); </div> <div> QPointF c2 &#61; QPointF((sp.x() &#43; ep.x()) / <span>2</span>, ep.y()); </div> <div> path.cubicTo(c1, c2, ep); </div> <div> } </div> <div></div> <div> <span>return</span> path; </div> <div> } </div></pre> </td></tr></tbody></div> 
接下来就介绍一下生成平滑曲线的具体使用方法,就是开头被喷的那个曲线图的平滑实现。 在 SmoothCurveWidget.ui 上如图放两个 QCheckBox,命名为 showKnotsCheckBox 和 showSmoothCurveCheckBox,QPushButton 用于点击重新生成曲线,ComboBox 用于选择生成曲线的算法: 下面是 SmoothCurveWidget.h, SmoothCurveWidget.cpp 和 main.cpp
 
讯享网 <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> <div> 20 </div> <div> 21 </div> <div> 22 </div> <div> 23 </div> <div> 24 </div> <div> 25 </div> <div> 26 </div> <div> 27 </div> <div> 28 </div> <div> 29 </div> <div> 30 </div> <div> 31 </div> <div> 32 </div> <div> 33 </div> <div> 34 </div></pre> </td><td> <pre> <div> <span>#<span>ifndef</span> SMOOTHCURVEWIDGET_H</span> </div> <div> <span>#<span>define</span> SMOOTHCURVEWIDGET_H</span> </div> <div></div> <div> <span>#<span>include</span> <span>&lt;QWidget&gt;</span></span> </div> <div> <span>#<span>include</span> <span>&lt;QList&gt;</span></span> </div> <div> <span>#<span>include</span> <span>&lt;QPointF&gt;</span></span> </div> <div> <span>#<span>include</span> <span>&lt;QPainterPath&gt;</span></span> </div> <div></div> <div> <span>namespace</span> Ui { </div> <div> <span><span>class</span> <span>SmoothCurveWidget</span>;</span> </div> <div> } </div> <div></div> <div> <span><span>class</span> <span>SmoothCurveWidget</span> :</span> <span>public</span> QWidget { </div> <div> Q_OBJECT </div> <div></div> <div> <span>public</span>: </div> <div> <span><span>explicit</span> <span>SmoothCurveWidget</span><span>(QWidget *parent &#61; <span>0</span>)</span></span>; </div> <div> ~SmoothCurveWidget(); </div> <div></div> <div> <span>protected</span>: </div> <div> <span><span>void</span> <span>paintEvent</span><span>(QPaintEvent *event)</span> Q_DECL_OVERRIDE</span>; </div> <div></div> <div> <span>private</span> slots: </div> <div> <span><span>void</span> <span>generateCurves</span><span>()</span></span>; <span>// 生成平滑曲线和非平滑曲线</span> </div> <div></div> <div> <span>private</span>: </div> <div> Ui::SmoothCurveWidget *ui; </div> <div> QList&lt;QPointF&gt; knots; <span>// 曲线上的点</span> </div> <div> QPainterPath smoothCurve1; <span>// 平滑曲线</span> </div> <div> QPainterPath smoothCurve2; <span>// 平滑曲线</span> </div> <div> QPainterPath nonSmoothCurve; <span>// 直接连接点的非平滑曲线</span> </div> <div> }; </div> <div></div> <div> <span>#<span>endif</span> <span>// SMOOTHCURVEWIDGET_H</span></span> </div></pre> </td></tr></tbody></div> 
 
          
            
          
1
讯享网 <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> <div> 20 </div> <div> 21 </div> <div> 22 </div> <div> 23 </div> <div> 24 </div> <div> 25 </div> <div> 26 </div> <div> 27 </div> <div> 28 </div> <div> 29 </div> <div> 30 </div> <div> 31 </div> <div> 32 </div> <div> 33 </div> <div> 34 </div> <div> 35 </div> <div> 36 </div> <div> 37 </div> <div> 38 </div> <div> 39 </div> <div> 40 </div> <div> 41 </div> <div> 42 </div> <div> 43 </div> <div> 44 </div> <div> 45 </div> <div> 46 </div> <div> 47 </div> <div> 48 </div> <div> 49 </div> <div> 50 </div> <div> 51 </div> <div> 52 </div> <div> 53 </div> <div> 54 </div> <div> 55 </div> <div> 56 </div> <div> 57 </div> <div> 58 </div> <div> 59 </div> <div> 60 </div> <div> 61 </div> <div> 62 </div> <div> 63 </div> <div> 64 </div> <div> 65 </div> <div> 66 </div> <div> 67 </div> <div> 68 </div> <div> 69 </div> <div> 70 </div> <div> 71 </div> <div> 72 </div> <div> 73 </div> <div> 74 </div> <div> 75 </div> <div> 76 </div> <div> 77 </div> <div> 78 </div> <div> 79 </div> <div> 80 </div></pre> </td><td> <pre> <div> <span>#<span>include</span> <span>&#34;SmoothCurveWidget.h&#34;</span></span> </div> <div> <span>#<span>include</span> <span>&#34;ui_SmoothCurveWidget.h&#34;</span></span> </div> <div> <span>#<span>include</span> <span>&#34;SmoothCurveGenerator1.h&#34;</span></span> </div> <div> <span>#<span>include</span> <span>&#34;SmoothCurveGenerator2.h&#34;</span></span> </div> <div></div> <div> <span>#<span>include</span> <span>&lt;QPainter&gt;</span></span> </div> <div> <span>#<span>include</span> <span>&lt;QtGlobal&gt;</span></span> </div> <div> <span>#<span>include</span> <span>&lt;QDateTime&gt;</span></span> </div> <div></div> <div> SmoothCurveWidget::SmoothCurveWidget(QWidget *parent) : </div> <div> QWidget(parent), ui( <span>new</span> Ui::SmoothCurveWidget) { </div> <div> ui-&gt;setupUi( <span>this</span>); </div> <div></div> <div> connect(ui-&gt;generateCurveButton, SIGNAL(clicked( <span>bool</span>)), <span>this</span>, SLOT(generateCurves())); </div> <div> connect(ui-&gt;showKnotsCheckBox, SIGNAL(clicked( <span>bool</span>)), <span>this</span>, SLOT(update())); </div> <div> connect(ui-&gt;showSmoothCurveCheckBox, SIGNAL(clicked( <span>bool</span>)), <span>this</span>, SLOT(update())); </div> <div> connect(ui-&gt;smoothCurveGeneratorComboBox, SIGNAL(currentIndexChanged( <span>int</span>)), <span>this</span>, SLOT(update())); </div> <div></div> <div> ui-&gt;generateCurveButton-&gt;click(); </div> <div> } </div> <div></div> <div> SmoothCurveWidget::~SmoothCurveWidget() { </div> <div> <span>delete</span> ui; </div> <div> } </div> <div></div> <div> <span>void</span> SmoothCurveWidget::paintEvent(QPaintEvent *) { </div> <div> <span>QPainter <span>painter</span><span>(<span>this</span>)</span></span>; </div> <div> painter.setRenderHint(QPainter::Antialiasing); </div> <div> painter.translate(width() / <span>2</span> , height() / <span>2</span>); </div> <div> painter.scale( <span>1</span>, <span>-1</span>); </div> <div></div> <div> <span>// 画坐标轴</span> </div> <div> painter.setPen(QColor( <span>180</span>, <span>180</span>, <span>180</span>)); </div> <div> painter.drawLine( <span>-500</span>, <span>0</span>, <span>500</span>, <span>0</span>); </div> <div> painter.drawLine( <span>0</span>, <span>500</span>, <span>0</span>, <span>-500</span>); </div> <div></div> <div> <span>// showSmoothCurveCheckBox 被选中时显示平滑曲线&#xff0c;否则显示非平滑曲线</span> </div> <div> painter.setPen(QPen(QColor( <span>80</span>, <span>80</span>, <span>80</span>), <span>2</span>)); </div> <div> <span>if</span> (ui-&gt;showSmoothCurveCheckBox-&gt;isChecked() &amp;&amp; ui-&gt;smoothCurveGeneratorComboBox-&gt;currentIndex() &#61;&#61; <span>0</span>) { </div> <div> painter.drawPath(smoothCurve1); </div> <div> } <span>else</span> <span>if</span> (ui-&gt;showSmoothCurveCheckBox-&gt;isChecked() &amp;&amp; ui-&gt;smoothCurveGeneratorComboBox-&gt;currentIndex() &#61;&#61; <span>1</span>) { </div> <div> painter.drawPath(smoothCurve2); </div> <div> } <span>else</span> { </div> <div> painter.drawPath(nonSmoothCurve); </div> <div> } </div> <div></div> <div> <span>// 如果曲线上的点可见&#xff0c;则显示出来</span> </div> <div> <span>if</span> (ui-&gt;showKnotsCheckBox-&gt;isChecked()) { </div> <div> painter.setPen(Qt::black); </div> <div> painter.setBrush(Qt::gray); </div> <div> foreach(QPointF p, knots) { </div> <div> painter.drawEllipse(p, <span>3</span>, <span>3</span>); </div> <div> } </div> <div> } </div> <div> } </div> <div></div> <div> <span>void</span> SmoothCurveWidget::generateCurves() { </div> <div> qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); </div> <div></div> <div> <span>// 随机生成曲线上的点: 横坐标为 [-200, 200]&#xff0c;纵坐标为 [-100, 100]</span> </div> <div> <span>int</span> x &#61; <span>-200</span>; </div> <div> knots.clear(); </div> <div> <span>while</span> (x &lt; <span>200</span>) { </div> <div> knots &lt;&lt; QPointF(x, qrand() % <span>200</span> - <span>100</span>); </div> <div> x &#43;&#61; qMin(qrand() % <span>30</span> &#43; <span>5</span>, <span>200</span>); </div> <div> } </div> <div></div> <div> <span>// 根据曲线上的点创建平滑曲线</span> </div> <div> smoothCurve1 &#61; SmoothCurveGenerator1::generateSmoothCurve(knots); </div> <div> smoothCurve2 &#61; SmoothCurveGenerator2::generateSmoothCurve(knots); </div> <div></div> <div> <span>// 连接点创建非平滑曲线曲线</span> </div> <div> nonSmoothCurve &#61; QPainterPath(); </div> <div> nonSmoothCurve.moveTo(knots[ <span>0</span>]); </div> <div> <span>for</span> ( <span>int</span> i &#61; <span>1</span>; i &lt; knots.size(); &#43;&#43;i) { </div> <div> nonSmoothCurve.lineTo(knots[i]); </div> <div> } </div> <div></div> <div> update(); </div> <div> } </div></pre> </td></tr></tbody></div> 
 
            
              
            
1
讯享网 <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div></pre> </td><td> <pre> <div> <span>#<span>include</span> <span>&#34;SmoothCurveWidget.h&#34;</span></span> </div> <div> <span>#<span>include</span> <span>&lt;QApplication&gt;</span></span> </div> <div></div> <div> <span><span>int</span> <span>main</span><span>(<span>int</span> argc, <span>char</span> *argv[])</span> </span>{ </div> <div> <span>QApplication <span>a</span><span>(argc, argv)</span></span>; </div> <div></div> <div> SmoothCurveWidget w; </div> <div> w.show(); </div> <div></div> <div> <span>return</span> a.exec(); </div> <div> } </div></pre> </td></tr></tbody></div> 
为了让程序更具有普谝性,曲线上的点采用随机生成,所以每次生成的曲线是不一样的,选中 “Smooth Curve” 时显示为平滑曲线,没有选中则显示为非平滑的曲线。选中 “Show knots” 显示曲线上的点,反之则不显示。 如果仔细观察 SmoothCurveGenerator1 生成的平滑曲线,会发现平滑曲线段之间会有很多小段的抖动,下面提供另一个也是使用 QPainterPath 实现平滑曲线的方法,可以解决平滑曲线段之间的抖动问题,但是曲线段在比较陡时,曲线上的值可能会超出曲线原来值的范围,但是总体上看效果更好,改编自 http://www.codeproject.com/Articles/31859/Draw-a-Smooth-Curve-through-a-Set-of-D-Points-wit&#xff0c;核心是使用曲线上的点计算出贝塞尔曲线的两个控制点&#xff0c;然后使用贝塞尔曲线生成平滑曲线&#xff0c;很惭愧的是生成控制点的算法细节我没看懂&#xff0c;只不过是作了一次搬运工&#xff0c;把程序移植到了 Qt 上,有兴趣的话,请自行参考吧,不过即使没有理解控制点的生成算法也不影响使用。
 
讯享网 <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> <div> 20 </div> <div> 21 </div> <div> 22 </div> <div> 23 </div> <div> 24 </div> <div> 25 </div> <div> 26 </div> <div> 27 </div> <div> 28 </div> <div> 29 </div> <div> 30 </div> <div> 31 </div> <div> 32 </div> <div> 33 </div> <div> 34 </div> <div> 35 </div> <div> 36 </div> <div> 37 </div> <div> 38 </div></pre> </td><td> <pre> <div> <span>#<span>ifndef</span> SMOOTHCURVEGENERATOR2_H</span> </div> <div> <span>#<span>define</span> SMOOTHCURVEGENERATOR2_H</span> </div> <div></div> <div> <span>#<span>include</span> <span>&lt;QList&gt;</span></span> </div> <div> <span>#<span>include</span> <span>&lt;QPointF&gt;</span></span> </div> <div> <span>#<span>include</span> <span>&lt;QPainterPath&gt;</span></span> </div> <div></div> <div> <span><span>class</span> <span>SmoothCurveGenerator2</span> {</span> </div> <div> <span>public</span>: </div> <div> <span>/</span> </div> <div> * 传入曲线上的点的 list&#xff0c;创建平滑曲线 </div> <div> * &#64;param points - 曲线上的点 </div> <div> * &#64;return - 返回使用给定的点创建的 QPainterPath 表示的平滑曲线 </div> <div> */ </div> <div> <span><span>static</span> QPainterPath <span>generateSmoothCurve</span><span>(<span>const</span> QList&lt;QPointF&gt; &amp;points)</span></span>; </div> <div></div> <div> <span>private</span>: </div> <div> <span>/</span> </div> <div> * Solves a tridiagonal system for one of coordinates (x or y) </div> <div> * of first Bezier control points. </div> <div> * &#64;param result - Solution vector. </div> <div> * &#64;param rhs - Right hand side vector. </div> <div> * &#64;param n - Size of rhs. </div> <div> */ </div> <div> <span><span>static</span> <span>void</span> <span>calculateFirstControlPoints</span><span>(<span>double</span> * &amp;result, <span>const</span> <span>double</span> *rhs, <span>int</span> n)</span></span>; </div> <div></div> <div> <span>/</span> </div> <div> * Calculate control points of the smooth curve using the given knots. </div> <div> * &#64;param knots - Points of the given curve. </div> <div> * &#64;param firstControlPoints - Store the generated first control points. </div> <div> * &#64;param secondControlPoints - Store the generated second control points. </div> <div> */ </div> <div> <span><span>static</span> <span>void</span> <span>calculateControlPoints</span><span>(<span>const</span> QList&lt;QPointF&gt; &amp;knots,</span></span> </div> <div> QList&lt;QPointF&gt; *firstControlPoints, </div> <div> QList&lt;QPointF&gt; *secondControlPoints); </div> <div> }; </div> <div></div> <div> <span>#<span>endif</span> <span>// SMOOTHCURVEGENERATOR2_H</span></span> </div></pre> </td></tr></tbody></div> 
 
                
                  
                
1
讯享网 <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> <div> 20 </div> <div> 21 </div> <div> 22 </div> <div> 23 </div> <div> 24 </div> <div> 25 </div> <div> 26 </div> <div> 27 </div> <div> 28 </div> <div> 29 </div> <div> 30 </div> <div> 31 </div> <div> 32 </div> <div> 33 </div> <div> 34 </div> <div> 35 </div> <div> 36 </div> <div> 37 </div> <div> 38 </div> <div> 39 </div> <div> 40 </div> <div> 41 </div> <div> 42 </div> <div> 43 </div> <div> 44 </div> <div> 45 </div> <div> 46 </div> <div> 47 </div> <div> 48 </div> <div> 49 </div> <div> 50 </div> <div> 51 </div> <div> 52 </div> <div> 53 </div> <div> 54 </div> <div> 55 </div> <div> 56 </div> <div> 57 </div> <div> 58 </div> <div> 59 </div> <div> 60 </div> <div> 61 </div> <div> 62 </div> <div> 63 </div> <div> 64 </div> <div> 65 </div> <div> 66 </div> <div> 67 </div> <div> 68 </div> <div> 69 </div> <div> 70 </div> <div> 71 </div> <div> 72 </div> <div> 73 </div> <div> 74 </div> <div> 75 </div> <div> 76 </div> <div> 77 </div> <div> 78 </div> <div> 79 </div> <div> 80 </div> <div> 81 </div> <div> 82 </div> <div> 83 </div> <div> 84 </div> <div> 85 </div> <div> 86 </div> <div> 87 </div> <div> 88 </div> <div> 89 </div> <div> 90 </div> <div> 91 </div> <div> 92 </div> <div> 93 </div> <div> 94 </div> <div> 95 </div> <div> 96 </div> <div> 97 </div> <div> 98 </div> <div> 99 </div> <div> 100 </div> <div> 101 </div> <div> 102 </div> <div> 103 </div> <div> 104 </div> <div> 105 </div> <div> 106 </div></pre> </td><td> <pre> <div> <span>#<span>include</span> <span>&#34;SmoothCurveGenerator2.h&#34;</span></span> </div> <div></div> <div> QPainterPath SmoothCurveGenerator2::generateSmoothCurve( <span>const</span> QList&lt;QPointF&gt; &amp;points) { </div> <div> QPainterPath path; </div> <div> <span>int</span> len &#61; points.size(); </div> <div></div> <div> <span>if</span> (len &lt; <span>2</span>) { </div> <div> <span>return</span> path; </div> <div> } </div> <div></div> <div> QList&lt;QPointF&gt; firstControlPoints; </div> <div> QList&lt;QPointF&gt; secondControlPoints; </div> <div> calculateControlPoints(points, &amp;firstControlPoints, &amp;secondControlPoints); </div> <div></div> <div> path.moveTo(points[ <span>0</span>].x(), points[ <span>0</span>].y()); </div> <div></div> <div> <span>// Using bezier curve to generate a smooth curve.</span> </div> <div> <span>for</span> ( <span>int</span> i &#61; <span>0</span>; i &lt; len - <span>1</span>; &#43;&#43;i) { </div> <div> path.cubicTo(firstControlPoints[i], secondControlPoints[i], points[i&#43; <span>1</span>]); </div> <div> } </div> <div></div> <div> <span>return</span> path; </div> <div> } </div> <div></div> <div> <span>void</span> SmoothCurveGenerator2::calculateFirstControlPoints( <span>double</span> *&amp;result, <span>const</span> <span>double</span> *rhs, <span>int</span> n) { </div> <div> result &#61; <span>new</span> <span>double</span>[n]; </div> <div> <span>double</span> *tmp &#61; <span>new</span> <span>double</span>[n]; </div> <div> <span>double</span> b &#61; <span>2.0</span>; </div> <div> result[ <span>0</span>] &#61; rhs[ <span>0</span>] / b; </div> <div></div> <div> <span>// Decomposition and forward substitution.</span> </div> <div> <span>for</span> ( <span>int</span> i &#61; <span>1</span>; i &lt; n; i&#43;&#43;) { </div> <div> tmp[i] &#61; <span>1</span> / b; </div> <div> b &#61; (i &lt; n - <span>1</span> ? <span>4.0</span> : <span>3.5</span>) - tmp[i]; </div> <div> result[i] &#61; (rhs[i] - result[i - <span>1</span>]) / b; </div> <div> } </div> <div></div> <div> <span>for</span> ( <span>int</span> i &#61; <span>1</span>; i &lt; n; i&#43;&#43;) { </div> <div> result[n - i - <span>1</span>] -&#61; tmp[n - i] * result[n - i]; <span>// Backsubstitution.</span> </div> <div> } </div> <div></div> <div> <span>delete</span>[] tmp; </div> <div> } </div> <div></div> <div> <span>void</span> SmoothCurveGenerator2::calculateControlPoints( <span>const</span> QList&lt;QPointF&gt; &amp;knots, </div> <div> QList&lt;QPointF&gt; *firstControlPoints, </div> <div> QList&lt;QPointF&gt; *secondControlPoints) { </div> <div> <span>int</span> n &#61; knots.size() - <span>1</span>; </div> <div></div> <div> <span>for</span> ( <span>int</span> i &#61; <span>0</span>; i &lt; n; &#43;&#43;i) { </div> <div> firstControlPoints-&gt;append(QPointF()); </div> <div> secondControlPoints-&gt;append(QPointF()); </div> <div> } </div> <div></div> <div> <span>if</span> (n &#61;&#61; <span>1</span>) { </div> <div> <span>// Special case: Bezier curve should be a straight line.</span> </div> <div> <span>// P1 &#61; (2P0 &#43; P3) / 3</span> </div> <div> (*firstControlPoints)[ <span>0</span>].rx() &#61; ( <span>2</span> * knots[ <span>0</span>].x() &#43; knots[ <span>1</span>].x()) / <span>3</span>; </div> <div> (*firstControlPoints)[ <span>0</span>].ry() &#61; ( <span>2</span> * knots[ <span>0</span>].y() &#43; knots[ <span>1</span>].y()) / <span>3</span>; </div> <div></div> <div> <span>// P2 &#61; 2P1 – P0</span> </div> <div> (*secondControlPoints)[ <span>0</span>].rx() &#61; <span>2</span> * (*firstControlPoints)[ <span>0</span>].x() - knots[ <span>0</span>].x(); </div> <div> (*secondControlPoints)[ <span>0</span>].ry() &#61; <span>2</span> * (*firstControlPoints)[ <span>0</span>].y() - knots[ <span>0</span>].y(); </div> <div></div> <div> <span>return</span>; </div> <div> } </div> <div></div> <div> <span>// Calculate first Bezier control points</span> </div> <div> <span>double</span> *xs &#61; <span>0</span>; </div> <div> <span>double</span> *ys &#61; <span>0</span>; </div> <div> <span>double</span> *rhsx &#61; <span>new</span> <span>double</span>[n]; <span>// Right hand side vector</span> </div> <div> <span>double</span> *rhsy &#61; <span>new</span> <span>double</span>[n]; <span>// Right hand side vector</span> </div> <div></div> <div> <span>// Set right hand side values</span> </div> <div> <span>for</span> ( <span>int</span> i &#61; <span>1</span>; i &lt; n - <span>1</span>; &#43;&#43;i) { </div> <div> rhsx[i] &#61; <span>4</span> * knots[i].x() &#43; <span>2</span> * knots[i &#43; <span>1</span>].x(); </div> <div> rhsy[i] &#61; <span>4</span> * knots[i].y() &#43; <span>2</span> * knots[i &#43; <span>1</span>].y(); </div> <div> } </div> <div> rhsx[ <span>0</span>] &#61; knots[ <span>0</span>].x() &#43; <span>2</span> * knots[ <span>1</span>].x(); </div> <div> rhsx[n - <span>1</span>] &#61; ( <span>8</span> * knots[n - <span>1</span>].x() &#43; knots[n].x()) / <span>2.0</span>; </div> <div> rhsy[ <span>0</span>] &#61; knots[ <span>0</span>].y() &#43; <span>2</span> * knots[ <span>1</span>].y(); </div> <div> rhsy[n - <span>1</span>] &#61; ( <span>8</span> * knots[n - <span>1</span>].y() &#43; knots[n].y()) / <span>2.0</span>; </div> <div></div> <div> <span>// Calculate first control points coordinates</span> </div> <div> calculateFirstControlPoints(xs, rhsx, n); </div> <div> calculateFirstControlPoints(ys, rhsy, n); </div> <div></div> <div> <span>// Fill output control points.</span> </div> <div> <span>for</span> ( <span>int</span> i &#61; <span>0</span>; i &lt; n; &#43;&#43;i) { </div> <div> (*firstControlPoints)[i].rx() &#61; xs[i]; </div> <div> (*firstControlPoints)[i].ry() &#61; ys[i]; </div> <div></div> <div> <span>if</span> (i &lt; n - <span>1</span>) { </div> <div> (*secondControlPoints)[i].rx() &#61; <span>2</span> * knots[i &#43; <span>1</span>].x() - xs[i &#43; <span>1</span>]; </div> <div> (*secondControlPoints)[i].ry() &#61; <span>2</span> * knots[i &#43; <span>1</span>].y() - ys[i &#43; <span>1</span>]; </div> <div> } <span>else</span> { </div> <div> (*secondControlPoints)[i].rx() &#61; (knots[n].x() &#43; xs[n - <span>1</span>]) / <span>2</span>; </div> <div> (*secondControlPoints)[i].ry() &#61; (knots[n].y() &#43; ys[n - <span>1</span>]) / <span>2</span>; </div> <div> } </div> <div> } </div> <div></div> <div> <span>delete</span> xs; </div> <div> <span>delete</span> ys; </div> <div> <span>delete</span>[] rhsx; </div> <div> <span>delete</span>[] rhsy; </div> <div> } </div></pre> </td></tr></tbody></div> 
相信还有其他用于生成平滑曲线的方法,甚至可以同时解决 SmoothCurveGenerator1 和 SmoothCurveGenerator2 的问题,这个需要大家继续深入的研究了。

讯享网
小讯
上一篇 2025-06-02 18:00
下一篇 2025-04-14 13:20

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/157369.html