1. 程式人生 > >二維空間點到直線垂足計算公式推導及Java實現——學習筆記

二維空間點到直線垂足計算公式推導及Java實現——學習筆記

二維空間點到直線垂足計算公式推導及Java實現

前言

簡單的公式推導,大概是高中程度的知識了。不管以前學的好不好,很久不用的東西,一上手還是有點懵的。推導一遍也是為了加深記憶。

公式推導

首先我們知道直線上兩點p1,p2
p1:(x1,y1) p_1:(x_1,y_1)p2:(x2,y2) p_2:(x_2,y_2)
和直線外一點p3
p3:(x3,y3) p_3:(x_3,y_3)
現在我們要求p3在直線p1p2上的垂足p4
p4:(x4,y4) p_4:(x_4,y_4)

:(x4,y4)
可知直線p1p2垂直於直線p3p4,根據向量垂直的關係我們可以知道:
(x1x2)(x3x4)+(y1y2)(y3y4)=0(1) (x_1-x_2)(x_3-x_4)+(y_1-y_2)(y_3-y_4)=0\quad\quad(1)
同時由於p1,p2,p4三點共線,可假設係數u使得:
{x4=x1+u(x1x2)y4=y1+u(y1y2)(2) \begin{cases} \quad x_4=x_1+u(x_1-x_2)\\ \quad y_4=y_1+u(y_1-y_2) \end{cases}\quad\quad\quad(2)

將式子(2)帶入(1)中,可以解得:
u=(x1x2)(x3x1)+(y1y2)(y3y1)(x1x2)2+(y1y2)2(3) u=\frac{(x_1-x_2)(x_3-x_1)+(y_1-y_2)(y_3-y_1)} {(x_1-x_2)^2+(y_1-y_2)^2}\quad(3)
再將求得的u帶回(2)中,就得到了垂足。

程式碼實現

private Point getFoot
(Point p1,Point p2,Point p3){ Point foot=new Point(); float dx=p1.x-p2.x; float dy=p1.y-p2.y; float u=(p3.x-p1.x)*dx+(p3.y-p1.y)*dy; u/=dx*dx+dy*dy; foot.x=(int)(p1.x+u*dx); foot.y=(int)(p1.y+u*dy); return foot; }

程式碼很簡單,不解釋了,參照上面推導的式子(2)和式子(3)

畫蛇添足

這裡多提一點。實際運用中,有的時候需要的只是把點對映在一條線段上,這時會出現一種情況,就是我們計算得到的垂足p4線上段p1p2的延長線上而不是落在p1p2之間,此時我們需要把p4對映到線段的兩個端點(即p1p2)上。針對此情況修改程式碼:

private Point getFoot(Point p1,Point p2,Point p3){
        Point foot=new Point();

        float dx=p1.x-p2.x;
        float dy=p1.y-p2.y;

        float u=(p3.x-p1.x)*dx+(p3.y-p1.y)*dy;
        u/=dx*dx+dy*dy;

        foot.x=(int)(p1.x+u*dx);
        foot.y=(int)(p1.y+u*dy);

        float d=Math.abs((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.x-p2.y));
        float d1=Math.abs((p1.x-foot.x)*(p1.x-foot.x)+(p1.y-foot.y)*(p1.x-foot.y));
        float d2=Math.abs((p2.x-foot.x)*(p2.x-foot.x)+(p2.y-foot.y)*(p2.x-foot.y));

        if(d1>d||d2>d){
            if (d1>d2)  return p2;
            else return p1;
        }

        return foot;
    }