2018-11-26 21:30:04 -05:00
|
|
|
// pathfinder/demo2/geometry.ts
|
|
|
|
//
|
|
|
|
// Copyright © 2018 The Pathfinder Project Developers.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
export const EPSILON: number = 1e-6;
|
|
|
|
|
|
|
|
export class Point2D {
|
|
|
|
x: number;
|
|
|
|
y: number;
|
|
|
|
|
|
|
|
constructor(x: number, y: number) {
|
|
|
|
this.x = x;
|
|
|
|
this.y = y;
|
2018-11-30 18:42:19 -05:00
|
|
|
Object.freeze(this);
|
2018-11-26 21:30:04 -05:00
|
|
|
}
|
|
|
|
|
2018-12-03 17:08:08 -05:00
|
|
|
approxEq(other: Point2D, epsilon: number | undefined): boolean {
|
|
|
|
return approxEq(this.x, other.x, epsilon) && approxEq(this.y, other.y, epsilon);
|
2018-11-26 21:30:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
lerp(other: Point2D, t: number): Point2D {
|
|
|
|
return new Point2D(lerp(this.x, other.x, t), lerp(this.y, other.y, t));
|
|
|
|
}
|
2018-12-03 15:30:12 -05:00
|
|
|
|
|
|
|
translate(x: number, y: number): Point2D {
|
|
|
|
return new Point2D(this.x + x, this.y + y);
|
|
|
|
}
|
2018-12-03 20:16:44 -05:00
|
|
|
|
|
|
|
add(other: Point2D): Point2D {
|
|
|
|
return new Point2D(this.x + other.x, this.y + other.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
sub(other: Point2D): Point2D {
|
|
|
|
return new Point2D(this.x - other.x, this.y - other.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
normalize(): Point2D {
|
|
|
|
const length = this.length();
|
|
|
|
return new Point2D(this.x / length, this.y / length);
|
|
|
|
}
|
|
|
|
|
|
|
|
length(): number {
|
|
|
|
return Math.sqrt(this.x * this.x + this.y * this.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
scale(factor: number): Point2D {
|
|
|
|
return new Point2D(this.x * factor, this.y * factor);
|
|
|
|
}
|
2018-11-26 21:30:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface Size2D {
|
|
|
|
width: number;
|
|
|
|
height: number;
|
|
|
|
}
|
|
|
|
|
2018-11-30 18:42:19 -05:00
|
|
|
export class Rect {
|
2018-11-26 21:30:04 -05:00
|
|
|
origin: Point2D;
|
|
|
|
size: Size2D;
|
2018-11-30 18:42:19 -05:00
|
|
|
|
|
|
|
constructor(origin: Point2D, size: Size2D) {
|
|
|
|
this.origin = origin;
|
|
|
|
this.size = size;
|
|
|
|
Object.freeze(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
unionWithPoint(point: Point2D): Rect {
|
|
|
|
let newOrigin = this.origin, newSize = this.size;
|
|
|
|
|
|
|
|
if (point.x < this.origin.x) {
|
|
|
|
newSize = {
|
|
|
|
width: newSize.width + newOrigin.x - point.x,
|
|
|
|
height: newSize.height,
|
|
|
|
};
|
|
|
|
newOrigin = new Point2D(point.x, newOrigin.y);
|
|
|
|
} else if (point.x > this.maxX()) {
|
|
|
|
newSize = {
|
|
|
|
width: newSize.width + point.x - this.maxX(),
|
|
|
|
height: newSize.height,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (point.y < this.origin.y) {
|
|
|
|
newSize = {
|
|
|
|
width: newSize.width,
|
|
|
|
height: newSize.height + newOrigin.y - point.y,
|
|
|
|
};
|
|
|
|
newOrigin = new Point2D(newOrigin.x, point.y);
|
|
|
|
} else if (point.y > this.maxY()) {
|
|
|
|
newSize = {
|
|
|
|
width: newSize.width,
|
|
|
|
height: newSize.height + point.y - this.maxY(),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Rect(newOrigin, newSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
maxX(): number {
|
|
|
|
return this.origin.x + this.size.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
maxY(): number {
|
|
|
|
return this.origin.y + this.size.height;
|
|
|
|
}
|
2018-11-26 21:30:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface Vector3D {
|
|
|
|
x: number;
|
|
|
|
y: number;
|
|
|
|
z: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
export class Matrix2D {
|
|
|
|
a: number; b: number;
|
|
|
|
c: number; d: number;
|
|
|
|
tx: number; ty: number;
|
|
|
|
|
|
|
|
constructor(a: number, b: number, c: number, d: number, tx: number, ty: number) {
|
|
|
|
this.a = a; this.b = b;
|
|
|
|
this.c = c; this.d = d;
|
|
|
|
this.tx = tx; this.ty = ty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-03 17:08:08 -05:00
|
|
|
export function approxEq(a: number, b: number, epsilon: number | undefined): boolean {
|
|
|
|
return Math.abs(a - b) <= (epsilon == null ? EPSILON : epsilon);
|
2018-11-26 21:30:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export function lerp(a: number, b: number, t: number): number {
|
|
|
|
return a + (b - a) * t;
|
|
|
|
}
|
2018-11-30 18:42:19 -05:00
|
|
|
|
|
|
|
export function cross(a: Vector3D, b: Vector3D): Vector3D {
|
|
|
|
return {
|
|
|
|
x: a.y*b.z - a.z*b.y,
|
|
|
|
y: a.z*b.x - a.x*b.z,
|
|
|
|
z: a.x*b.y - a.y*b.x,
|
|
|
|
};
|
|
|
|
}
|