QPainterPath和QPoint之间的最短距离

时间:2016-02-23 17:23:20

标签: c++ qt qt5 distance qpainterpath

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

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

2 个答案:

答案 0 :(得分:1)

QPainterPathpointAtPercent(),因此您可以在给定步骤中迭代路径,并检查路径上的多个点与目标点之间的距离。

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

答案 1 :(得分: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也必须首先位于项目的本地坐标中,或者必须在此处进行映射({{ 1}}等。


Python:

mapToItem, mapFromParent, mapFromScene