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 条评论