1.点到直线的距离

求点到直线的垂点python 求点到直线距离方法_经验分享


如上图所示,点C为直线AB外一点,CD⊥AB,那么CD的模长就是点C到直线AB的距离。所以求点到直线得距离,就是求CD得长度。

求点到直线的垂点python 求点到直线距离方法_经验分享_02


作辅助线如上图所示,要求得线段CD得长度,需要知道点D得坐标,剩下求两点距离就变得简单了。

为求得点D得坐标。

**令A(xa,ya),B(xb,yb),C(xc,yc),D(xd,yd)**其中,A,B,C的坐标已知(如果不已知也没法求呀)。

dx = xb - xa;
dy = yb - ya;

q = |AD|/|AB|,使得

xd = xa + q·dx;
yd = ya + q·dy;

令|AC| = m,|AD| = n,|CD|=o,
根据两点距离公式得出:

方程a: m2 = (xc - xa)2 + (yc - ya)2;
方程b: n2 = (xd - xa)2 + (yd - ya)2;
方程c: o2 = (xd - xc)2 + (yd - yc)2;

根据勾股定理得知,
m2=n2+o2;

将方程a,b,c代入上式,得:

(xc - xa)2 + (yc - ya)2 = (xd - xa)2+(yd - ya)o2 + (xd - xc)2+(yd - yc)2
展开化简得出:
方程d: -xa·xc - yc·ya = xd2 + xa2- xd·xa+ yd2 - yd·ya - xd·xc - yd·yc;
将xd = xa + q·dx;yd = ya + q·dy代入方程d,
求得: q = (dx(xc - xa) + dy(yc - ya))/(dx2 + dy2);
又 xd = xa + q·dx;yd = ya + q·dy;
所以:
xd = (dx(xc - xa) + dy(yc - ya))/(dx2+ dy2) * dx + xa;
yd = (dx(xc - xa) + dy(yc - ya))/(dx2 + dy2) * dy + ya;

这个求方程的过程可以自己导一下。

求得D得坐标,就可以根据两点间距离公式得到点到直线得距离。
TS代码实现如下:

/**
     * 求C到直线AB得距离
     * @param C 直线外一点
     * @param A 直线上一点
     * @param B 直线上一点
     */
    static pointToLineDistance(C, A, B) {
        let dx = B.x - A.x;
        let dy = B.y - A.y;
        let d = dx*dx + dy*dy;
        let D;
        if(d === 0){ // |AB| = 0,说明A与B共点
            D = A;
        }else{
            let q = ((C.x - A.x) * dx + (C.y - A.y) * dy) / d; // 求出q得值
            D = {x:A.x + q * dx, y:A.y + q * dy};// 得到D得坐标
        }
        dx = D.x - C.x;
        dy = D.y - C.y;
        return Math.sqrt(dx*dx + dy*dy);
    }

2.点到线段的距离

这边拓展一下点到线段得距离,当C到AB得垂足D,不在A,B之间得时候,求出点C到线段AB两端点最近得距离。

求点到直线的垂点python 求点到直线距离方法_经验分享_03


分析上图

当D在AB的左侧时,C点距离A点更近,如绿色的CD所示;此时返回|AC|的长度;

当D在AB的右侧时,C点距离B点更近,如蓝色的CD所示;此时返回|BC|的长度;

那如何判断D在AB的左侧还是右侧呢?

因为B,C,D共线,如图中所示

当xd < xa && yd < ya时,D在AB的左侧;
当xd > xb && yd > yb时,D在AB的右侧;

(有人可能会问,你上面的图直线的斜率k是大于0的,如果小于0的话,这个就不成立了!)

借用上面的方程,设dx,dy均不等于0。

dx = xb - xa;
dy = yb - ya;
xd = xa + q·dx;
yd = ya + q·dy;

分析得到:

当xd < xa && yd < ya时,q < 0;
当xd < xa && yd < ya时,q > 1;(xb = xa + dx);

(这边如果直线斜率k < 0,那么dy一定是小于0的,负负得正,又刚好满足条件)
所以,求点到线段的长度代码实现如下

/**
     * 求C到线段AB得距离
     * @param C 线段外一点
     * @param A 线段上一点
     * @param B 线段上一点
     */
    static pointToLineSegmentDistance(C, A, B) {
        let dx = B.x - A.x;
        let dy = B.y - A.y;
        let d = dx*dx + dy*dy;
        let D;
        if(d === 0){ // |AB| = 0,说明A与B共点,D可以直接给A
            D = A;
        }else{
            let q = ((C.x - A.x) * dx + (C.y - A.y) * dy) / d; // 求出q得值
            if (q < 0) D = A; //垂足在AB左边
            else if (q > 1) D = B; //垂足在AB右边
            else D = {x:A.x + q * dx, y:A.y + q * dy}; // 得到D得坐标
        }
       
        dx = D.x - C.x;
        dy = D.y - C.y;
        return Math.sqrt(dx*dx + dy*dy);