Skip to content

Instantly share code, notes, and snippets.

@steveruizok
Created April 17, 2021 10:52
Show Gist options
  • Save steveruizok/d4a2d4edbdb05b51fee3a8686d878353 to your computer and use it in GitHub Desktop.
Save steveruizok/d4a2d4edbdb05b51fee3a8686d878353 to your computer and use it in GitHub Desktop.
Given a point and a line (or line segment), get the nearest point on the line.
/**
* Get the nearest point on a line with a known unit vector that passes through point A
* @param A Any point on the line
* @param u The unit vector for the line.
* @param P A point not on the line to test.
* @returns
*/
export function nearestPointOnLineThroughPoint(
A: number[],
u: number[],
P: number[]
) {
return add(A, mul(u, pry(sub(P, A), u)))
}
/**
* Get the nearest point on a line segment between A and B
* @param A The start of the line segment
* @param B The end of the line segment
* @param P The off-line point
* @param clamp Whether to clamp the point between A and B.
* @returns
*/
export function nearestPointOnLineSegment(
A: number[],
B: number[],
P: number[],
clamp = true
) {
const delta = sub(B, A)
const length = len(delta)
const u = div(delta, length)
const pt = add(A, mul(u, pry(sub(P, A), u)))
const da = dist(A, pt)
const db = dist(B, pt)
if (clamp) {
if (db < da && da > length) return B
if (da < db && db > length) return A
}
return pt
}
/**
* Distance between a point and a line with a known unit vector that passes through a point.
* @param A Any point on the line
* @param u The unit vector for the line.
* @param P A point not on the line to test.
* @returns
*/
export function distanceToLineThroughPoint(
A: number[],
u: number[],
P: number[]
) {
return dist(P, nearestPointOnLineThroughPoint(A, u, P))
}
/**
* Distance between a point and the nearest point on a line segment between A and B
* @param A The start of the line segment
* @param B The end of the line segment
* @param P The off-line point
* @param clamp Whether to clamp the point between A and B.
* @returns
*/
export function distanceToLineSegment(
A: number[],
u: number[],
P: number[],
clamp = true
) {
return dist(P, nearestPointOnLineSegment(A, u, P, clamp))
}
// Vector Utilities
function add(A: number[], B: number[]) {
return [A[0] + B[0], A[1] + B[1]]
}
function sub(A: number[], B: number[]) {
return [A[0] - B[0], A[1] - B[1]]
}
function mul(A: number[], n: number) {
return [A[0] * n, A[1] * n]
}
function dpr(A: number[], B: number[]) {
return A[0] * B[0] + A[1] * B[1]
}
function len(A: number[]) {
return Math.hypot(A[0], A[1])
}
function dist(A: number[], B: number[]) {
return Math.hypot(A[1] - B[1], A[0] - B[0])
}
function pry(A: number[], B: number[]) {
return dpr(A, B) / len(B)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment