1. 程式人生 > >JS:求點與線段的最短距離,並返回該最短距離線上段上的座標。

JS:求點與線段的最短距離,並返回該最短距離線上段上的座標。

直接上程式碼:

function PointToLineDistance (xx, yy, x1, y1, x2, y2) {

let ang1, ang2, ang, m;

let result = 0;

// 分別計算三條邊的長度

const a = Math.sqrt((x1 - xx) * (x1 - xx) + (y1 - yy) * (y1 - yy));

if (a === 0) {

return [0, { x: x1,

y: y1 }];

}

const b = Math.sqrt((x2 - xx) * (x2 - xx) + (y2 - yy) * (y2 - yy));

if (b === 0) {

return [0, { x: x2,

y: y2 }];

}

const c = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));

// 如果線段是一個點則退出函式並返回距離

if (c === 0) {

result = a;

return [result, { x: x1,

y: y1 }];

}

// 如果點(xx,yy到點x1,y1)這條邊短

if (a < b) {

// 如果直線段AB是水平線。得到直線段AB的弧度

if (y1 === y2) {

if (x1 < x2) {

ang1 = 0;

} else {

ang1 = Math.PI;

}

} else {

m = (x2 - x1) / c;

if (m - 1 > 0.00001) {

m = 1;

}

ang1 = Math.acos(m);

if (y1 > y2) {

ang1 = Math.PI * 2 - ang1;

}// 直線(x1,y1)-(x2,y2)與折X軸正向夾角的弧度

}

m = (xx - x1) / a;

if (m - 1 > 0.00001) {

m = 1;

}

ang2 = Math.acos(m);

if (y1 > yy) {

ang2 = Math.PI * 2 - ang2;

}// 直線(x1,y1)-(xx,yy)與折X軸正向夾角的弧度

ang = ang2 - ang1;

if (ang < 0) {

ang = -ang;

}

if (ang > Math.PI) {

ang = Math.PI * 2 - ang;

}

// 如果是鈍角則直接返回距離

if (ang > Math.PI / 2) {

return [a, { x: x1,

y: y1 }];

}

// 返回距離並且求得當前距離所線上段的座標

if (x1 === x2) {

return [b * Math.sin(ang), { x: x1,

y: yy }];

} else if (y1 === y2) {

return [b * Math.sin(ang), { x: xx,

y: y1 }];

}

// 直線的斜率存在且不為0的情況下

let x = 0,

y = 0;

const k1 = ((y2 - y1) / x2 - x1);

const kk = -1 / k1;

const bb = yy - xx * kk;

const b1 = y2 - x2 * k1;

x = (b1 - bb) / (kk - k1);

y = kk * x + bb;

return [a * Math.sin(ang), { x,

y }];

}

// 如果兩個點的縱座標相同,則直接得到直線斜率的弧度

if (y1 === y2) {

if (x1 < x2) {

ang1 = Math.PI;

} else {

ang1 = 0;

}

} else {

m = (x1 - x2) / c;

if (m - 1 > 0.00001) {

m = 1;

}

ang1 = Math.acos(m);

if (y2 > y1) {

ang1 = Math.PI * 2 - ang1;

}

}

m = (xx - x2) / b;

if (m - 1 > 0.00001) {

m = 1;

}

ang2 = Math.acos(m);// 直線(x2-x1)-(xx,yy)斜率的弧度

if (y2 > yy) {

ang2 = Math.PI * 2 - ang2;

}

ang = ang2 - ang1;

if (ang < 0) {

ang = -ang;

}

if (ang > Math.PI) {

ang = Math.PI * 2 - ang;

}// 交角的大小

// 如果是對角則直接返回距離

if (ang > Math.PI / 2) {

return [b, { x: x2,

y: y2 }];

}

// 如果是銳角,返回計算得到的距離,並計算出相應的座標

if (x1 === x2) {

return [b * Math.sin(ang), { x: x1,

y: yy }];

} else if (y1 === y2) {

return [b * Math.sin(ang), { x: xx,

y: y1 }];

}

// 直線的斜率存在且不為0的情況下

let x = 0,

y = 0;

const k1 = ((y2 - y1) / x2 - x1);

const kk = -1 / k1;

const bb = yy - xx * kk;

const b1 = y2 - x2 * k1;

x = (b1 - bb) / (kk - k1);

y = kk * x + bb;

return [b * Math.sin(ang), { x,

y }];

}