0
点赞
收藏
分享

微信扫一扫

求点到线段的最短距离

计算目录

一、原理分析

1.向量相乘为0,即向量垂直

2.垂点在线段上

垂点范围

X的范围

 Y的范围

二、代码实现

已知,线段的起点和终点,以及点的坐标。求点到线的最短距离

一、原理分析

线段的起点为 (_{}X_{s},Y_{s}) ,终点为(_{}X_{e},Y_{e}),点的坐标为(_{}X_{p},Y_{p})

求垂点坐标:(x_{c},y_{c}

 解答如下:

1.向量相乘为0,即向量垂直

由向量公式可以知道,两个向量相乘为0表示垂直。

假设线段向量为\vec{a},点和垂点向量为\vec{p}

 \vec{a}*\vec{p}=0

=>

2.垂点在线段上

由于 (X_{c},Y_{c})经过线段因此假设线段为y=ax+b,得到一下


由1和2得到 ===>


将4带入1 ===>


将4和5带入3 ===>

由( 7` )  ===>


由 (6`)和(8`)   ===>

x_{c} = \frac{(X_{s}-X_{e})^{2}*X_{p} +(Y_{p}-Y_{s})*(Y_{s}-Y_{e})*(X_{s}-X_{e}) + X_{s}* (Y_{s}-Y_{e})^{2}}{(X_{s}-X_{e})^{2} + (Y_{s}-Y_{e})^{2} }

===>

x^{c}带入(8`)得到最后结果

计算好垂点,那么我们就要计算他们于起始点的位置。

判断垂点是否在线段中,如果不在,那么需要计算他距离最近的点。

3.垂点范围

x_{c} 的范围

如果: X_{s} > X{e} ==>

那么满足 X_{s} > x_{c} > X{e},表示x_{c}在线段上

如果:X_{s} < X{e}

那么满足 X_{s} > x_{c} > X{e},表示x_{c}在线段上

 y_{c} 的范围

如果: Y_{s} > Y{e} ==>

那么满足 Y_{s} > y_{c} > Y{e},表示y_{c}在线段上

如果:Y_{s} < Y{e}

那么满足 Y_{s} > y_{c} > Y_{e},表示y_{c}在线段上

如果垂点不在线段上,那么点(X_{p},Y_{p})到定点的距离最短。

二、代码实现

线段的数据结构

struct LineSegment {
QPointF startPoint;
QPointF endPoint;
LineSegment(QPointF a, QPointF b)
{
startPoint = a;
endPoint = b;
}
LineSegment() {}
};

计算垂点代码如下:

 /**
* @brief 获取点到在线段上的线的垂点
* @param pt 点
* @param seg 线段
* @return
*/

QPointF QDrawingPaperView::getPointToLineVerticalpoint(QPointF pt,
LineSegment seg)

{
QPointF np;
double x_se = seg.startPoint.x() - seg.endPoint.x();
double y_se = seg.startPoint.y() - seg.endPoint.y();
double x_se_2 = x_se * x_se;
double y_se_2 = y_se * y_se;
double x = (x_se_2 * pt.x() + (pt.y() - seg.startPoint.y()) * y_se * x_se +
seg.startPoint.x() * y_se_2) /
(x_se_2 + y_se_2);
double y = pt.y() + x_se * (pt.x() - x) / y_se;
np.setX(x);
np.setY(y);
return np;
}

 计算两点之间的距离如下:

// 计算两点之间的距离
double QDrawingPaperView::distance(QPointF startPoint, QPointF endPoint)
{
double dis = 0;
double width = startPoint.x() - endPoint.x();
double height = startPoint.y() - endPoint.y();
dis = qSqrt(width * width + height * height);
return dis;
}

判断垂点是否在线段上


bool QDrawingPaperView::verticalPointIsOnLine(QPoint np, LineSegment seg)
{
bool isOnX = false; // 垂点的x坐标是否在线段上
bool isOnY = false; // 垂点的y坐标是否在线段上
if (seg.startPoint.x() > seg.endPoint.x()) {
if (np.x() < seg.startPoint.x() && np.x() > seg.endPoint.x()) {
isOnX = true;
}
} else {
if (np.x() < seg.endPoint.x() && np.x() > seg.startPoint.x()) {
isOnX = true;
}
}

if (seg.startPoint.y() > seg.endPoint.y()) {
if (np.y() < seg.startPoint.y() && np.y() > seg.endPoint.y()) {
isOnY = true;
}
} else {
if (np.y() < seg.endPoint.y() && np.y() > seg.startPoint.y()) {
isOnY = true;
}
}

if (isOnX && isOnY) {
return true;
}
return false;
}

点计算距离线段距离

double QDrawingPaperView::pointToSegmentDis(QPointF pt, LineSegment seg)
{
// 1. 获取垂点
QPointF Verticalpoint;
Verticalpoint = getPointToLineVerticalpoint(pt, seg);
// 2. 判断垂点是否在线段上

bool isOnSeg = verticalPointIsOnLine(Verticalpoint, seg);
if (isOnSeg) {
// 如果在线段上那么垂点到点的距离最短
return distance(pt, Verticalpoint);
} else {
// 如果不在点段上那么到两点的距离最短。
double startDistance = distance(pt, seg.startPoint);
double endDistance = distance(pt, seg.endPoint);
return startDistance < endDistance ? startDistance : endDistance;
}
}

git传送门

举报

相关推荐

0 条评论