4

我有一个QPainterPath可以容纳任何线条和/或三次贝塞尔曲线的序列。现在,QPoint我需要计算QPainterPath点和点之间的最短距离。由于路径本身除了存储元素以便我将它们添加到路径之外并没有做更多的事情,因此它本身不提供这样的功能。我唯一的想法是使用 构造一个多边形QPainterPath::toFillPolygon(),但这有时会返回一个等于路径的多边形,有时会返回一个空多边形。而且,QPolygonF对象只是一个点的列表,有的用线连接,有的在原来的路径上没有连接,但我查不出哪些是连接的,哪些不是。

是否有任何(简单)解决方案来计算 a QPainterPath(最好不转换为多边形)和 a之间的最短距离QPoint

4

2 回答 2

1

QPainterPath具有pointAtPercent()因此您可以在给定步骤迭代路径并检查位于路径上的多个点与目标点之间的距离。

这将为您提供大致最短的距离,如果您想要更精确,您可以专注于路径的这些部分并以更精细的步骤进行迭代。

于 2016-02-23T18:49:29.013 回答
0

将此代码段粘贴到您的utility.cppgeom_tools.cpp. 它是一个通用工具,所以不应该说自定义 QGraphicsItem 子类。

 #include <QVector2D>
 #include <limits>

 QPointF closestPointOnPath(const QPointF &point, const QPainterPath &path)
{
    if (path.isEmpty())
        return point;

    auto vec = QVector2D(point);
    auto poly = path.toFillPolygon();
    float d, minDist = FLT_MAX;
    QVector2D p, q, v, u, minVec;

    for (int k=0; k < poly.count() - 1; k++)
    {
        p = QVector2D(poly.at(k));
        if (k == poly.count() - 1)
            k = -1;
        q = QVector2D(poly.at(k+1));
        v = q - p;
        u = v.normalized();
        d = QVector2D::dotProduct(u, vec - p);

        if (d < 0.0f) {
            d = (vec - p).lengthSquared();

            if (d < minDist)
            {
                minDist = d;
                minVec = p;
            }
        }
        else if (d*d > v.lengthSquared())
        {
            d = (vec - q).lengthSquared();

            if (d < minDist)
            {
                minDist = d;
                minVec = q;
            }
        }
        else {
            u *= d;
            u += p;
            d = (vec - u).lengthSquared();

            if (d < minDist)
            {
                minDist = d;
                minVec = u;
            }
        }
    }

    if (minDist >= FLT_MAX)
        return point;

    return minVec.toPointF();
}

如果必须将箭头附加到节点并且拖动箭头的另一端,这将导致非常流畅的操作。它适用于圆角节点等。您将 QGrpahicsItem 的 shape() 传递给它,它位于项目的本地坐标中,因此point也必须首先位于项目的本地坐标中,否则您必须将其映射到那里(mapToItem, mapFromParent, mapFromScene等)。


Python:

def closest_point_on_path(point:QPointF, path:QPainterPath) -> QPointF:
    if path.isEmpty():
        return point

    vec = QVector2D(point)
    poly = path.toFillPolygon()
    minDist = sys.float_info.max

    for k in range(poly.count()):
        p = QVector2D(poly.at(k))
        if k == poly.count() - 1:
            k = -1 
        q = QVector2D(poly.at(k+1))
        v = q - p
        u = v.normalized()
        d = QVector2D.dotProduct(u, vec - p)

        if d < 0.0:
            d = (vec - p).lengthSquared()
            if d < minDist:
                minDist = d
                minVec = p
        elif d*d > v.lengthSquared():
            d = (vec - q).lengthSquared()
            if d < minDist:
                minDist = d
                minVec = q
        else:
            u *= d
            u += p
            d = (vec - u).lengthSquared()
            if d < minDist:
                minDist = d
                minVec = u

    if minDist >= sys.float_info.max:
        return point

    return minVec.toPointF()
于 2020-01-13T14:10:19.260 回答