Last active
June 20, 2020 01:07
-
-
Save Eggbertx/349076b7a0c2f0cf11abcec7f3a5edec to your computer and use it in GitHub Desktop.
An ES6 JavaScript class for handling vector algebra in two or three dimensions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * A class for handling vector algebra in two or three dimensions | |
| * If you only need a two-dimensional vector, you can just ignore | |
| * the z property and all z parameters, since they aren't required | |
| * | |
| * See https://en.wikipedia.org/wiki/Euclidean_vector | |
| */ | |
| export class Vector { | |
| /** | |
| * Constructs a Vector object | |
| * | |
| * @param {number} x | |
| * @param {number} y | |
| * @param {number} z (optional) | |
| */ | |
| constructor(x = 0, y = 0, z = 0) { | |
| this.x = x; | |
| this.y = y; | |
| this.z = z; | |
| } | |
| /** | |
| * Use distance formula to calculate length of vector | |
| * | |
| * @return {number} (0,0) to (this.x, this.y, this.z) | |
| */ | |
| get length() { | |
| return Math.sqrt( | |
| Math.pow(this.x, 2) + | |
| Math.pow(this.y, 2) + | |
| Math.pow(this.z, 2) | |
| ); | |
| } | |
| /** | |
| * Theta (angle in radians) of vector on x,y plane | |
| */ | |
| get thetaXY() { | |
| return Math.atan2(this.y, this.x); | |
| } | |
| /** | |
| * Theta (angle in radians) of vector on y,z plane | |
| */ | |
| get thetaYZ() { | |
| return Math.atan2(this.z, this.y); | |
| } | |
| /** | |
| * Theta (angle in radians) of vector on z,x plane | |
| */ | |
| get thetaZX() { | |
| return Math.atan2(this.x, this.z); | |
| } | |
| /** | |
| * Calculate the angle between this and another vector in radians | |
| * | |
| * @param {Vector} vector the other vector | |
| * @return {number} angle in radians | |
| */ | |
| angleBetween(vector) { | |
| return Math.acos(this.dotProduct(vector) / (this.length * vector.length)); | |
| // return Math.atan2(this.y - vector.y, this.x - vector.x); | |
| } | |
| /** | |
| * Add two vectors together | |
| * | |
| * @param {Vector} vector the vector to add to this | |
| */ | |
| add(vector) { | |
| this.x += vector.x; | |
| this.y += vector.y; | |
| this.z += vector.z; | |
| } | |
| /** | |
| * Subtract two vectors | |
| * | |
| * @param {Vector} vector the vector to subtract from this | |
| */ | |
| subtract(vector) { | |
| this.x -= vector.x; | |
| this.y -= vector.y; | |
| this.z -= vector.z; | |
| } | |
| /** | |
| * Scale up by scalar | |
| * | |
| * @param {number} scalar the scalar to multiply by | |
| */ | |
| scale(by) { | |
| this.x *= by; | |
| this.y *= by; | |
| this.z *= by; | |
| } | |
| /** | |
| * Scale by individual axes | |
| * | |
| * @param {number} amount to scale the x axis by | |
| * @param {number} amount to scale the y axis by | |
| * @param {number} amount to scale the z axis by | |
| */ | |
| scaleAxes(x,y,z) { | |
| this.x *= x; | |
| this.y *= y; | |
| this.z *= z; | |
| } | |
| /** | |
| * Calculate a dot product | |
| * | |
| * See https://en.wikipedia.org/wiki/Euclidean_vector#Dot_product | |
| * @param {Vector} vector the vector to multiply by | |
| * @return {number} scalar product of two Vectors | |
| */ | |
| dotProduct(vector) { | |
| return this.x * vector.x + this.y * vector.y + this.z * vector.z; | |
| } | |
| /** | |
| * Calculates a Cross product | |
| * | |
| * see https://en.wikipedia.org/wiki/Euclidean_vector#Cross_product | |
| * @param {Vector} the vector to multiply by | |
| * @return {Vector} Vector product of two Vectors | |
| */ | |
| crossProduct(vector) { | |
| return new Vector( | |
| this.y * vector.z - this.z * vector.y, | |
| this.z * vector.x - this.x * vector.z, | |
| this.x * vector.y - this.y * vector.x | |
| ); | |
| } | |
| /** | |
| * Return a copy of this | |
| * @return {Vector} the clone | |
| */ | |
| clone() { | |
| return new Vector(this.x, this.y, this.z); | |
| } | |
| /** | |
| * Rotates the vector on a single axis | |
| * (TODO: Add ability to rotate on multiple axes) | |
| * | |
| * @param {number} angle rotate around this angle (in radians) | |
| * @param {string} axis (optional) axis to rotate around, | |
| * must be 'x', 'y' * or 'z'. Defaults to 'z' | |
| */ | |
| rotate(angle, axis = 'z') { | |
| var cosA = Math.cos(angle); | |
| var sinA = Math.sin(angle); | |
| let _x, _y, _z; | |
| switch(axis) { | |
| case 'X': | |
| case 'x': | |
| _y = this.y * cosA + this.z * sinA; | |
| _z = this.z * cosA - this.y * sinA; | |
| this.y = _y; | |
| this.z = _z; | |
| break; | |
| case 'Y': | |
| case 'y': | |
| _z = this.z * cosA + this.x * sinA; | |
| _x = this.x * cosA - this.z * sinA; | |
| this.z = _z; | |
| this.x = _x; | |
| break; | |
| default: | |
| // z, undefined, or invalid | |
| _x = this.x * cosA - this.y * sinA; | |
| _y = this.x * sinA + this.y * sinA; | |
| this.x = _x; | |
| this.y = _y; | |
| break; | |
| } | |
| // this.roundAxes(); | |
| } | |
| /** | |
| * Return a string representation of the Vector | |
| * | |
| * @override | |
| * @return {string} a human-readable string for debugging | |
| */ | |
| toString() { | |
| return `Vector(${this.x},${this.y},${this.z})`; | |
| } | |
| /** | |
| * Round the axes to three decimal places, automatically done by rotate() | |
| */ | |
| roundAxes() { | |
| this.x = Math.round(this.x * 1000) / 1000; | |
| this.y = Math.round(this.y * 1000) / 1000; | |
| this.z = Math.round(this.z * 1000) / 1000; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment