得到曲线上的点,画出曲线,这是一个很常见的需求。画曲线嘛,当然难不住我们,用 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<QPointF> knots; </div> <div> knots << QPointF(x1, y1); </div> <div> ... </div> <div> knots << QPointF(xn, yn); </div> <div></div> <div> <span>// [2] 创建平滑曲线</span> </div> <div> QPainterPath smoothCurve1 = SmoothCurveGenerator1::generateSmoothCurve(knots); </div> <div> QPainterPath smoothCurve2 = 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><QList></span></span> </div> <div> <span>#<span>include</span> <span><QPointF></span></span> </div> <div> <span>#<span>include</span> <span><QPainterPath></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,创建平滑曲线 </div> <div> * </div> <div> * @param points - 曲线上的点 </div> <div> * @return - 返回使用给定的点创建的 QPainterPath 表示的平滑曲线 </div> <div> */ </div> <div> <span><span>static</span> QPainterPath <span>generateSmoothCurve</span><span>(<span>const</span> QList<QPointF> &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>"SmoothCurveGenerator1.h"</span></span> </div> <div></div> <div> QPainterPath SmoothCurveGenerator1::generateSmoothCurve( <span>const</span> QList<QPointF> &points) { </div> <div> <span>if</span> (points.size() == <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 = <span>0</span>; i < points.size() - <span>1</span>; ++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 = points[i]; </div> <div> QPointF ep = points[i+ <span>1</span>]; </div> <div> QPointF c1 = QPointF((sp.x() + ep.x()) / <span>2</span>, sp.y()); </div> <div> QPointF c2 = QPointF((sp.x() + 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><QWidget></span></span> </div> <div> <span>#<span>include</span> <span><QList></span></span> </div> <div> <span>#<span>include</span> <span><QPointF></span></span> </div> <div> <span>#<span>include</span> <span><QPainterPath></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 = <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<QPointF> 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>"SmoothCurveWidget.h"</span></span> </div> <div> <span>#<span>include</span> <span>"ui_SmoothCurveWidget.h"</span></span> </div> <div> <span>#<span>include</span> <span>"SmoothCurveGenerator1.h"</span></span> </div> <div> <span>#<span>include</span> <span>"SmoothCurveGenerator2.h"</span></span> </div> <div></div> <div> <span>#<span>include</span> <span><QPainter></span></span> </div> <div> <span>#<span>include</span> <span><QtGlobal></span></span> </div> <div> <span>#<span>include</span> <span><QDateTime></span></span> </div> <div></div> <div> SmoothCurveWidget::SmoothCurveWidget(QWidget *parent) : </div> <div> QWidget(parent), ui( <span>new</span> Ui::SmoothCurveWidget) { </div> <div> ui->setupUi( <span>this</span>); </div> <div></div> <div> connect(ui->generateCurveButton, SIGNAL(clicked( <span>bool</span>)), <span>this</span>, SLOT(generateCurves())); </div> <div> connect(ui->showKnotsCheckBox, SIGNAL(clicked( <span>bool</span>)), <span>this</span>, SLOT(update())); </div> <div> connect(ui->showSmoothCurveCheckBox, SIGNAL(clicked( <span>bool</span>)), <span>this</span>, SLOT(update())); </div> <div> connect(ui->smoothCurveGeneratorComboBox, SIGNAL(currentIndexChanged( <span>int</span>)), <span>this</span>, SLOT(update())); </div> <div></div> <div> ui->generateCurveButton->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 被选中时显示平滑曲线,否则显示非平滑曲线</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->showSmoothCurveCheckBox->isChecked() && ui->smoothCurveGeneratorComboBox->currentIndex() == <span>0</span>) { </div> <div> painter.drawPath(smoothCurve1); </div> <div> } <span>else</span> <span>if</span> (ui->showSmoothCurveCheckBox->isChecked() && ui->smoothCurveGeneratorComboBox->currentIndex() == <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>// 如果曲线上的点可见,则显示出来</span> </div> <div> <span>if</span> (ui->showKnotsCheckBox->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],纵坐标为 [-100, 100]</span> </div> <div> <span>int</span> x = <span>-200</span>; </div> <div> knots.clear(); </div> <div> <span>while</span> (x < <span>200</span>) { </div> <div> knots << QPointF(x, qrand() % <span>200</span> - <span>100</span>); </div> <div> x += qMin(qrand() % <span>30</span> + <span>5</span>, <span>200</span>); </div> <div> } </div> <div></div> <div> <span>// 根据曲线上的点创建平滑曲线</span> </div> <div> smoothCurve1 = SmoothCurveGenerator1::generateSmoothCurve(knots); </div> <div> smoothCurve2 = SmoothCurveGenerator2::generateSmoothCurve(knots); </div> <div></div> <div> <span>// 连接点创建非平滑曲线曲线</span> </div> <div> nonSmoothCurve = QPainterPath(); </div> <div> nonSmoothCurve.moveTo(knots[ <span>0</span>]); </div> <div> <span>for</span> ( <span>int</span> i = <span>1</span>; i < knots.size(); ++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>"SmoothCurveWidget.h"</span></span> </div> <div> <span>#<span>include</span> <span><QApplication></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,核心是使用曲线上的点计算出贝塞尔曲线的两个控制点,然后使用贝塞尔曲线生成平滑曲线,很惭愧的是生成控制点的算法细节我没看懂,只不过是作了一次搬运工,把程序移植到了 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><QList></span></span> </div> <div> <span>#<span>include</span> <span><QPointF></span></span> </div> <div> <span>#<span>include</span> <span><QPainterPath></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,创建平滑曲线 </div> <div> * @param points - 曲线上的点 </div> <div> * @return - 返回使用给定的点创建的 QPainterPath 表示的平滑曲线 </div> <div> */ </div> <div> <span><span>static</span> QPainterPath <span>generateSmoothCurve</span><span>(<span>const</span> QList<QPointF> &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> * @param result - Solution vector. </div> <div> * @param rhs - Right hand side vector. </div> <div> * @param n - Size of rhs. </div> <div> */ </div> <div> <span><span>static</span> <span>void</span> <span>calculateFirstControlPoints</span><span>(<span>double</span> * &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> * @param knots - Points of the given curve. </div> <div> * @param firstControlPoints - Store the generated first control points. </div> <div> * @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<QPointF> &knots,</span></span> </div> <div> QList<QPointF> *firstControlPoints, </div> <div> QList<QPointF> *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>"SmoothCurveGenerator2.h"</span></span> </div> <div></div> <div> QPainterPath SmoothCurveGenerator2::generateSmoothCurve( <span>const</span> QList<QPointF> &points) { </div> <div> QPainterPath path; </div> <div> <span>int</span> len = points.size(); </div> <div></div> <div> <span>if</span> (len < <span>2</span>) { </div> <div> <span>return</span> path; </div> <div> } </div> <div></div> <div> QList<QPointF> firstControlPoints; </div> <div> QList<QPointF> secondControlPoints; </div> <div> calculateControlPoints(points, &firstControlPoints, &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 = <span>0</span>; i < len - <span>1</span>; ++i) { </div> <div> path.cubicTo(firstControlPoints[i], secondControlPoints[i], points[i+ <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> *&result, <span>const</span> <span>double</span> *rhs, <span>int</span> n) { </div> <div> result = <span>new</span> <span>double</span>[n]; </div> <div> <span>double</span> *tmp = <span>new</span> <span>double</span>[n]; </div> <div> <span>double</span> b = <span>2.0</span>; </div> <div> result[ <span>0</span>] = rhs[ <span>0</span>] / b; </div> <div></div> <div> <span>// Decomposition and forward substitution.</span> </div> <div> <span>for</span> ( <span>int</span> i = <span>1</span>; i < n; i++) { </div> <div> tmp[i] = <span>1</span> / b; </div> <div> b = (i < n - <span>1</span> ? <span>4.0</span> : <span>3.5</span>) - tmp[i]; </div> <div> result[i] = (rhs[i] - result[i - <span>1</span>]) / b; </div> <div> } </div> <div></div> <div> <span>for</span> ( <span>int</span> i = <span>1</span>; i < n; i++) { </div> <div> result[n - i - <span>1</span>] -= 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<QPointF> &knots, </div> <div> QList<QPointF> *firstControlPoints, </div> <div> QList<QPointF> *secondControlPoints) { </div> <div> <span>int</span> n = knots.size() - <span>1</span>; </div> <div></div> <div> <span>for</span> ( <span>int</span> i = <span>0</span>; i < n; ++i) { </div> <div> firstControlPoints->append(QPointF()); </div> <div> secondControlPoints->append(QPointF()); </div> <div> } </div> <div></div> <div> <span>if</span> (n == <span>1</span>) { </div> <div> <span>// Special case: Bezier curve should be a straight line.</span> </div> <div> <span>// P1 = (2P0 + P3) / 3</span> </div> <div> (*firstControlPoints)[ <span>0</span>].rx() = ( <span>2</span> * knots[ <span>0</span>].x() + knots[ <span>1</span>].x()) / <span>3</span>; </div> <div> (*firstControlPoints)[ <span>0</span>].ry() = ( <span>2</span> * knots[ <span>0</span>].y() + knots[ <span>1</span>].y()) / <span>3</span>; </div> <div></div> <div> <span>// P2 = 2P1 – P0</span> </div> <div> (*secondControlPoints)[ <span>0</span>].rx() = <span>2</span> * (*firstControlPoints)[ <span>0</span>].x() - knots[ <span>0</span>].x(); </div> <div> (*secondControlPoints)[ <span>0</span>].ry() = <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 = <span>0</span>; </div> <div> <span>double</span> *ys = <span>0</span>; </div> <div> <span>double</span> *rhsx = <span>new</span> <span>double</span>[n]; <span>// Right hand side vector</span> </div> <div> <span>double</span> *rhsy = <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 = <span>1</span>; i < n - <span>1</span>; ++i) { </div> <div> rhsx[i] = <span>4</span> * knots[i].x() + <span>2</span> * knots[i + <span>1</span>].x(); </div> <div> rhsy[i] = <span>4</span> * knots[i].y() + <span>2</span> * knots[i + <span>1</span>].y(); </div> <div> } </div> <div> rhsx[ <span>0</span>] = knots[ <span>0</span>].x() + <span>2</span> * knots[ <span>1</span>].x(); </div> <div> rhsx[n - <span>1</span>] = ( <span>8</span> * knots[n - <span>1</span>].x() + knots[n].x()) / <span>2.0</span>; </div> <div> rhsy[ <span>0</span>] = knots[ <span>0</span>].y() + <span>2</span> * knots[ <span>1</span>].y(); </div> <div> rhsy[n - <span>1</span>] = ( <span>8</span> * knots[n - <span>1</span>].y() + 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 = <span>0</span>; i < n; ++i) { </div> <div> (*firstControlPoints)[i].rx() = xs[i]; </div> <div> (*firstControlPoints)[i].ry() = ys[i]; </div> <div></div> <div> <span>if</span> (i < n - <span>1</span>) { </div> <div> (*secondControlPoints)[i].rx() = <span>2</span> * knots[i + <span>1</span>].x() - xs[i + <span>1</span>]; </div> <div> (*secondControlPoints)[i].ry() = <span>2</span> * knots[i + <span>1</span>].y() - ys[i + <span>1</span>]; </div> <div> } <span>else</span> { </div> <div> (*secondControlPoints)[i].rx() = (knots[n].x() + xs[n - <span>1</span>]) / <span>2</span>; </div> <div> (*secondControlPoints)[i].ry() = (knots[n].y() + 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 的问题,这个需要大家继续深入的研究了。
讯享网







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