module els { export class Vector2D { _x: number; _y: number; constructor(x: number = 0, y: number = 0) { this._x = x; this._y = y; } get x() { return this._x; } get y() { return this._y; } set x(value: number) { this._x = value; } set y(value: number) { this._y = value; } get length(): number { return Math.sqrt(this._x * this._x + this._y * this._y); } set length(value: number) { var a: number = this.angle; this._x = Math.cos(a) * value; this._y = Math.sin(a) * value; } get lengthSQ() { return this._x * this._x + this._y * this._y; } get angle() { return Math.atan2(this._y, this._x); } set angle(value: number) { var len: number = this.length; this._x = Math.cos(value) * len; this._y = Math.sin(value) * len; } set rotation(value: number) { var _angle: number = value / 180 * Math.PI; this.angle = _angle; } normalize(): Vector2D { var len: number = this.length; if (!len) return this; this.x /= len; this.y /= len; return this; } //截取当前向量(多余的裁掉,少的不裁) truncate(max: number): Vector2D { this.length = Math.min(max, this.length); return this; } reverse(): Vector2D { this._x = -this._x; this._y = -this._y; return this; } isNormalized(): boolean { return this.length == 1; } //向量积,又称为点积(计算投影),如果值为负,那么,两向量所形成的角度大于90度,如果为零,那么垂直,否则角度小于90度 //通过它可以知道两个向量的相似性,利用点积可以判断一个多边形是否面向摄像机还是背向摄像机 //向量的点积与它们的夹角余弦成正比,因此,在聚光灯效果计算中,可以根据点积来得到光照效果,点积越大,夹角越小,则物理离光照的轴线越近,光照越强 dotProd(v2: Vector2D): number { return this._x * v2._x + this._y * v2._y; } //判断两个向量是否垂直 crossProd(v2: Vector2D): boolean { return this.getCross(v2) === 0; } //cross值 getCross(v2: Vector2D): number { return this._x * v2._y - this._y * v2._x; } //返回两向量夹角的角度值,两个单位向量的点积得到两个向量的夹角的cos值 static angleBetween(v1: Vector2D, v2: Vector2D): number { if (!v1.isNormalized()) v1 = v1.clone().normalize(); if (!v2.normalize()) v2 = v2.clone().normalize(); return Math.acos(v1.dotProd(v2)); } //返回法线向量(perpendicular) get perp() { return new Vector2D(-this._y, this._x); } //返回向量的符号值 sign(v2: Vector2D): number { return this.perp.dotProd(v2) < 0 ? -1 : 1; } distance(v2: Vector2D): number { return Math.sqrt(this.distanceSQ(v2)); } distanceSQ(v2: Vector2D): number { var dx: number = v2._x - this._x; var dy: number = v2._y - this._y; return dx * dx + dy * dy; } equals(v2: Vector2D): boolean { return this._x === v2._x && this._y === v2._y; } isZero(): boolean { return this._x === 0 && this._y === 0; } scale(value: number): Vector2D { this._x *= value; this._y *= value; return this; } add(x: number, y: number): Vector2D { this._x += x; this._y += y; return this; } substruct(x: number, y: number): Vector2D { this._x -= x; this._y -= y; return this; } multiply(x: number, y: number): Vector2D { this._x *= x; this._y *= y; return this; } divide(x: number, y: number): Vector2D { this._x /= x; this._y /= y; return this; } clone(): Vector2D { var v: Vector2D = new Vector2D(); v._x = this._x; v._y = this._y; return v; } toString(): string { return "(x=" + this.x + ", y=" + this.y + ")"; } } }