cut-demo/src/Nest/Common/Vector2.ts

288 lines
7.2 KiB
TypeScript
Raw Normal View History

2020-04-27 16:39:48 +08:00
import { Point } from "./Point";
export class Vector2
{
x: number;
y: number;
readonly isVector2: boolean = true;
constructor(x: number = 0, y: number = 0)
{
this.x = x;
this.y = y;
}
get width(): number { return this.x; }
set width(value: number) { this.x = value; }
get height(): number { return this.y; }
set height(value: number) { this.y = value; }
set(x: number, y: number): Vector2
{
this.x = x;
this.y = y;
return this;
}
setScalar(scalar: number): Vector2
{
this.x = scalar;
this.y = scalar;
return this;
}
setX(x: number): Vector2
{
this.x = x;
return this;
}
setY(y: number): Vector2
{
this.y = y;
return this;
}
setComponent(index: number, value: number): Vector2
{
switch (index)
{
case 0: this.x = value; break;
case 1: this.y = value; break;
default: throw new Error('index is out of range: ' + index);
}
return this;
}
getComponent(index: number): number
{
switch (index)
{
case 0: return this.x;
case 1: return this.y;
default: throw new Error('index is out of range: ' + index);
}
}
clone(): Vector2
{
return new (this.constructor as any)().copy(this);
}
copy(v: Vector2): Vector2
{
this.x = v.x;
this.y = v.y;
return this;
}
add(v: Point): Vector2
{
this.x += v.x;
this.y += v.y;
return this;
}
addScalar(s: number): Vector2
{
this.x += s;
this.y += s;
return this;
}
addVectors(a: Vector2, b: Vector2): Vector2
{
this.x = a.x + b.x;
this.y = a.y + b.y;
return this;
}
addScaledVector(v: Vector2, s: number): Vector2
{
this.x += v.x * s;
this.y += v.y * s;
return this;
}
sub(v: Vector2): Vector2
{
this.x -= v.x;
this.y -= v.y;
return this;
}
subScalar(s: number): Vector2
{
this.x -= s;
this.y -= s;
return this;
}
subVectors(a: Vector2, b: Vector2): Vector2
{
this.x = a.x - b.x;
this.y = a.y - b.y;
return this;
}
multiply(v: Vector2): Vector2
{
this.x *= v.x;
this.y *= v.y;
return this;
}
multiplyScalar(scalar: number): Vector2
{
if (isFinite(scalar))
{
this.x *= scalar;
this.y *= scalar;
} else
{
this.x = 0;
this.y = 0;
}
return this;
}
divide(v: Vector2): Vector2
{
this.x /= v.x;
this.y /= v.y;
return this;
}
divideScalar(scalar: number): Vector2
{
return this.multiplyScalar(1 / scalar);
}
min(v: Vector2): Vector2
{
this.x = Math.min(this.x, v.x);
this.y = Math.min(this.y, v.y);
return this;
}
max(v: Vector2): Vector2
{
this.x = Math.max(this.x, v.x);
this.y = Math.max(this.y, v.y);
return this;
}
clamp(min: Vector2, max: Vector2): Vector2
{
// This function assumes min < max, if this assumption isn't true it will not operate correctly
this.x = Math.max(min.x, Math.min(max.x, this.x));
this.y = Math.max(min.y, Math.min(max.y, this.y));
return this;
}
private static clampScalar_min = new Vector2();
private static clampScalar_max = new Vector2();
clampScalar(minVal: number, maxVal: number): Vector2
{
const min: Vector2 = Vector2.clampScalar_min.set(minVal, minVal);
const max: Vector2 = Vector2.clampScalar_max.set(maxVal, maxVal);
return this.clamp(min, max);
}
clampLength(min: number, max: number): Vector2
{
const length: number = this.length();
return this.multiplyScalar(Math.max(min, Math.min(max, length)) / length);
}
floor(): Vector2
{
this.x = Math.floor(this.x);
this.y = Math.floor(this.y);
return this;
}
ceil(): Vector2
{
this.x = Math.ceil(this.x);
this.y = Math.ceil(this.y);
return this;
}
round(): Vector2
{
this.x = Math.round(this.x);
this.y = Math.round(this.y);
return this;
}
roundToZero(): Vector2
{
this.x = (this.x < 0) ? Math.ceil(this.x) : Math.floor(this.x);
this.y = (this.y < 0) ? Math.ceil(this.y) : Math.floor(this.y);
return this;
}
negate(): Vector2
{
this.x = - this.x;
this.y = - this.y;
return this;
}
dot(v: Vector2): number
{
return this.x * v.x + this.y * v.y;
}
lengthSq(): number
{
return this.x * this.x + this.y * this.y;
}
length(): number
{
return Math.sqrt(this.x * this.x + this.y * this.y);
}
lengthManhattan(): number
{
return Math.abs(this.x) + Math.abs(this.y);
}
normalize(): Vector2
{
return this.divideScalar(this.length());
}
angle(): number
{
// computes the angle in radians with respect to the positive x-axis
let angle: number = Math.atan2(this.y, this.x);
if (angle < 0) angle += 2 * Math.PI;
return angle;
}
distanceTo(v: Vector2): number
{
return Math.sqrt(this.distanceToSquared(v));
}
distanceToSquared(v: Vector2): number
{
const dx: number = this.x - v.x, dy: number = this.y - v.y;
return dx * dx + dy * dy;
}
distanceToManhattan(v: Vector2): number
{
return Math.abs(this.x - v.x) + Math.abs(this.y - v.y);
}
setLength(length: number): Vector2
{
return this.multiplyScalar(length / this.length());
}
lerp(v: Vector2, alpha: number): Vector2
{
this.x += (v.x - this.x) * alpha;
this.y += (v.y - this.y) * alpha;
return this;
}
lerpVectors(v1: Vector2, v2: Vector2, alpha: number): Vector2
{
return this.subVectors(v2, v1).multiplyScalar(alpha).add(v1);
}
equals(v: Vector2): boolean
{
return ((v.x === this.x) && (v.y === this.y));
}
fromArray(array: Float32Array | number[], offset: number = 0): Vector2
{
this.x = array[offset];
this.y = array[offset + 1];
return this;
}
toArray(array: Float32Array | number[] = [], offset: number = 0): Float32Array | number[]
{
array[offset] = this.x;
array[offset + 1] = this.y;
return array;
}
fromAttribute(attribute: any, index: number, offset: number = 0): Vector2
{
index = index * attribute.itemSize + offset;
this.x = attribute.array[index];
this.y = attribute.array[index + 1];
return this;
}
rotateAround(center: Vector2, angle: number): Vector2
{
const c: number = Math.cos(angle), s: number = Math.sin(angle);
const x: number = this.x - center.x;
const y: number = this.y - center.y;
this.x = x * c - y * s + center.x;
this.y = x * s + y * c + center.y;
return this;
}
}