我有QPainterPath
可以保存任何行和/或三次贝塞尔曲线。现在,我需要QPoint
来计算QPainterPath
和点之间的最短距离。由于路径本身不仅仅是存储元素,而是将它们添加到路径中,因此它本身并不提供这样的功能。我唯一的想法是使用QPainterPath::toFillPolygon()
构造一个多边形,但这有时会返回一个等于路径的多边形,有时候是一个空的多边形。此外,QPolygonF
对象只是一个点列表,其中一些与线连接,其中一些在原始路径中没有连接,但我无法找出它们中的哪些是连接的,不是。
是否有任何(简单)解决方案来计算QPainterPath
(最好不转换为多边形)和QPoint
之间的最短距离?
答案 0 :(得分:1)
QPainterPath
有pointAtPercent()
,因此您可以在给定步骤中迭代路径,并检查路径上的多个点与目标点之间的距离。
这将为您提供大致最短的距离,如果您想要更高的精度,您可以专注于路径的这些段并以更精细的步骤迭代。
答案 1 :(得分:0)
将此代码段粘贴到您的utility.cpp
或geom_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}}等。
mapToItem, mapFromParent, mapFromScene