p5
Version:
[](https://www.npmjs.com/package/p5)
1,816 lines (1,781 loc) • 107 kB
JavaScript
import { f as TWO_PI } from '../constants-BRcElHU3.js';
/**
* @module Math
* @requires constants
*/
/// HELPERS FOR REMAINDER METHOD
const calculateRemainder2D = function (xComponent, yComponent) {
if (xComponent !== 0) {
this.x = this.x % xComponent;
}
if (yComponent !== 0) {
this.y = this.y % yComponent;
}
return this;
};
const calculateRemainder3D = function (xComponent, yComponent, zComponent) {
if (xComponent !== 0) {
this.x = this.x % xComponent;
}
if (yComponent !== 0) {
this.y = this.y % yComponent;
}
if (zComponent !== 0) {
this.z = this.z % zComponent;
}
return this;
};
class Vector {
// This is how it comes in with createVector()
// This check if the first argument is a function
constructor(...args) {
let values = args.map((arg) => arg || 0);
if (typeof args[0] === "function") {
this.isPInst = true;
this._fromRadians = args[0];
this._toRadians = args[1];
values = args.slice(2).map((arg) => arg || 0);
}
let dimensions = values.length; // TODO: make default 3 if no arguments
if (dimensions === 0) {
this.dimensions = 2;
this._values = [0, 0, 0];
} else {
this.dimensions = dimensions;
this._values = values;
}
}
/**
* Gets the values of the N-dimensional vector.
*
* This method returns an array of numbers that represent the vector.
* Each number in the array corresponds to a different component of the vector,
* like its position in different directions (e.g., x, y, z).
*
* @returns {Array<number>} The array of values representing the vector.
*/
get values() {
return this._values;
}
/**
* Sets the values of the vector.
*
* This method allows you to update the entire vector with a new set of values.
* You need to provide an array of numbers, where each number represents a component
* of the vector (e.g., x, y, z). The length of the array should match the number of
* dimensions of the vector. If the array is shorter, the missing components will be
* set to 0. If the array is longer, the extra values will be ignored.
*
* @param {Array<number>} newValues - An array of numbers representing the new values for the vector.
*
*/
set values(newValues) {
let dimensions = newValues.length;
if (dimensions === 0) {
this.dimensions = 2;
this._values = [0, 0, 0];
} else {
this.dimensions = dimensions;
this._values = newValues.slice();
}
}
/**
* Gets the x component of the vector.
*
* This method returns the value of the x component of the vector.
* Think of the x component as the horizontal position or the first number in the vector.
* If the x component is not defined, it will return 0.
*
* @returns {Number} The x component of the vector. Returns 0 if the value is not defined.
*/
get x() {
return this._values[0] || 0;
}
/**
* Retrieves the value at the specified index from the vector.
*
* This method allows you to get the value of a specific component of the vector
* by providing its index. Think of the vector as a list of numbers, where each
* number represents a different direction (like x, y, or z). The index is just
* the position of the number in that list.
*
* For example, if you have a vector with values 10, 20, 30 the index 0 would
* give you the first value 10, index 1 would give you the second value 20,
* and so on.
*
* @param {Number} index - The position of the value you want to get from the vector.
* @returns {Number} The value at the specified position in the vector.
* @throws Will throw an error if the index is out of bounds, meaning if you try to
* get a value from a position that doesn't exist in the vector.
*/
getValue(index) {
if (index < this._values.length) {
return this._values[index];
} else {
p5._friendlyError(
"The index parameter is trying to set a value outside the bounds of the vector",
"p5.Vector.setValue"
);
}
}
/**
* Sets the value at the specified index of the vector.
*
* This method allows you to change a specific component of the vector by providing its index and the new value you want to set.
* Think of the vector as a list of numbers, where each number represents a different direction (like x, y, or z).
* The index is just the position of the number in that list.
*
* For example, if you have a vector with values [0, 20, 30], and you want to change the second value (20) to 50,
* you would use this method with index 1 (since indexes start at 0) and value 50.
*
* @param {Number} index - The position in the vector where you want to set the new value.
* @param {Number} value - The new value you want to set at the specified position.
* @throws Will throw an error if the index is outside the bounds of the vector, meaning if you try to set a value at a position that doesn't exist in the vector.
*/
setValue(index, value) {
if (index < this._values.length) {
this._values[index] = value;
} else {
p5._friendlyError(
"The index parameter is trying to set a value outside the bounds of the vector",
"p5.Vector.setValue"
);
}
}
/**
* Gets the y component of the vector.
*
* This method returns the value of the y component of the vector.
* Think of the y component as the vertical position or the second number in the vector.
* If the y component is not defined, it will return 0.
*
* @returns {Number} The y component of the vector. Returns 0 if the value is not defined.
*/
get y() {
return this._values[1] || 0;
}
/**
* Gets the z component of the vector.
*
* This method returns the value of the z component of the vector.
* Think of the z component as the depth or the third number in the vector.
* If the z component is not defined, it will return 0.
*
* @returns {Number} The z component of the vector. Returns 0 if the value is not defined.
*/
get z() {
return this._values[2] || 0;
}
/**
* Gets the w component of the vector.
*
* This method returns the value of the w component of the vector.
* Think of the w component as the fourth number in the vector.
* If the w component is not defined, it will return 0.
*
* @returns {Number} The w component of the vector. Returns 0 if the value is not defined.
*/
get w() {
return this._values[3] || 0;
}
/**
* Sets the x component of the vector.
*
* This method allows you to change the x value of the vector.
* The x value is the first number in the vector, representing the horizontal position.
* By calling this method, you can update the x value to a new number.
*
* @param {Number} xVal - The new value for the x component.
*/
set x(xVal) {
if (this._values.length > 1) {
this._values[0] = xVal;
}
}
/**
* Sets the y component of the vector.
*
* This method allows you to change the y value of the vector.
* The y value is the second number in the vector, representing the vertical position.
* By calling this method, you can update the y value to a new number.
*
* @param {Number} yVal - The new value for the y component.
*/
set y(yVal) {
if (this._values.length > 1) {
this._values[1] = yVal;
}
}
/**
* Sets the z component of the vector.
*
* This method allows you to change the z value of the vector.
* The z value is the third number in the vector, representing the depth or the third dimension.
* By calling this method, you can update the z value to a new number.
*
* @param {Number} zVal - The new value for the z component.
*/
set z(zVal) {
if (this._values.length > 2) {
this._values[2] = zVal;
}
}
/**
* Sets the w component of the vector.
*
* This method allows you to change the w value of the vector.
* The w value is the fourth number in the vector, representing the fourth dimension.
* By calling this method, you can update the w value to a new number.
*
* @param {Number} wVal - The new value for the w component.
*/
set w(wVal) {
if (this._values.length > 3) {
this._values[3] = wVal;
}
}
/**
* Returns a string representation of a vector.
*
* Calling `toString()` is useful for printing vectors to the console while
* debugging.
*
* @return {String} string representation of the vector.
*
* @example
* <div class = "norender">
* <code>
* function setup() {
* let v = createVector(20, 30);
*
* // Prints 'p5.Vector Object : [20, 30, 0]'.
* print(v.toString());
* }
* </code>
* </div>
*/
toString() {
return `[${this.values.join(", ")}]`;
}
/**
* Sets the vector's `x`, `y`, and `z` components.
*
* `set()` can use separate numbers, as in `v.set(1, 2, 3)`, a
* <a href="#/p5.Vector">p5.Vector</a> object, as in `v.set(v2)`, or an
* array of numbers, as in `v.set([1, 2, 3])`.
*
* If a value isn't provided for a component, it will be set to 0. For
* example, `v.set(4, 5)` sets `v.x` to 4, `v.y` to 5, and `v.z` to 0.
* Calling `set()` with no arguments, as in `v.set()`, sets all the vector's
* components to 0.
*
* @param {Number} [x] x component of the vector.
* @param {Number} [y] y component of the vector.
* @param {Number} [z] z component of the vector.
* @chainable
* @example
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Top left.
* let pos = createVector(25, 25);
* point(pos);
*
* // Top right.
* // set() with numbers.
* pos.set(75, 25);
* point(pos);
*
* // Bottom right.
* // set() with a p5.Vector.
* let p2 = createVector(75, 75);
* pos.set(p2);
* point(pos);
*
* // Bottom left.
* // set() with an array.
* let arr = [25, 75];
* pos.set(arr);
* point(pos);
*
* describe('Four black dots arranged in a square on a gray background.');
* }
* </code>
* </div>
*/
/**
* @param {p5.Vector|Number[]} value vector to set.
* @chainable
*/
set(...args) {
if (args[0] instanceof Vector) {
this.values = args[0].values.slice();
} else if (Array.isArray(args[0])) {
this.values = args[0].map((arg) => arg || 0);
} else {
this.values = args.map((arg) => arg || 0);
}
this.dimensions = this.values.length;
return this;
}
/**
* Returns a copy of the <a href="#/p5.Vector">p5.Vector</a> object.
*
* @return {p5.Vector} copy of the <a href="#/p5.Vector">p5.Vector</a> object.
*
* @example
* <div>
* <code>
* function setup() {
* createCanvas(100 ,100);
*
* background(200);
*
* // Create a p5.Vector object.
* let pos = createVector(50, 50);
*
* // Make a copy.
* let pc = pos.copy();
*
* // Draw the point.
* strokeWeight(5);
* point(pc);
*
* describe('A black point drawn in the middle of a gray square.');
* }
* </code>
* </div>
*/
copy() {
if (this.isPInst) {
return new Vector(this._fromRadians, this._toRadians, ...this.values);
} else {
return new Vector(...this.values);
}
}
/**
* Adds to a vector's components.
*
* `add()` can use separate numbers, as in `v.add(1, 2, 3)`,
* another <a href="#/p5.Vector">p5.Vector</a> object, as in `v.add(v2)`, or
* an array of numbers, as in `v.add([1, 2, 3])`.
*
* If a value isn't provided for a component, it won't change. For
* example, `v.add(4, 5)` adds 4 to `v.x`, 5 to `v.y`, and 0 to `v.z`.
* Calling `add()` with no arguments, as in `v.add()`, has no effect.
*
* This method supports N-dimensional vectors.
*
* The static version of `add()`, as in `p5.Vector.add(v2, v1)`, returns a new
* <a href="#/p5.Vector">p5.Vector</a> object and doesn't change the
* originals.
*
* @param {Number|Array} x x component of the vector to be added or an array of components.
* @param {Number} [y] y component of the vector to be added.
* @param {Number} [z] z component of the vector to be added.
* @chainable
*
* @example
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Top left.
* let pos = createVector(25, 25);
* point(pos);
*
* // Top right.
* // Add numbers.
* pos.add(50, 0);
* point(pos);
*
* // Bottom right.
* // Add a p5.Vector.
* let p2 = createVector(0, 50);
* pos.add(p2);
* point(pos);
*
* // Bottom left.
* // Add an array.
* let arr = [-50, 0];
* pos.add(arr);
* point(pos);
*
* describe('Four black dots arranged in a square on a gray background.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Top left.
* let p1 = createVector(25, 25);
*
* // Center.
* let p2 = createVector(50, 50);
*
* // Bottom right.
* // Add p1 and p2.
* let p3 = p5.Vector.add(p1, p2);
*
* // Draw the points.
* strokeWeight(5);
* point(p1);
* point(p2);
* point(p3);
*
* describe('Three black dots in a diagonal line from top left to bottom right.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* describe('Three arrows drawn on a gray square. A red arrow extends from the top left corner to the center. A blue arrow extends from the tip of the red arrow. A purple arrow extends from the origin to the tip of the blue arrow.');
* }
*
* function draw() {
* background(200);
*
* let origin = createVector(0, 0);
*
* // Draw the red arrow.
* let v1 = createVector(50, 50);
* drawArrow(origin, v1, 'red');
*
* // Draw the blue arrow.
* let v2 = createVector(-30, 20);
* drawArrow(v1, v2, 'blue');
*
* // Purple arrow.
* let v3 = p5.Vector.add(v1, v2);
* drawArrow(origin, v3, 'purple');
* }
*
* // Draws an arrow between two vectors.
* function drawArrow(base, vec, myColor) {
* push();
* stroke(myColor);
* strokeWeight(3);
* fill(myColor);
* translate(base.x, base.y);
* line(0, 0, vec.x, vec.y);
* rotate(vec.heading());
* let arrowSize = 7;
* translate(vec.mag() - arrowSize, 0);
* triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
* pop();
* }
* </code>
* </div>
*/
/**
* @param {p5.Vector|Number[]} value The vector to add
* @chainable
*/
add(...args) {
if (args[0] instanceof Vector) {
args = args[0].values;
} else if (Array.isArray(args[0])) {
args = args[0];
}
args.forEach((value, index) => {
this.values[index] = (this.values[index] || 0) + (value || 0);
});
return this;
}
/**
* Performs modulo (remainder) division with a vector's `x`, `y`, and `z`
* components.
*
* `rem()` can use separate numbers, as in `v.rem(1, 2, 3)`,
* another <a href="#/p5.Vector">p5.Vector</a> object, as in `v.rem(v2)`, or
* an array of numbers, as in `v.rem([1, 2, 3])`.
*
* If only one value is provided, as in `v.rem(2)`, then all the components
* will be set to their values modulo 2. If two values are provided, as in
* `v.rem(2, 3)`, then `v.z` won't change. Calling `rem()` with no
* arguments, as in `v.rem()`, has no effect.
*
* The static version of `rem()`, as in `p5.Vector.rem(v2, v1)`, returns a
* new <a href="#/p5.Vector">p5.Vector</a> object and doesn't change the
* originals.
*
* @param {Number} x x component of divisor vector.
* @param {Number} y y component of divisor vector.
* @param {Number} z z component of divisor vector.
* @chainable
*
* @example
* <div class='norender'>
* <code>
* function setup() {
* // Create a p5.Vector object.
* let v = createVector(3, 4, 5);
*
* // Divide numbers.
* v.rem(2);
*
* // Prints 'p5.Vector Object : [1, 0, 1]'.
* print(v.toString());
* }
* </code>
* </div>
*
* <div class='norender'>
* <code>
* function setup() {
* // Create a p5.Vector object.
* let v = createVector(3, 4, 5);
*
* // Divide numbers.
* v.rem(2, 3);
*
* // Prints 'p5.Vector Object : [1, 1, 5]'.
* print(v.toString());
* }
* </code>
* </div>
*
* <div class='norender'>
* <code>
* function setup() {
* // Create a p5.Vector object.
* let v = createVector(3, 4, 5);
*
* // Divide numbers.
* v.rem(2, 3, 4);
*
* // Prints 'p5.Vector Object : [1, 1, 1]'.
* print(v.toString());
* }
* </code>
* </div>
*
* <div class='norender'>
* <code>
* function setup() {
* // Create p5.Vector objects.
* let v1 = createVector(3, 4, 5);
* let v2 = createVector(2, 3, 4);
*
* // Divide a p5.Vector.
* v1.rem(v2);
*
* // Prints 'p5.Vector Object : [1, 1, 1]'.
* print(v1.toString());
* }
* </code>
* </div>
*
* <div class='norender'>
* <code>
* function setup() {
* // Create a p5.Vector object.
* let v = createVector(3, 4, 5);
*
* // Divide an array.
* let arr = [2, 3, 4];
* v.rem(arr);
*
* // Prints 'p5.Vector Object : [1, 1, 1]'.
* print(v.toString());
* }
* </code>
* </div>
*
* <div class="norender">
* <code>
* function setup() {
* // Create p5.Vector objects.
* let v1 = createVector(3, 4, 5);
* let v2 = createVector(2, 3, 4);
*
* // Divide without modifying the original vectors.
* let v3 = p5.Vector.rem(v1, v2);
*
* // Prints 'p5.Vector Object : [1, 1, 1]'.
* print(v3.toString());
* }
* </code>
* </div>
*/
/**
* @param {p5.Vector | Number[]} value divisor vector.
* @chainable
*/
rem(x, y, z) {
if (x instanceof Vector) {
if ([x.x, x.y, x.z].every(Number.isFinite)) {
const xComponent = parseFloat(x.x);
const yComponent = parseFloat(x.y);
const zComponent = parseFloat(x.z);
return calculateRemainder3D.call(
this,
xComponent,
yComponent,
zComponent
);
}
} else if (Array.isArray(x)) {
if (x.every((element) => Number.isFinite(element))) {
if (x.length === 2) {
return calculateRemainder2D.call(this, x[0], x[1]);
}
if (x.length === 3) {
return calculateRemainder3D.call(this, x[0], x[1], x[2]);
}
}
} else if (arguments.length === 1) {
if (Number.isFinite(arguments[0]) && arguments[0] !== 0) {
this.x = this.x % arguments[0];
this.y = this.y % arguments[0];
this.z = this.z % arguments[0];
return this;
}
} else if (arguments.length === 2) {
const vectorComponents = [...arguments];
if (vectorComponents.every((element) => Number.isFinite(element))) {
if (vectorComponents.length === 2) {
return calculateRemainder2D.call(
this,
vectorComponents[0],
vectorComponents[1]
);
}
}
} else if (arguments.length === 3) {
const vectorComponents = [...arguments];
if (vectorComponents.every((element) => Number.isFinite(element))) {
if (vectorComponents.length === 3) {
return calculateRemainder3D.call(
this,
vectorComponents[0],
vectorComponents[1],
vectorComponents[2]
);
}
}
}
}
/**
* Subtracts from a vector's `x`, `y`, and `z` components.
*
* `sub()` can use separate numbers, as in `v.sub(1, 2, 3)`, another
* <a href="#/p5.Vector">p5.Vector</a> object, as in `v.sub(v2)`, or an array
* of numbers, as in `v.sub([1, 2, 3])`.
*
* If a value isn't provided for a component, it won't change. For
* example, `v.sub(4, 5)` subtracts 4 from `v.x`, 5 from `v.y`, and 0 from `v.z`.
* Calling `sub()` with no arguments, as in `v.sub()`, has no effect.
*
* The static version of `sub()`, as in `p5.Vector.sub(v2, v1)`, returns a new
* <a href="#/p5.Vector">p5.Vector</a> object and doesn't change the
* originals.
*
* @param {Number} x x component of the vector to subtract.
* @param {Number} [y] y component of the vector to subtract.
* @param {Number} [z] z component of the vector to subtract.
* @chainable
*
* @example
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Bottom right.
* let pos = createVector(75, 75);
* point(pos);
*
* // Top right.
* // Subtract numbers.
* pos.sub(0, 50);
* point(pos);
*
* // Top left.
* // Subtract a p5.Vector.
* let p2 = createVector(50, 0);
* pos.sub(p2);
* point(pos);
*
* // Bottom left.
* // Subtract an array.
* let arr = [0, -50];
* pos.sub(arr);
* point(pos);
*
* describe('Four black dots arranged in a square on a gray background.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Create p5.Vector objects.
* let p1 = createVector(75, 75);
* let p2 = createVector(50, 50);
*
* // Subtract with modifying the original vectors.
* let p3 = p5.Vector.sub(p1, p2);
*
* // Draw the points.
* strokeWeight(5);
* point(p1);
* point(p2);
* point(p3);
*
* describe('Three black dots in a diagonal line from top left to bottom right.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* describe('Three arrows drawn on a gray square. A red and a blue arrow extend from the top left. A purple arrow extends from the tip of the red arrow to the tip of the blue arrow.');
* }
*
* function draw() {
* background(200);
*
* let origin = createVector(0, 0);
*
* // Draw the red arrow.
* let v1 = createVector(50, 50);
* drawArrow(origin, v1, 'red');
*
* // Draw the blue arrow.
* let v2 = createVector(20, 70);
* drawArrow(origin, v2, 'blue');
*
* // Purple arrow.
* let v3 = p5.Vector.sub(v2, v1);
* drawArrow(v1, v3, 'purple');
* }
*
* // Draws an arrow between two vectors.
* function drawArrow(base, vec, myColor) {
* push();
* stroke(myColor);
* strokeWeight(3);
* fill(myColor);
* translate(base.x, base.y);
* line(0, 0, vec.x, vec.y);
* rotate(vec.heading());
* let arrowSize = 7;
* translate(vec.mag() - arrowSize, 0);
* triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
* pop();
* }
* </code>
* </div>
*/
/**
* @param {p5.Vector|Number[]} value the vector to subtract
* @chainable
*/
sub(...args) {
if (args[0] instanceof Vector) {
args[0].values.forEach((value, index) => {
this.values[index] -= value || 0;
});
} else if (Array.isArray(args[0])) {
args[0].forEach((value, index) => {
this.values[index] -= value || 0;
});
} else {
args.forEach((value, index) => {
this.values[index] -= value || 0;
});
}
return this;
}
/**
* Multiplies a vector's `x`, `y`, and `z` components.
*
* `mult()` can use separate numbers, as in `v.mult(1, 2, 3)`, another
* <a href="#/p5.Vector">p5.Vector</a> object, as in `v.mult(v2)`, or an array
* of numbers, as in `v.mult([1, 2, 3])`.
*
* If only one value is provided, as in `v.mult(2)`, then all the components
* will be multiplied by 2. If a value isn't provided for a component, it
* won't change. For example, `v.mult(4, 5)` multiplies `v.x` by, `v.y` by 5,
* and `v.z` by 1. Calling `mult()` with no arguments, as in `v.mult()`, has
* no effect.
*
* The static version of `mult()`, as in `p5.Vector.mult(v, 2)`, returns a new
* <a href="#/p5.Vector">p5.Vector</a> object and doesn't change the
* originals.
*
* @method mult
* @param {Number} n The number to multiply with the vector
* @chainable
* @example
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Top-left.
* let p = createVector(25, 25);
* point(p);
*
* // Center.
* // Multiply all components by 2.
* p.mult(2);
* point(p);
*
* describe('Two black dots drawn on a gray square. One dot is in the top left corner and the other is in the center.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* strokeWeight(5);
*
* // Top-left.
* let p = createVector(25, 25);
* point(p);
*
* // Bottom-right.
* // Multiply p.x * 2 and p.y * 3
* p.mult(2, 3);
* point(p);
*
* describe('Two black dots drawn on a gray square. One dot is in the top left corner and the other is in the bottom center.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Top-left.
* let p = createVector(25, 25);
* point(p);
*
* // Bottom-right.
* // Multiply p.x * 2 and p.y * 3
* let arr = [2, 3];
* p.mult(arr);
* point(p);
*
* describe('Two black dots drawn on a gray square. One dot is in the top left corner and the other is in the bottom center.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Top-left.
* let p = createVector(25, 25);
* point(p);
*
* // Bottom-right.
* // Multiply p.x * p2.x and p.y * p2.y
* let p2 = createVector(2, 3);
* p.mult(p2);
* point(p);
*
* describe('Two black dots drawn on a gray square. One dot is in the top left corner and the other is in the bottom center.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Top-left.
* let p = createVector(25, 25);
* point(p);
*
* // Bottom-right.
* // Create a new p5.Vector with
* // p3.x = p.x * p2.x
* // p3.y = p.y * p2.y
* let p2 = createVector(2, 3);
* let p3 = p5.Vector.mult(p, p2);
* point(p3);
*
* describe('Two black dots drawn on a gray square. One dot is in the top left corner and the other is in the bottom center.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* describe('Two arrows extending from the top left corner. The blue arrow is twice the length of the red arrow.');
* }
*
* function draw() {
* background(200);
*
* let origin = createVector(0, 0);
*
* // Draw the red arrow.
* let v1 = createVector(25, 25);
* drawArrow(origin, v1, 'red');
*
* // Draw the blue arrow.
* let v2 = p5.Vector.mult(v1, 2);
* drawArrow(origin, v2, 'blue');
* }
*
* // Draws an arrow between two vectors.
* function drawArrow(base, vec, myColor) {
* push();
* stroke(myColor);
* strokeWeight(3);
* fill(myColor);
* translate(base.x, base.y);
* line(0, 0, vec.x, vec.y);
* rotate(vec.heading());
* let arrowSize = 7;
* translate(vec.mag() - arrowSize, 0);
* triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
* pop();
* }
* </code>
* </div>
*/
/**
* @param {Number} x number to multiply with the x component of the vector.
* @param {Number} y number to multiply with the y component of the vector.
* @param {Number} [z] number to multiply with the z component of the vector.
* @chainable
*/
/**
* @param {Number[]} arr array to multiply with the components of the vector.
* @chainable
*/
/**
* @param {p5.Vector} v vector to multiply with the components of the original vector.
* @chainable
*/
mult(...args) {
if (args.length === 1 && args[0] instanceof Vector) {
const v = args[0];
const maxLen = Math.min(this.values.length, v.values.length);
for (let i = 0; i < maxLen; i++) {
if (Number.isFinite(v.values[i]) && typeof v.values[i] === "number") {
this._values[i] *= v.values[i];
} else {
console.warn(
"p5.Vector.prototype.mult:",
"v contains components that are either undefined or not finite numbers"
);
return this;
}
}
} else if (args.length === 1 && Array.isArray(args[0])) {
const arr = args[0];
const maxLen = Math.min(this.values.length, arr.length);
for (let i = 0; i < maxLen; i++) {
if (Number.isFinite(arr[i]) && typeof arr[i] === "number") {
this._values[i] *= arr[i];
} else {
console.warn(
"p5.Vector.prototype.mult:",
"arr contains elements that are either undefined or not finite numbers"
);
return this;
}
}
} else if (
args.length === 1 &&
typeof args[0] === "number" &&
Number.isFinite(args[0])
) {
for (let i = 0; i < this._values.length; i++) {
this._values[i] *= args[0];
}
}
return this;
}
/**
* Divides a vector's `x`, `y`, and `z` components.
*
* `div()` can use separate numbers, as in `v.div(1, 2, 3)`, another
* <a href="#/p5.Vector">p5.Vector</a> object, as in `v.div(v2)`, or an array
* of numbers, as in `v.div([1, 2, 3])`.
*
* If only one value is provided, as in `v.div(2)`, then all the components
* will be divided by 2. If a value isn't provided for a component, it
* won't change. For example, `v.div(4, 5)` divides `v.x` by, `v.y` by 5,
* and `v.z` by 1. Calling `div()` with no arguments, as in `v.div()`, has
* no effect.
*
* The static version of `div()`, as in `p5.Vector.div(v, 2)`, returns a new
* <a href="#/p5.Vector">p5.Vector</a> object and doesn't change the
* originals.
*
* @param {Number} n The number to divide the vector by
* @chainable
* @example
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Center.
* let p = createVector(50, 50);
* point(p);
*
* // Top-left.
* // Divide p.x / 2 and p.y / 2
* p.div(2);
* point(p);
*
* describe('Two black dots drawn on a gray square. One dot is in the top left corner and the other is in the center.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Bottom-right.
* let p = createVector(50, 75);
* point(p);
*
* // Top-left.
* // Divide p.x / 2 and p.y / 3
* p.div(2, 3);
* point(p);
*
* describe('Two black dots drawn on a gray square. One dot is in the top left corner and the other is in the bottom center.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Bottom-right.
* let p = createVector(50, 75);
* point(p);
*
* // Top-left.
* // Divide p.x / 2 and p.y / 3
* let arr = [2, 3];
* p.div(arr);
* point(p);
*
* describe('Two black dots drawn on a gray square. One dot is in the top left corner and the other is in the bottom center.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Bottom-right.
* let p = createVector(50, 75);
* point(p);
*
* // Top-left.
* // Divide p.x / 2 and p.y / 3
* let p2 = createVector(2, 3);
* p.div(p2);
* point(p);
*
* describe('Two black dots drawn on a gray square. One dot is in the top left corner and the other is in the bottom center.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Style the points.
* strokeWeight(5);
*
* // Bottom-right.
* let p = createVector(50, 75);
* point(p);
*
* // Top-left.
* // Create a new p5.Vector with
* // p3.x = p.x / p2.x
* // p3.y = p.y / p2.y
* let p2 = createVector(2, 3);
* let p3 = p5.Vector.div(p, p2);
* point(p3);
*
* describe('Two black dots drawn on a gray square. One dot is in the top left corner and the other is in the bottom center.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function draw() {
* background(200);
*
* let origin = createVector(0, 0);
*
* // Draw the red arrow.
* let v1 = createVector(50, 50);
* drawArrow(origin, v1, 'red');
*
* // Draw the blue arrow.
* let v2 = p5.Vector.div(v1, 2);
* drawArrow(origin, v2, 'blue');
*
* describe('Two arrows extending from the top left corner. The blue arrow is half the length of the red arrow.');
* }
*
* // Draws an arrow between two vectors.
* function drawArrow(base, vec, myColor) {
* push();
* stroke(myColor);
* strokeWeight(3);
* fill(myColor);
* translate(base.x, base.y);
* line(0, 0, vec.x, vec.y);
* rotate(vec.heading());
* let arrowSize = 7;
* translate(vec.mag() - arrowSize, 0);
* triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
* pop();
* }
* </code>
* </div>
*/
/**
* @param {Number} x number to divide with the x component of the vector.
* @param {Number} y number to divide with the y component of the vector.
* @param {Number} [z] number to divide with the z component of the vector.
* @chainable
*/
/**
* @param {Number[]} arr array to divide the components of the vector by.
* @chainable
*/
/**
* @param {p5.Vector} v vector to divide the components of the original vector by.
* @chainable
*/
div(...args) {
if (args.length === 0) return this;
if (args.length === 1 && args[0] instanceof Vector) {
const v = args[0];
if (
v._values.every(
(val) => Number.isFinite(val) && typeof val === "number"
)
) {
if (v._values.some((val) => val === 0)) {
console.warn("p5.Vector.prototype.div:", "divide by 0");
return this;
}
this._values = this._values.map((val, i) => val / v._values[i]);
} else {
console.warn(
"p5.Vector.prototype.div:",
"vector contains components that are either undefined or not finite numbers"
);
}
return this;
}
if (args.length === 1 && Array.isArray(args[0])) {
const arr = args[0];
if (arr.every((val) => Number.isFinite(val) && typeof val === "number")) {
if (arr.some((val) => val === 0)) {
console.warn("p5.Vector.prototype.div:", "divide by 0");
return this;
}
this._values = this._values.map((val, i) => val / arr[i]);
} else {
console.warn(
"p5.Vector.prototype.div:",
"array contains components that are either undefined or not finite numbers"
);
}
return this;
}
if (args.every((val) => Number.isFinite(val) && typeof val === "number")) {
if (args.some((val) => val === 0)) {
console.warn("p5.Vector.prototype.div:", "divide by 0");
return this;
}
this._values = this._values.map((val, i) => val / args[0]);
} else {
console.warn(
"p5.Vector.prototype.div:",
"arguments contain components that are either undefined or not finite numbers"
);
}
return this;
}
/**
* Calculates the magnitude (length) of the vector.
*
* Use <a href="#/p5/mag">mag()</a> to calculate the magnitude of a 2D vector
* using components as in `mag(x, y)`.
*
* @return {Number} magnitude of the vector.
*
* @example
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Create a p5.Vector object.
* let p = createVector(30, 40);
*
* // Draw a line from the origin.
* line(0, 0, p.x, p.y);
*
* // Style the text.
* textAlign(CENTER);
* textSize(16);
*
* // Display the vector's magnitude.
* let m = p.mag();
* text(m, p.x, p.y);
*
* describe('A diagonal black line extends from the top left corner of a gray square. The number 50 is written at the end of the line.');
* }
* </code>
* </div>
*/
mag() {
return Math.sqrt(this.magSq());
}
/**
* Calculates the magnitude (length) of the vector squared.
*
* @return {Number} squared magnitude of the vector.
* @example
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Create a p5.Vector object.
* let p = createVector(30, 40);
*
* // Draw a line from the origin.
* line(0, 0, p.x, p.y);
*
* // Style the text.
* textAlign(CENTER);
* textSize(16);
*
* // Display the vector's magnitude squared.
* let m = p.magSq();
* text(m, p.x, p.y);
*
* describe('A diagonal black line extends from the top left corner of a gray square. The number 2500 is written at the end of the line.');
* }
* </code>
* </div>
*/
magSq() {
return this._values.reduce(
(sum, component) => sum + component * component,
0
);
}
/**
* Calculates the dot product of two vectors.
*
* The dot product is a number that describes the overlap between two vectors.
* Visually, the dot product can be thought of as the "shadow" one vector
* casts on another. The dot product's magnitude is largest when two vectors
* point in the same or opposite directions. Its magnitude is 0 when two
* vectors form a right angle.
*
* The version of `dot()` with one parameter interprets it as another
* <a href="#/p5.Vector">p5.Vector</a> object.
*
* The version of `dot()` with multiple parameters interprets them as the
* `x`, `y`, and `z` components of another vector.
*
* The static version of `dot()`, as in `p5.Vector.dot(v1, v2)`, is the same
* as calling `v1.dot(v2)`.
*
* @param {Number} x x component of the vector.
* @param {Number} [y] y component of the vector.
* @param {Number} [z] z component of the vector.
* @return {Number} dot product.
*
* @example
* <div class="norender">
* <code>
* function setup() {
* // Create p5.Vector objects.
* let v1 = createVector(3, 4);
* let v2 = createVector(3, 0);
*
* // Calculate the dot product.
* let dp = v1.dot(v2);
*
* // Prints "9" to the console.
* print(dp);
* }
* </code>
* </div>
*
* <div class="norender">
* <code>
* function setup() {
* // Create p5.Vector objects.
* let v1 = createVector(1, 0);
* let v2 = createVector(0, 1);
*
* // Calculate the dot product.
* let dp = p5.Vector.dot(v1, v2);
*
* // Prints "0" to the console.
* print(dp);
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* describe('Two arrows drawn on a gray square. A black arrow points to the right and a red arrow follows the mouse. The text "v1 • v2 = something" changes as the mouse moves.');
* }
*
* function draw() {
* background(200);
*
* // Center.
* let v0 = createVector(50, 50);
*
* // Draw the black arrow.
* let v1 = createVector(30, 0);
* drawArrow(v0, v1, 'black');
*
* // Draw the red arrow.
* let v2 = createVector(mouseX - 50, mouseY - 50);
* drawArrow(v0, v2, 'red');
*
* // Display the dot product.
* let dp = v2.dot(v1);
* text(`v2 • v1 = ${dp}`, 10, 20);
* }
*
* // Draws an arrow between two vectors.
* function drawArrow(base, vec, myColor) {
* push();
* stroke(myColor);
* strokeWeight(3);
* fill(myColor);
* translate(base.x, base.y);
* line(0, 0, vec.x, vec.y);
* rotate(vec.heading());
* let arrowSize = 7;
* translate(vec.mag() - arrowSize, 0);
* triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
* pop();
* }
* </code>
* </div>
*/
/**
* @param {p5.Vector} v <a href="#/p5.Vector">p5.Vector</a> to be dotted.
* @return {Number}
*/
dot(...args) {
if (args[0] instanceof Vector) {
return this.dot(...args[0]._values);
}
return this._values.reduce((sum, component, index) => {
return sum + component * (args[index] || 0);
}, 0);
}
/**
* Calculates the cross product of two vectors.
*
* The cross product is a vector that points straight out of the plane created
* by two vectors. The cross product's magnitude is the area of the parallelogram
* formed by the original two vectors.
*
* The static version of `cross()`, as in `p5.Vector.cross(v1, v2)`, is the same
* as calling `v1.cross(v2)`.
*
* @param {p5.Vector} v <a href="#/p5.Vector">p5.Vector</a> to be crossed.
* @return {p5.Vector} cross product as a <a href="#/p5.Vector">p5.Vector</a>.
*
* @example
* <div class="norender">
* <code>
* function setup() {
* // Create p5.Vector objects.
* let v1 = createVector(1, 0);
* let v2 = createVector(3, 4);
*
* // Calculate the cross product.
* let cp = v1.cross(v2);
*
* // Prints "p5.Vector Object : [0, 0, 4]" to the console.
* print(cp.toString());
* }
* </code>
* </div>
*
* <div class="norender">
* <code>
* function setup() {
* // Create p5.Vector objects.
* let v1 = createVector(1, 0);
* let v2 = createVector(3, 4);
*
* // Calculate the cross product.
* let cp = p5.Vector.cross(v1, v2);
*
* // Prints "p5.Vector Object : [0, 0, 4]" to the console.
* print(cp.toString());
* }
* </code>
* </div>
*/
cross(v) {
const x = this.y * v.z - this.z * v.y;
const y = this.z * v.x - this.x * v.z;
const z = this.x * v.y - this.y * v.x;
if (this.isPInst) {
return new Vector(this._fromRadians, this._toRadians, x, y, z);
} else {
return new Vector(x, y, z);
}
}
/**
* Calculates the distance between two points represented by vectors.
*
* A point's coordinates can be represented by the components of a vector
* that extends from the origin to the point.
*
* The static version of `dist()`, as in `p5.Vector.dist(v1, v2)`, is the same
* as calling `v1.dist(v2)`.
*
* Use <a href="#/p5/dist">dist()</a> to calculate the distance between points
* using coordinates as in `dist(x1, y1, x2, y2)`.
*
* @method dist
* @submodule p5.Vector
* @param {p5.Vector} v x, y, and z coordinates of a <a href="#/p5.Vector">p5.Vector</a>.
* @return {Number} distance.
*
* @example
* <div class="norender">
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Create p5.Vector objects.
* let v1 = createVector(1, 0);
* let v2 = createVector(0, 1);
*
* // Calculate the distance between them.
* let d = v1.dist(v2);
*
* // Prints "1.414..." to the console.
* print(d);
* }
* </code>
* </div>
*
* <div class="norender">
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Create p5.Vector objects.
* let v1 = createVector(1, 0);
* let v2 = createVector(0, 1);
*
* // Calculate the distance between them.
* let d = p5.Vector.dist(v1, v2);
*
* // Prints "1.414..." to the console.
* print(d);
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* describe('Three arrows drawn on a gray square. A red and a blue arrow extend from the top left. A purple arrow extends from the tip of the red arrow to the tip of the blue arrow. The number 36 is written in black near the purple arrow.');
* }
*
* function draw() {
* background(200);
*
* let origin = createVector(0, 0);
*
* // Draw the red arrow.
* let v1 = createVector(50, 50);
* drawArrow(origin, v1, 'red');
*
* // Draw the blue arrow.
* let v2 = createVector(20, 70);
* drawArrow(origin, v2, 'blue');
*
* // Purple arrow.
* let v3 = p5.Vector.sub(v2, v1);
* drawArrow(v1, v3, 'purple');
*
* // Style the text.
* textAlign(CENTER);
*
* // Display the magnitude. The same as floor(v3.mag());
* let m = floor(p5.Vector.dist(v1, v2));
* text(m, 50, 75);
* }
*
* // Draws an arrow between two vectors.
* function drawArrow(base, vec, myColor) {
* push();
* stroke(myColor);
* strokeWeight(3);
* fill(myColor);
* translate(base.x, base.y);
* line(0, 0, vec.x, vec.y);
* rotate(vec.heading());
* let arrowSize = 7;
* translate(vec.mag() - arrowSize, 0);
* triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
* pop();
* }
* </code>
* </div>
*/
dist(v) {
return v.copy().sub(this).mag();
}
/**
* Scales the components of a <a href="#/p5.Vector">p5.Vector</a> object so
* that its magnitude is 1.
*
* The static version of `normalize()`, as in `p5.Vector.normalize(v)`,
* returns a new <a href="#/p5.Vector">p5.Vector</a> object and doesn't change
* the original.
*
* @return {p5.Vector} normalized <a href="#/p5.Vector">p5.Vector</a>.
*
* @example
* <div class="norender">
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Create a p5.Vector.
* let v = createVector(10, 20, 2);
*
* // Normalize.
* v.normalize();
*
* // Prints "p5.Vector Object : [0.445..., 0.890..., 0.089...]" to the console.
* print(v.toString());
* }
* </code>
* </div>
*
* <div class="norender">
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Create a p5.Vector.
* let v0 = createVector(10, 20, 2);
*
* // Create a normalized copy.
* let v1 = p5.Vector.normalize(v0);
*
* // Prints "p5.Vector Object : [10, 20, 2]" to the console.
* print(v0.toString());
* // Prints "p5.Vector Object : [0.445..., 0.890..., 0.089...]" to the console.
* print(v1.toString());
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* describe("A red and blue arrow extend from the center of a circle. Both arrows follow the mouse, but the blue arrow's length is fixed to the circle's radius.");
* }
*
* function draw() {
* background(240);
*
* // Vector to the center.
* let v0 = createVector(50, 50);
*
* // Vector from the center to the mouse.
* let v1 = createVector(mouseX - 50, mouseY - 50);
*
* // Circle's radius.
* let r = 25;
*
* // Draw the red arrow.
* drawArrow(v0, v1, 'red');
*
* // Draw the blue arrow.
* v1.normalize();
* drawArrow(v0, v1.mult(r), 'blue');
*
* // Draw the circle.
* noFill();
* circle(50, 50, r * 2);
* }
*
* // Draws an arrow between two vectors.
* function drawArrow(base, vec, myColor) {
* push();
* stroke(myColor);
* strokeWeight(3);
* fill(myColor);
* translate(base.x, base.y);
* line(0, 0, vec.x, vec.y);
* rotate(vec.heading());
* let arrowSize = 7;
* translate(vec.mag() - arrowSize, 0);
* triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
* pop();
* }
* </code>
* </div>
*/
normalize() {
const len = this.mag();
// here we multiply by the reciprocal instead of calling 'div()'
// since div duplicates this zero check.
if (len !== 0) this.mult(1 / len);
return this;
}
/**
* Limits a vector's magnitude to a maximum value.
*
* The static version of `limit()`, as in `p5.Vector.limit(v, 5)`, returns a
* new <a href="#/p5.Vector">p5.Vector</a> object and doesn't change the
* original.
*
* @param {Number} max maximum magnitude for the vector.
* @chainable
*
* @example
* <div class="norender">
* <code>
* fu