有没有办法在QT中画一条流畅的线通过一组点?点的数量和位置是在运行时设置的。
目前,我绘制了一个包含lineTo的QPainterPath,它从一个点到另一个点,创建一条路径。我确实使用了渲染提示抗锯齿,但路径仍然参差不齐。
我见过QSplineSeries,它似乎提供了这种曲线路径,但在Qt4.8中不可用,这是我正在使用的QT版本。
另一个经常被建议的选择是使用贝塞尔曲线,但这些曲线使用一个起点和终点以及两个控制点,所以我需要为每个线段(每个lineTo)计算它,并以某种方式计算那些我目前没有的控制点。
发布于 2017-04-25 19:07:20
最后,我实现了某种变通方法,它基本上采用了两条相连的线,删除了它们之间的连接点,并将其替换为一条曲线。因为我有很多这样的更改看不到的小线,所以我删除了所有很短的线,并重新连接了开放的两端。该功能主要由Bojan Kverh提供,请查看他的教程:https://www.toptal.com/c-plus-plus/rounded-corners-bezier-curves-qpainter
下面是函数:
namespace
{
float distance(const QPointF& pt1, const QPointF& pt2)
{
float hd = (pt1.x() - pt2.x()) * (pt1.x() - pt2.x());
float vd = (pt1.y() - pt2.y()) * (pt1.y() - pt2.y());
return std::sqrt(hd + vd);
}
QPointF getLineStart(const QPointF& pt1, const QPointF& pt2)
{
QPointF pt;
float rat = 10.0 / distance(pt1, pt2);
if (rat > 0.5) {
rat = 0.5;
}
pt.setX((1.0 - rat) * pt1.x() + rat * pt2.x());
pt.setY((1.0 - rat) * pt1.y() + rat * pt2.y());
return pt;
}
QPointF getLineEnd(const QPointF& pt1, const QPointF& pt2)
{
QPointF pt;
float rat = 10.0 / distance(pt1, pt2);
if (rat > 0.5) {
rat = 0.5;
}
pt.setX(rat * pt1.x() + (1.0 - rat)*pt2.x());
pt.setY(rat * pt1.y() + (1.0 - rat)*pt2.y());
return pt;
}
}
void PainterPath::smoothOut(const float& factor)
{
QList<QPointF> points;
QPointF p;
for (int i = 0; i < mPath->elementCount() - 1; i++) {
p = QPointF(mPath->elementAt(i).x, mPath->elementAt(i).y);
// Except for first and last points, check what the distance between two
// points is and if its less then min, don't add them to the list.
if (points.count() > 1 && (i < mPath->elementCount() - 2) && (distance(points.last(), p) < factor)) {
continue;
}
points.append(p);
}
// Don't proceed if we only have 3 or less points.
if (points.count() < 3) {
return;
}
QPointF pt1;
QPointF pt2;
QPainterPath* path = new QPainterPath();
for (int i = 0; i < points.count() - 1; i++) {
pt1 = getLineStart(points[i], points[i + 1]);
if (i == 0) {
path->moveTo(pt1);
} else {
path->quadTo(points[i], pt1);
}
pt2 = getLineEnd(points[i], points[i + 1]);
path->lineTo(pt2);
}
delete mPath;
mPath = path;
prepareGeometryChange();
}发布于 2016-11-23 20:17:56
我不认为Qt4.8中有开箱即用的解决方案(正如你已经注意到的,QSplineSeries是Qt5.x的一个特性)。此外,QSplineSeries是QtCharts模块的一部分,这是一个商业模块(如QtDataVisualization),所以除非你有商业许可,或者你的项目是GPL,否则你不能使用它。
您必须手动完成它,即通过所需的数学运算并自己实现它(或者找到一个很好的实现(甚至不需要用C++实现,更不用说Qt兼容了)。
既然你提到了贝塞尔曲线,我建议你试试composite Bezier curve。我记得在我参与的一个项目中实现了这个东西。它需要some...work。:D This article可能会帮助您入门。
Bezier曲线实际上是B样条(如果我没记错的话)。特别是,如果你可以解决某些缺乏平滑度的问题,你就可以非常快地生成复合贝塞尔曲线。对于它们的健壮性和受欢迎程度,我百分之百确定你可以在网上找到一个像样的实现。可能不是Qt友好的,但如果编写得当,你应该能够在任何时间适应代码。
This看起来很有前途(它在ActionScript中,但是没问题)。或者你可以给QPainterPath::cubicTo()一个镜头,它可以为你创建贝塞尔曲线,给定你也可以提供计算曲线所需的两个控制点。
发布于 2016-12-02 22:31:55
几乎每个人都使用三次插值来完成此任务,您可以选择Bezier曲线或Catmull-Rom样条线。如果你必须击中每个点,那么你需要保持“手柄”或贝塞尔曲线控制点之间的直线。然后使用最小二乘进行拟合,正如您已经发现的那样,这有点牵涉其中。
Catmull Rom样条线的优点是,它们只需要两个额外的控制点(开始和结束,只需镜像点来创建它们)。只要这些点是合理平滑的,这条线就会表现良好。QT图形不太可能直接绘制CatMull Rom样条线,所以转换为Bezier,这是一种标准的发布方法,您可以很容易地从Catmull Rom到Bezier,尽管不是相反-并不是每一个Bezier都可以用只有几个点的Catmull Rom来表示。
如果立方曲线不能给出你想要的曲线,你可以使用其他插值方法,等式五次插值。
https://stackoverflow.com/questions/40764011
复制相似问题