Skip to content

Instantly share code, notes, and snippets.

@steveruizok
Created October 4, 2020 19:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steveruizok/fe417d04f772c114ef383c6b2f6c26b1 to your computer and use it in GitHub Desktop.
Save steveruizok/fe417d04f772c114ef383c6b2f6c26b1 to your computer and use it in GitHub Desktop.
A minimal ray-casting function.
export type RayOptions = {
max?: number
min?: number
start?: number
}
/**
* Casts a ray in a given direction and check if it hits something.
* @param from - [x, y]
* @param delta - [deltaX, deltaY]
* @param hitTest - (point) => hit
* @param options - {max: number, min: number, start: number}
* @example
* ```ts
* const hitPolygon = castRay([0,0], [.25, .5], (point) => {
* return myPolys.find(poly => pointInPoly(point, poly))
* }
* ```
*/
export function castRay<T = any>(
from: number[],
delta: number[],
hitTest: (point: number[]) => T,
options: RayOptions = {}
): {
hit?: T
point: number[]
} {
const { min = 0, max = 9999, start = 1 } = options
const step = Math.hypot(delta[0], delta[1]),
dx = delta[0] / step,
dy = delta[1] / step,
point = [from[0] + start * dx, from[1] + start * dy]
let hit: T | undefined = undefined
if (step > min) {
for (let dist = 0; dist <= max; dist++) {
point[0] += dx
point[1] += dy
hit = hitTest(point)
if (hit !== undefined) {
return { hit, point }
}
}
}
return { hit, point } // No hit
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment