计算目录
已知,线段的起点和终点,以及点的坐标。求点到线的最短距离
一、原理分析
线段的起点为 (,
) ,终点为(
,
),点的坐标为(
,
)
求垂点坐标:(,
)
解答如下:
1.向量相乘为0,即向量垂直
由向量公式可以知道,两个向量相乘为0表示垂直。
假设线段向量为,点和垂点向量为
*
=0
=>
2.垂点在线段上
由于 (,
)经过线段因此假设线段为y=ax+b,得到一下
由1和2得到 ===>
将4带入1 ===>
将4和5带入3 ===>
由( 7` ) ===>
由 (6`)和(8`) ===>
===>
将带入(8`)得到最后结果
计算好垂点,那么我们就要计算他们于起始点的位置。
判断垂点是否在线段中,如果不在,那么需要计算他距离最近的点。
3.垂点范围
的范围
如果: ==>
那么满足 ,表示
在线段上
如果:
那么满足 ,表示
在线段上
的范围
如果: ==>
那么满足 ,表示
在线段上
如果:
那么满足 ,表示
在线段上
如果垂点不在线段上,那么点到定点的距离最短。
二、代码实现
线段的数据结构
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传送门