import {frac} from "../math";
import {Vec3} from "./Vec3";
export type NumberArray4 = [number, number, number, number];
/**
* Class represents a 4d vector.
* @class
* @param {number} [x] - First value.
* @param {number} [y] - Second value.
* @param {number} [z] - Third value.
* @param {number} [w] - Fourth value.
*/
export class Vec4 {
/**
* @public
* @type {number}
*/
public x: number;
/**
* @public
* @type {number}
*/
public y: number;
/**
* @public
* @type {number}
*/
public z: number;
/**
* @public
* @type {number}
*/
public w: number;
constructor(x: number = 0.0, y: number = 0.0, z: number = 0.0, w: number = 0.0) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
/**
* Identity vector [0,0,0,1].
* @const
* @type {Vec4}
*/
static get identity(): Vec4 {
return new Vec4(0, 0, 0, 1);
}
/**
* Creates 4d vector from array.
* @function
* @param {Array.<number>} arr - Array of four values
* @returns {Vec4}
*/
static fromVec(arr: NumberArray4): Vec4 {
return new Vec4(arr[0], arr[1], arr[2], arr[3]);
}
/**
* Converts to Vec3, without fourth value.
* @public
* @returns {Vec3}
*/
public toVec3(): Vec3 {
return new Vec3(this.x, this.y, this.z);
}
/**
* Returns clone vector.
* @public
* @returns {Vec4}
*/
public clone(): Vec4 {
return new Vec4(this.x, this.y, this.z, this.w);
}
/**
* Compares with vector. Returns true if it equals another.
* @public
* @param {Vec4} v - Vector to compare.
* @returns {boolean}
*/
public equal(v: Vec4): boolean {
return this.x === v.x && this.y === v.y && this.z === v.z && this.w === v.w;
}
/**
* Copy input vector's values.
* @param {Vec4} v - Vector to copy.
* @returns {Vec4}
*/
public copy(v: Vec4): Vec4 {
this.x = v.x;
this.y = v.y;
this.z = v.z;
this.w = v.w;
return this;
}
/**
* Converts vector to a number array.
* @public
* @returns {Array.<number>} - (exactly 4 entries)
*/
public toArray(): NumberArray4 {
return [this.x, this.y, this.z, this.w];
}
/**
* Converts vector to a number array.
* @public
* @returns {Array.<number>} - (exactly 4 entries)
*/
toArray3(): [number, number, number] {
return [this.x, this.y, this.z];
}
/**
* Sets vector's values.
* @public
* @param {number} x - Value X.
* @param {number} y - Value Y.
* @param {number} z - Value Z.
* @param {number} w - Value W.
* @returns {Vec4}
*/
public set(x: number, y: number, z: number, w: number): Vec4 {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return this;
}
/**
* Adds vector to the current.
* @public
* @param {Vec4} v - Vector to add.
* @returns {Vec4}
*/
public addA(v: Vec4): Vec4 {
this.x += v.x;
this.y += v.y;
this.z += v.z;
this.w += v.w;
return this;
}
/**
* Subtract vector from the current.
* @public
* @param {Vec4} v - Subtract vector.
* @returns {Vec4}
*/
public subA(v: Vec4): Vec4 {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
this.w -= v.w;
return this;
}
/**
* Scale current vector.
* @public
* @param {number} scale - Scale value.
* @returns {Vec4}
*/
public scale(scale: number): Vec4 {
this.x *= scale;
this.y *= scale;
this.z *= scale;
this.w *= scale;
return this;
}
/**
* Makes vector affinity. Thereby fourth component becomes to 1.0.
* @public
* @returns {Vec4}
*/
public affinity(): Vec4 {
let iw = 1.0 / this.w;
this.x *= iw;
this.y *= iw;
this.z *= iw;
this.w = 1.0;
return this;
}
/**
* Scale current vector to another instance.
* @public
* @param {number} scale - Scale value.
* @returns {Vec3}
*/
public scaleTo(scale: number): Vec4 {
return new Vec4(this.x * scale, this.y * scale, this.z * scale, this.w * scale);
}
/**
* Vector's edge function that returns vector where each component is 0.0 if it's smaller than edge and otherwise 1.0.
* @public
* @returns {Vec4}
*/
public getStep(edge: number): Vec4 {
return new Vec4(
this.x < edge ? 0.0 : 1.0,
this.y < edge ? 0.0 : 1.0,
this.z < edge ? 0.0 : 1.0,
this.w < edge ? 0.0 : 1.0
);
}
/**
* The vector frac function returns the vector of fractional parts of each value, i.e. x minus floor(x).
* @public
* @param {Vec4} v - Input vector
* @returns {Vec4}
*/
public getFrac(v: Vec4): Vec4 {
return new Vec4(frac(v.x), frac(v.y), frac(v.z), frac(v.w));
}
/**
* Gets vectors dot production.
* @public
* @param {Vec4} v - Another vector.
* @returns {number} - Dot product.
*/
public dot(v: Vec4): number {
return v.x * this.x + v.y * this.y + v.z * this.z + v.w * this.w;
}
/**
* Returns true if vector's values are zero.
* @public
* @returns {boolean} -
*/
public isZero(): boolean {
return !(this.x || this.y || this.z || this.w);
}
}
/**
* Vector 4d object creator.
* @function
* @param {number} [x] - First value.
* @param {number} [y] - Second value.
* @param {number} [z] - Third value.
* @param {number} [w] - Fourth value.
* @returns {Vec4}
*/
export function vec4(x: number = 0, y: number = 0, z: number = 0, w: number = 0): Vec4 {
return new Vec4(x, y, z, w);
}