Last active
March 23, 2021 06:08
-
-
Save steveruizok/3b80882ada0b10539bc88a41042faf4d to your computer and use it in GitHub Desktop.
Get the minimum distance between a point and a line. Get the nearest point on a line to a second point.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Get the minimum distance from a point P to a line with a segment AB. | |
* @param A The start of the line. | |
* @param B The end of the line. | |
* @param P A point. | |
* @returns | |
*/ | |
export function distanceToLine(A: number[], B: number[], P: number[]) { | |
const delta = sub(B, A) | |
const angle = Math.atan2(delta[1], delta[0]) | |
const dir = rot(sub(P, A), -angle) | |
return dir[1] | |
} | |
/** | |
* Get the nearest point on a line segment AB. | |
* @param A The start of the line. | |
* @param B The end of the line. | |
* @param P A point. | |
* @param clamp Whether to clamp the resulting point to the segment. | |
* @returns | |
*/ | |
export function nearestPointOnLine( | |
A: number[], | |
B: number[], | |
P: number[], | |
clamp = true | |
) { | |
const delta = sub(B, A) | |
const angle = Math.atan2(delta[1], delta[0]) | |
const length = len(delta) | |
const dir = rot(sub(P, A), -angle) | |
if (clamp) { | |
if (dir[0] < 0) return A | |
if (dir[0] > length) return B | |
} | |
return add(A, div(mul(delta, dir[0]), length)) | |
} | |
// Vector utilities | |
export function add(A: number[], B: number[]) { | |
return [A[0] + B[0], A[1] + B[1]] | |
} | |
export function sub(A: number[], B: number[]) { | |
return [A[0] - B[0], A[1] - B[1]] | |
} | |
export function div(A: number[], n: number) { | |
return [A[0] / n, A[1] / n] | |
} | |
export function mul(A: number[], n: number) { | |
return [A[0] * n, A[1] * n] | |
} | |
export function dpr(A: number[], B: number[]) { | |
return A[0] * B[0] + A[1] * B[1] | |
} | |
export function cpr(A: number[], B: number[]) { | |
return A[0] * B[1] - B[0] * A[1] | |
} | |
export function len(A: number[]) { | |
return Math.hypot(A[0], A[1]) | |
} | |
export function rot(A: number[], r: number) { | |
return [ | |
A[0] * Math.cos(r) - A[1] * Math.sin(r), | |
A[1] * Math.cos(r) + A[0] * Math.sin(r), | |
] | |
} | |
// Thanks to https://observablehq.com/@tomktjemsland/distance-from-point-to-line |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment