← Back to index

Reflect a line off a circle

A ray fired from a fixed origin toward the mouse. Where it hits the circle, the surface normal is the unit vector from the centre to the hit point; the reflection is the standard d − 2(d·n)n.

See also: Reflect a line off another line — same reflection formula, flat mirror; Circle ↔ line intersection — same quadratic, different output.

Pseudocode

// 1. Ray-circle intersection (quadratic in t along d)
m = origin - centre
a = d . d
b = 2 * (m . d)
c = (m . m) - r * r
disc = b*b - 4*a*c
if (disc < 0) return null       // ray misses
t = (-b - sqrt(disc)) / (2 * a)
if (t < 0) return null           // hit is behind origin
hit = origin + d * t

// 2. Reflect direction about the surface normal
n = (hit - centre) / r
reflected = d - n * (2 * (d . n))

Source

const cx = 180, cy = 150, r = 60
const ox = 20,  oy = 150              // ray origin

const dx = mouseX - ox
const dy = mouseY - oy

const mx = ox - cx, my = oy - cy
const a = dx * dx + dy * dy
const b = 2 * (mx * dx + my * dy)
const c = mx * mx + my * my - r * r
const disc = b * b - 4 * a * c

if (disc >= 0) {
    const t = (-b - Math.sqrt(disc)) / (2 * a)
    if (t > 0 && t < 1) {            // hit before reaching the mouse
        const hx = ox + dx * t
        const hy = oy + dy * t

        // unit normal at hit
        const nx = (hx - cx) / r
        const ny = (hy - cy) / r

        // reflect direction (kept un-normalised; only direction matters)
        const dDotN = dx * nx + dy * ny
        const rdx = dx - 2 * dDotN * nx
        const rdy = dy - 2 * dDotN * ny
    }
}