@pilotlab/lux-attributes
Version:
A luxurious user experience framework, developed by your friends at Pilot.
332 lines (242 loc) • 10.8 kB
text/typescript
import { IAttribute, AttributeChangeOptions } from '@pilotlab/lux-attributes';
import { List } from '@pilotlab/lux-collections';
import Types from './types';
import PointBase from './pointBase';
import Point from './point';
import IVector from './interfaces/iVector';
import {
AttributeChangeActions,
AttributeCreateOptions,
DataType,
IAttributeChangeOptions,
IAttributeUpdateTracker
} from '@pilotlab/lux-attributes';
import {
IAnimationEaseFunction,
ISpeed
} from '@pilotlab/lux-animation';
/**
* A Vector can represent point in 3D space, or a direction and length in 3D space.
* The length (or magnitude) will always be the Euclidean distance (straight-line distance)
* from (0, 0, 0) to (x, y, z) and the direction is also measured from (0, 0, 0) towards (x, y, z).
*/
export class Vector extends PointBase<Vector> implements IVector {
constructor(x:number = 0, y:number = 0, z:number = 0, w:number = 0, label?:string) {
super('vector', x, y, z, label);
this.p_w = this.children.get('w', new AttributeCreateOptions(w, DataType.NUMBER, null, AttributeChangeOptions.zero));
}
get w():number { return this.p_w.value; }
set w(value:number) { this.p_w.set(value, AttributeChangeOptions.save.durationZero); }
protected p_w:IAttribute;
get size():number {
return Math.sqrt(this.dot(this));
}
get magnitude():number { return this.size; }
get abs():Vector {
return new Vector(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z), Math.abs(this.w));
}
/*====================================================================*
START: Public Methods
*====================================================================*/
// out():Vector { return new Vector(this.x + this.coordinateSystem.x, this.coordinateSystem.y - this.y, this.z + this.coordinateSystem.z, this.w); }
//
//
// outFloat32Array():Float32Array {
// let ar:Float32Array = new Float32Array(this.children.list.size);
//
// for (let i:number = 0; i < this.children.list.size; i++) {
// if (i < 3) ar[i] = this.children.list.item(i).value + this.coordinateSystem.children.list.item(i).value;
// else ar[i] = this.children.list.item(i).value;
// }
//
// return ar;
// }
/**
* Get the scalar product of two Vectors
*/
dot(v:Vector):number {
let values:List<IAttribute> = this.children.list;
let valuesIn:List<IAttribute> = v.children.list;
if (values.size != values.size) throw new Error('Vectors of different dimensions.');
let erg:number = 0.0;
for (let i:number = 0; i < values.size; i++) erg += values.item(i).value * valuesIn.item(i).value;
return erg;
}
/**
* Returns the normalized version of the Vector.
*/
normalize():Vector {
let m:number = this.magnitude;
let values:List<IAttribute> = this.children.list;
if (m <= Types.tolerance) m = 1.0;
for (let i:number = 0; i < values.size; i++) {
values.item(i).value = values.item(i).value / m;
if (Math.abs(values.item(i).value) < Types.tolerance) values.item(i).value = 0.0;
}
return this;
}
multiply(v:Vector):Vector {
let values:List<IAttribute> = this.children.list;
let valuesIn:List<IAttribute> = v.children.list;
if (valuesIn.size !== values.size) return null;
for (let i:number = 0; i < values.size; i++) { values.item(i).value = values.item(i).value * valuesIn.item(i).value; }
return this;
}
divide(v:Vector):Vector {
let values:List<IAttribute> = this.children.list;
let valuesIn:List<IAttribute> = v.children.list;
if (valuesIn.size !== values.size) return null;
for (let i:number = 0; i < values.size; i++) { values.item(i).value = values.item(i).value / valuesIn.item(i).value; }
return this;
}
/*multiplyByMat3(matrix: mat3, dest: vec3 = null): vec3 {
if (!dest) dest = this;
return matrix.multiplyVec3(this, dest);
}
multiplyByQuat(quat: quat, dest: vec3 = null): vec3 {
if (!dest) dest = this;
return quat.multiplyVec3(this, dest);
}*/
go(
target:IVector,
durationSpeed?:(number | ISpeed),
ease?:IAnimationEaseFunction,
repeatCount:number = 0
):IAttributeUpdateTracker {
const options:IAttributeChangeOptions = new AttributeChangeOptions(AttributeChangeActions.SIGNAL_CHANGE, durationSpeed, ease);
options.repeatCount = repeatCount;
return this.attributes.update(target, options);
}
/*====================================================================*
START: Static Methods
*====================================================================*/
static get identity():Vector { return new Vector(0, 0); }
static fromPoint3D(pt:Point):Vector { return new Vector(pt.x, pt.y, pt.z, null); }
static get empty():Vector { return new Vector(); }
static cross(v1:Vector, v2:Vector, dest:Vector = null):Vector {
let values1:List<IAttribute> = v1.children.list;
let values2:List<IAttribute> = v2.children.list;
if (values1.size != values2.size || values1.size < 3) return new Vector();
if (!dest) dest = new Vector(0, 0, 0);
dest.x = v1.y * v2.z - v1.z * v2.y;
dest.y = v1.z * v2.x - v1.x * v2.z;
dest.z = v1.x * v2.y - v1.y * v2.x;
return dest;
}
static dot(v1:Vector, v2:Vector):number {
let values1:List<IAttribute> = v1.children.list;
let values2:List<IAttribute> = v2.children.list;
if (values1.size !== values2.size) return -1.0;
let e:number = 0.0;
let d:number = 0.0;
for (let i:number = 0; i < values1.size; i++) {
d = (values1.item(i).value * values2.item(i).value);
e += d;
}
return e;
}
static distance(v1:Vector, v2:Vector):number {
let values1:List<IAttribute> = v1.children.list;
let values2:List<IAttribute> = v2.children.list;
if (values1.size !== values2.size) return -1.0;
let e:number = 0.0;
let d:number = 0.0;
for (let i:number = 0; i < values1.size; i++) {
d = (values1.item(i).value - values2.item(i).value);
e += d * d;
}
return Math.sqrt(e);
}
static direction(v1:Vector, v2:Vector, dest:Vector = new Vector()):Vector {
let values1:List<IAttribute> = v1.children.list;
let values2:List<IAttribute> = v2.children.list;
let valuesDest:List<IAttribute> = dest.children.list;
if (values1.size !== values2.size) return new Vector();
let d:number = 0.0;
let size:number = 0.0;
for (let i:number = 0; i < values1.size; i++) {
valuesDest.item(i).value = values1.item(i).value - values2.item(i).value;
size += d * d;
}
if (size === 0) {
for (let i:number = 0; i < values1.size; i++) { valuesDest.item(i).value = 0; }
return dest;
}
size = 1 / size;
for (let i:number = 0; i < values1.size; i++) {
valuesDest.item(i).value = valuesDest.item(i).value * size;
}
return dest;
}
static mix(v1:Vector, v2:Vector, time:number, dest:Vector = new Vector()):Vector {
let values1:List<IAttribute> = v1.children.list;
let values2:List<IAttribute> = v2.children.list;
let valuesDest:List<IAttribute> = dest.children.list;
if (values1.size !== values2.size) return new Vector();
for (let i:number = 0; i < values1.size; i++) {
valuesDest.item(i).value = values1.item(i).value + time * (values2.item(i).value - values1.item(i).value);
}
return dest;
}
static sum(v1:Vector, v2:Vector, dest:Vector = new Vector()):Vector {
let values1:List<IAttribute> = v1.children.list;
let values2:List<IAttribute> = v2.children.list;
let valuesDest:List<IAttribute> = dest.children.list;
if (values1.size !== values2.size) return new Vector();
for (let i:number = 0; i < values1.size; i++) {
valuesDest.item(i).value = values1.item(i).value + values2.item(i).value;
}
return dest;
}
static difference(v1:Vector, v2:Vector, dest:Vector = new Vector()):Vector {
let values1:List<IAttribute> = v1.children.list;
let values2:List<IAttribute> = v2.children.list;
let valuesDest:List<IAttribute> = dest.children.list;
if (values1.size !== values2.size) return new Vector();
for (let i:number = 0; i < values1.size; i++) {
valuesDest.item(i).value = values1.item(i).value - values2.item(i).value;
}
return dest;
}
static product(v1:Vector, v2:Vector, dest:Vector = new Vector()):Vector {
let values1:List<IAttribute> = v1.children.list;
let values2:List<IAttribute> = v2.children.list;
let valuesDest:List<IAttribute> = dest.children.list;
if (values1.size !== values2.size) return new Vector();
for (let i:number = 0; i < values1.size; i++) {
valuesDest.item(i).value = values1.item(i).value * values2.item(i).value;
}
return dest;
}
static quotient(v1:Vector, v2:Vector, dest:Vector = new Vector()):Vector {
let values1:List<IAttribute> = v1.children.list;
let values2:List<IAttribute> = v2.children.list;
let valuesDest:List<IAttribute> = dest.children.list;
if (values1.size !== values2.size) return new Vector();
for (let i:number = 0; i < values1.size; i++) {
valuesDest.item(i).value = values1.item(i).value / values2.item(i).value;
}
return dest;
}
/*toQuat(dest: quat = null): quat {
if (!dest) dest = new quat();
let c = new vec3();
let s = new vec3();
c.x = Math.cos(this.x * 0.5);
s.x = Math.sin(this.x * 0.5);
c.y = Math.cos(this.y * 0.5);
s.y = Math.sin(this.y * 0.5);
c.z = Math.cos(this.z * 0.5);
s.z = Math.sin(this.z * 0.5);
dest.x = s.x * c.y * c.z - c.x * s.y * s.z;
dest.y = c.x * s.y * c.z + s.x * c.y * s.z;
dest.z = c.x * c.y * s.z - s.x * s.y * c.z;
dest.w = c.x * c.y * c.z + s.x * s.y * s.z;
return dest;
}*/
static zero = new Vector(0, 0, 0);
static up = new Vector(0, 1, 0);
static right = new Vector(1, 0, 0);
static forward = new Vector(0, 0, 1);
} // End class
export default Vector;