summaryrefslogtreecommitdiffstats
path: root/src/math/line.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/math/line.ts')
-rw-r--r--src/math/line.ts72
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;
+ }
}