diff options
Diffstat (limited to 'src/math/line.ts')
-rw-r--r-- | src/math/line.ts | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/src/math/line.ts b/src/math/line.ts index 902c9b6..d071779 100644 --- a/src/math/line.ts +++ b/src/math/line.ts @@ -1,6 +1,9 @@ import { mat2, vec2 } from 'gl-matrix'; -const rot90 = mat2.fromRotation(mat2.create(), Math.PI / 2); +const rot90 = mat2.fromValues( + 0, 1, + -1, 0, +); export function normal(out: vec2, a: vec2): vec2 { return vec2.transformMat2(out, a, rot90); @@ -16,6 +19,10 @@ export class Line { public readonly v: vec2, ) {} + public getNormal(out: vec2): vec2 { + return normal(out, this.v); + } + public projectPointDistance(p2: vec2): number { const v2 = vec2.sub(vec2.create(), p2, this.p); return vec2.dot(this.v, v2); @@ -55,6 +62,22 @@ export class Movement { const d2 = d / crossz(this.v, l.v); return vec2.scaleAndAdd(out, l.p, l.v, d2); } + + public passes(p: vec2): boolean { + const vp = vec2.sub(vec2.create(), p, this.p1); + const d = vec2.dot(this.v, vp); + return d >= 0 && d <= vec2.sqrLen(this.v); + } + + public toLineSegment(): LineSegment { + return LineSegment.fromPoints(this.p1, this.p2); + } + + public translate(t: vec2): Movement { + const p1 = vec2.add(vec2.create(), this.p1, t); + const p2 = vec2.add(vec2.create(), this.p2, t); + return new Movement(p1, p2); + } } export class LineSegment extends Line { @@ -98,4 +121,51 @@ export class LineSegment extends Line { return true; } + + public collidesMoveCircle(out: vec2, move: Movement, r: number): boolean { + const t = this.getNormal(vec2.create()); + vec2.scale(t, t, -r); + + const refMove = move.translate(t); + const refOut = vec2.create(); + + if (this.collidesMove(refOut, refMove)) { + vec2.sub(out, refOut, t); + return true; + } + + return this.collidesPointMoveCircle(out, move, r); + } + + private collidesPointMoveCircle(out: vec2, move: Movement, r: number): boolean { + const moveLine = move.toLineSegment(); + + if (moveLine.projectPointDistance(this.p) < 0) + return false; + + const d = moveLine.distancePoint(this.p) / r; + if (Math.abs(d) >= 1) + return false; + + const e = Math.sqrt(1 - d * d); + + const t = moveLine.getNormal(vec2.create()); + vec2.scale(t, t, d); + vec2.scaleAndAdd(t, t, moveLine.v, e); + + const tr = vec2.scale(vec2.create(), t, r); + + const refMove = move.translate(tr); + + if (vec2.sqrDist(this.p, move.p1) > r * r && !refMove.passes(this.p)) + return false; + + normal(t, t); + + const tang = new Line(this.p, t); + tang.projectPoint(out, refMove.p2); + vec2.sub(out, out, tr); + + return true; + } } |