【问题标题】:What's the best way to implement interactive spline-like curve on QGraphicsView?在 QGraphicsView 上实现交互式样条曲线的最佳方法是什么?
【发布时间】:2019-06-11 00:49:58
【问题描述】:

我正在开发允许用户上传岩石裂缝图像并将样条近似应用于该裂缝的应用程序。

为此,我有QGraphicsView,它显示上传的图像。 上传图像后,用户可以选择在scene 上绘制点,我希望它与线一致。那些连接的点会形成一条曲线,我希望它是交互式的。通过交互式,我的意思是我希望用户能够在不破坏曲线的情况下拖动点,制作连接点的线,随点移动。我还想让用户能够删除选定的点,以便相邻点保持连接。这些并不是我想要的所有功能,但我想你明白了。

我所做的是我创建了一个类MeasurePoint,它继承自QGraphicsItem,并包含有关单个点的所有信息。它有以下字段:

int xPos;
int yPos;
int index;
bool movable;
bool selected;

该类还有几种管理这些点的方法(字段的 getter 和 setter 函数等)。但我没有在该类中实现连接功能,因为它只包含有关单个点的信息,而不是进一步的信息。如果我只是将它们添加到场景中,我喜欢点的行为方式。但是现在我需要按照我之前描述的方式将它们连接起来,我真的不知道该怎么做。

存储积分的最佳方式是什么?我应该如何实现点之间的连接?任何可能的帮助表示赞赏。

附:如果这个问题需要我对 MeasurePoint 类的实现,我会编辑它。

【问题讨论】:

    标签: c++ qt spline qgraphicsscene qgraphicsitem


    【解决方案1】:

    使用QGraphicsPathItem 绘制样条线。然后,使用QPainterPath::cubicTo 方法创建点之间的连接。

    您需要计算控制点以在两点之间绘制平滑的贝塞尔曲线。

    您可以找到一堆基于二次贝塞尔曲线的更好的库,但下面是一个使用 Qt 类型和简单方法来理解如何获取控制点的快速示例:

    QPair<QPointF, QPointF> controlPoints(QPointF const& p0, QPointF const& p1, QPointF const& p2, qreal t=0.25)
    {
        QPair<QPointF, QPointF> pair;
        qreal d01 = qSqrt( ( p1.x() - p0.x() ) * ( p1.x() - p0.x() ) + ( p1.y() - p0.y() ) * ( p1.y() - p0.y() ) );
        qreal d12 = qSqrt( ( p2.x() - p1.x() ) * ( p2.x() - p1.x() ) + ( p2.y() - p1.y() ) * ( p2.y() - p1.y() ) );
    
        qreal fa = t * d01 / ( d01 + d12 );
        qreal fb = t * d12 / ( d01 + d12 );
    
        qreal c1x = p1.x() - fa * ( p2.x() - p0.x() );
        qreal c1y = p1.y() - fa * ( p2.y() - p0.y() );
        qreal c2x = p1.x() + fb * ( p2.x() - p0.x() );
        qreal c2y = p1.y() + fb * ( p2.y() - p0.y() );
    
        pair.first = QPointF( c1x, c1y );
        pair.second = QPointF( c2x, c2y );
    
        return pair;
    }
    

    然后,浏览您的积分列表以创建QPainterPath

    QPainterPath BackgroundBuilder::buildPath(QList<QPointF> const& points)
    {
        QPainterPath pth;
    
        QPair<QPointF, QPointF> pair = controlPoints(points.at(0), points.at(1), points.at(2));
        QPointF p0 = pair.second;
        pth.moveTo(0, 0);
        pth.lineTo(p0);
        for (int i = 2; i != points.count() - 1; ++i)
        {
            QPair<QPointF, QPointF> pair = controlPoints( points.at(i - 1), points.at(i), points.at(i + 1));
            pth.cubicTo( p0, pair.first, points.at( i ) );
            p0 = pair.second;
        }
        return pth;
    }
    

    您可能需要将您的 MeasurePoint 转换为 QPointF 以保持此代码通用:

    QList<QPointF> points;
    QList<MeasurePoint*> measures = ...;
    for (MeasurePoint* measure: measures)
    {
        points << QPointF(measure.xPos, measure.yPos);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-19
      • 1970-01-01
      • 2010-09-17
      • 2021-08-02
      • 1970-01-01
      • 1970-01-01
      • 2011-06-09
      相关资源
      最近更新 更多