From 0f983a6fb272d2f6f3a1803bf13327b55a0b2913 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Fri, 21 Feb 2025 23:17:34 +0100 Subject: [PATCH 1/3] Docs: More JSDoc. --- src/math/Box2.js | 177 ++++++++++++ src/math/Matrix2.js | 70 +++++ src/math/Matrix3.js | 233 ++++++++++++++- src/math/Matrix4.js | 371 +++++++++++++++++++++++- src/math/Vector2.js | 390 ++++++++++++++++++++++++- src/math/Vector3.js | 545 ++++++++++++++++++++++++++++++++++- src/math/Vector4.js | 393 +++++++++++++++++++++++++ utils/docs/jsdoc.config.json | 2 +- 8 files changed, 2167 insertions(+), 14 deletions(-) diff --git a/src/math/Box2.js b/src/math/Box2.js index 980a20264ae446..d0fb3086267bb0 100644 --- a/src/math/Box2.js +++ b/src/math/Box2.js @@ -2,17 +2,52 @@ import { Vector2 } from './Vector2.js'; const _vector = /*@__PURE__*/ new Vector2(); +/** + * Represents an axis-aligned bounding box (AABB) in 2D space. + */ class Box2 { + /** + * Constructs a new bounding box. + * + * @param {Vector2} [min=(Infinity,Infinity)] - A vector representing the lower boundary of the box. + * @param {Vector2} [max=(-Infinity,-Infinity)] - A vector representing the upper boundary of the box. + */ constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ this.isBox2 = true; + /** + * The lower boundary of the box. + * + * @type {Vector2} + */ this.min = min; + + /** + * The upper boundary of the box. + * + * @type {Vector2} + */ this.max = max; } + /** + * Sets the lower and upper boundaries of this box. + * Please note that this method only copies the values from the given objects. + * + * @param {Vector2} min - The lower boundary of the box. + * @param {Vector2} max - The upper boundary of the box. + * @return {Box2} A reference to this bounding box. + */ set( min, max ) { this.min.copy( min ); @@ -22,6 +57,13 @@ class Box2 { } + /** + * Sets the upper and lower bounds of this box so it encloses the position data + * in the given array. + * + * @param {Array} points - An array holding 2D position data as instances of {@link Vector2}. + * @return {Box2} A reference to this bounding box. + */ setFromPoints( points ) { this.makeEmpty(); @@ -36,6 +78,14 @@ class Box2 { } + /** + * Centers this box on the given center vector and sets this box's width, height and + * depth to the given size values. + * + * @param {Vector2} center - The center of the box. + * @param {Vector2} size - The x and y dimensions of the box. + * @return {Box2} A reference to this bounding box. + */ setFromCenterAndSize( center, size ) { const halfSize = _vector.copy( size ).multiplyScalar( 0.5 ); @@ -46,12 +96,23 @@ class Box2 { } + /** + * Returns a new box with copied values from this instance. + * + * @return {Box2} A clone of this instance. + */ clone() { return new this.constructor().copy( this ); } + /** + * Copies the values of the given box to this instance. + * + * @param {Box2} box - The box to copy. + * @return {Box2} A reference to this bounding box. + */ copy( box ) { this.min.copy( box.min ); @@ -61,6 +122,11 @@ class Box2 { } + /** + * Makes this box empty which means in encloses a zero space in 2D. + * + * @return {Box2} A reference to this bounding box. + */ makeEmpty() { this.min.x = this.min.y = + Infinity; @@ -70,6 +136,13 @@ class Box2 { } + /** + * Returns true if this box includes zero points within its bounds. + * Note that a box with equal lower and upper bounds still includes one + * point, the one both bounds share. + * + * @return {boolean} Whether this box is empty or not. + */ isEmpty() { // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes @@ -78,18 +151,36 @@ class Box2 { } + /** + * Returns the center point of this box. + * + * @param {Vector2} target - The target vector that is used to store the method's result. + * @return {Vector2} The center point. + */ getCenter( target ) { return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); } + /** + * Returns the dimensions of this box. + * + * @param {Vector2} target - The target vector that is used to store the method's result. + * @return {Vector2} The size. + */ getSize( target ) { return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); } + /** + * Expands the boundaries of this box to include the given point. + * + * @param {Vector2} point - The point that should be included by the bounding box. + * @return {Box2} A reference to this bounding box. + */ expandByPoint( point ) { this.min.min( point ); @@ -99,6 +190,15 @@ class Box2 { } + /** + * Expands this box equilaterally by the given vector. The width of this + * box will be expanded by the x component of the vector in both + * directions. The height of this box will be expanded by the y component of + * the vector in both directions. + * + * @param {Vector2} vector - The vector that should expand the bounding box. + * @return {Box2} A reference to this bounding box. + */ expandByVector( vector ) { this.min.sub( vector ); @@ -108,6 +208,13 @@ class Box2 { } + /** + * Expands each dimension of the box by the given scalar. If negative, the + * dimensions of the box will be contracted. + * + * @param {number} scalar - The scalar value that should expand the bounding box. + * @return {Box2} A reference to this bounding box. + */ expandByScalar( scalar ) { this.min.addScalar( - scalar ); @@ -117,6 +224,12 @@ class Box2 { } + /** + * Returns `true` if the given point lies within or on the boundaries of this box. + * + * @param {Vector2} point - The point to test. + * @return {boolean} Whether the bounding box contains the given point or not. + */ containsPoint( point ) { return point.x >= this.min.x && point.x <= this.max.x && @@ -124,6 +237,13 @@ class Box2 { } + /** + * Returns `true` if this bounding box includes the entirety of the given bounding box. + * If this box and the given one are identical, this function also returns `true`. + * + * @param {Box2} box - The bounding box to test. + * @return {boolean} Whether the bounding box contains the given bounding box or not. + */ containsBox( box ) { return this.min.x <= box.min.x && box.max.x <= this.max.x && @@ -131,6 +251,13 @@ class Box2 { } + /** + * Returns a point as a proportion of this box's width and height. + * + * @param {Vector2} point - A point in 2D space. + * @param {Vector2} target - The target vector that is used to store the method's result. + * @return {Vector2} A point as a proportion of this box's width and height. + */ getParameter( point, target ) { // This can potentially have a divide by zero if the box @@ -143,6 +270,12 @@ class Box2 { } + /** + * Returns `true` if the given bounding box intersects with this bounding box. + * + * @param {Box2} box - The bounding box to test. + * @return {boolean} Whether the given bounding box intersects with this bounding box. + */ intersectsBox( box ) { // using 4 splitting planes to rule out intersections @@ -152,18 +285,41 @@ class Box2 { } + /** + * Clamps the given point within the bounds of this box. + * + * @param {Vector2} point - The point to clamp. + * @param {Vector2} target - The target vector that is used to store the method's result. + * @return {Vector2} The clamped point. + */ clampPoint( point, target ) { return target.copy( point ).clamp( this.min, this.max ); } + /** + * Returns the euclidean distance from any edge of this box to the specified point. If + * the given point lies inside of this box, the distance will be `0`. + * + * @param {Vector2} point - The point to compute the distance to. + * @return {number} The euclidean distance. + */ distanceToPoint( point ) { return this.clampPoint( point, _vector ).distanceTo( point ); } + /** + * Computes the intersection of this bounding box and the given one, setting the upper + * bound of this box to the lesser of the two boxes' upper bounds and the + * lower bound of this box to the greater of the two boxes' lower bounds. If + * there's no overlap, makes this box empty. + * + * @param {Box2} box - The bounding box to intersect with. + * @return {Box2} A reference to this bounding box. + */ intersect( box ) { this.min.max( box.min ); @@ -175,6 +331,14 @@ class Box2 { } + /** + * Computes the union of this box and another and the given one, setting the upper + * bound of this box to the greater of the two boxes' upper bounds and the + * lower bound of this box to the lesser of the two boxes' lower bounds. + * + * @param {Box2} box - The bounding box that will be unioned with this instance. + * @return {Box2} A reference to this bounding box. + */ union( box ) { this.min.min( box.min ); @@ -184,6 +348,13 @@ class Box2 { } + /** + * Adds the given offset to both the upper and lower bounds of this bounding box, + * effectively moving it in 2D space. + * + * @param {Vector2} offset - The offset that should be used to translate the bounding box. + * @return {Box2} A reference to this bounding box. + */ translate( offset ) { this.min.add( offset ); @@ -193,6 +364,12 @@ class Box2 { } + /** + * Returns `true` if this bounding box is equal with the given one. + * + * @param {Box2} box - The box to test for equality. + * @return {boolean} Whether this bounding box is equal with the given one. + */ equals( box ) { return box.min.equals( this.min ) && box.max.equals( this.max ); diff --git a/src/math/Matrix2.js b/src/math/Matrix2.js index a3975672be4cae..a16841378d829b 100644 --- a/src/math/Matrix2.js +++ b/src/math/Matrix2.js @@ -1,9 +1,57 @@ +/** + * Represents a 2x2 matrix. + * + * A Note on Row-Major and Column-Major Ordering: + * + * The constructor and {@link Matrix2#set} method take arguments in + * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order} + * order, while internally they are stored in the {@link Matrix2#elements} array in column-major order. + * This means that calling: + * ```js + * const m = new THREE.Matrix2(); + * m.set( 11, 12, + * 21, 22 ); + * ``` + * will result in the elements array containing: + * ```js + * m.elements = [ 11, 21, + * 12, 22 ]; + * ``` + * and internally all calculations are performed using column-major ordering. + * However, as the actual ordering makes no difference mathematically and + * most people are used to thinking about matrices in row-major order, the + * three.js documentation shows matrices in row-major order. Just bear in + * mind that if you are reading the source code, you'll have to take the + * transpose of any matrices outlined here to make sense of the calculations. + */ export class Matrix2 { + /** + * Constructs a new 2x2 matrix. The arguments are supposed to be + * in row-major order. If no arguments are provided, the constructor + * initializes the matrix as an identity matrix. + * + * @param {number} [n11] - 1-1 matrix element. + * @param {number} [n12] - 1-2 matrix element. + * @param {number} [n21] - 2-1 matrix element. + * @param {number} [n22] - 2-2 matrix element. + */ constructor( n11, n12, n21, n22 ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ Matrix2.prototype.isMatrix2 = true; + /** + * A column-major list of matrix values. + * + * @type {Array} + */ this.elements = [ 1, 0, 0, 1, @@ -17,6 +65,11 @@ export class Matrix2 { } + /** + * Sets this matrix to the 2x2 identity matrix. + * + * @return {Matrix2} A reference to this matrix. + */ identity() { this.set( @@ -28,6 +81,13 @@ export class Matrix2 { } + /** + * Sets the elements of the matrix from the given array. + * + * @param {Array} array - The matrix elements in column-major order. + * @param {number} [offset=0] - Index of the first element in the array. + * @return {Matrix2} A reference to this matrix. + */ fromArray( array, offset = 0 ) { for ( let i = 0; i < 4; i ++ ) { @@ -40,6 +100,16 @@ export class Matrix2 { } + /** + * Sets the elements of the matrix.The arguments are supposed to be + * in row-major order. + * + * @param {number} n11 - 1-1 matrix element. + * @param {number} n12 - 1-2 matrix element. + * @param {number} n21 - 2-1 matrix element. + * @param {number} n22 - 2-2 matrix element. + * @return {Matrix2} A reference to this matrix. + */ set( n11, n12, n21, n22 ) { const te = this.elements; diff --git a/src/math/Matrix3.js b/src/math/Matrix3.js index 6bfb050d7f0945..e7d29496bf4bf2 100644 --- a/src/math/Matrix3.js +++ b/src/math/Matrix3.js @@ -1,9 +1,64 @@ +/** + * Represents a 3x3 matrix. + * + * A Note on Row-Major and Column-Major Ordering: + * + * The constructor and {@link Matrix3#set} method take arguments in + * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order} + * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order. + * This means that calling: + * ```js + * const m = new THREE.Matrix(); + * m.set( 11, 12, 13, + * 21, 22, 23, + * 31, 32, 33 ); + * ``` + * will result in the elements array containing: + * ```js + * m.elements = [ 11, 21, 31, + * 12, 22, 32, + * 13, 23, 33 ]; + * ``` + * and internally all calculations are performed using column-major ordering. + * However, as the actual ordering makes no difference mathematically and + * most people are used to thinking about matrices in row-major order, the + * three.js documentation shows matrices in row-major order. Just bear in + * mind that if you are reading the source code, you'll have to take the + * transpose of any matrices outlined here to make sense of the calculations. + */ class Matrix3 { + /** + * Constructs a new 3x3 matrix. The arguments are supposed to be + * in row-major order. If no arguments are provided, the constructor + * initializes the matrix as an identity matrix. + * + * @param {number} [n11] - 1-1 matrix element. + * @param {number} [n12] - 1-2 matrix element. + * @param {number} [n13] - 1-3 matrix element. + * @param {number} [n21] - 2-1 matrix element. + * @param {number} [n22] - 2-2 matrix element. + * @param {number} [n23] - 2-3 matrix element. + * @param {number} [n31] - 3-1 matrix element. + * @param {number} [n32] - 3-2 matrix element. + * @param {number} [n33] - 3-3 matrix element. + */ constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ Matrix3.prototype.isMatrix3 = true; + /** + * A column-major list of matrix values. + * + * @type {Array} + */ this.elements = [ 1, 0, 0, @@ -20,6 +75,21 @@ class Matrix3 { } + /** + * Sets the elements of the matrix.The arguments are supposed to be + * in row-major order. + * + * @param {number} [n11] - 1-1 matrix element. + * @param {number} [n12] - 1-2 matrix element. + * @param {number} [n13] - 1-3 matrix element. + * @param {number} [n21] - 2-1 matrix element. + * @param {number} [n22] - 2-2 matrix element. + * @param {number} [n23] - 2-3 matrix element. + * @param {number} [n31] - 3-1 matrix element. + * @param {number} [n32] - 3-2 matrix element. + * @param {number} [n33] - 3-3 matrix element. + * @return {Matrix3} A reference to this matrix. + */ set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { const te = this.elements; @@ -32,6 +102,11 @@ class Matrix3 { } + /** + * Sets this matrix to the 3x3 identity matrix. + * + * @return {Matrix3} A reference to this matrix. + */ identity() { this.set( @@ -46,6 +121,12 @@ class Matrix3 { } + /** + * Copies the values of the given matrix to this instance. + * + * @param {Matrix3} m - The matrix to copy. + * @return {Matrix3} A reference to this matrix. + */ copy( m ) { const te = this.elements; @@ -59,6 +140,14 @@ class Matrix3 { } + /** + * Extracts the basis of this matrix into the three axis vectors provided. + * + * @param {Vector3} xAxis - The basis's x axis. + * @param {Vector3} yAxis - The basis's y axis. + * @param {Vector3} zAxis - The basis's z axis. + * @return {Matrix3} A reference to this matrix. + */ extractBasis( xAxis, yAxis, zAxis ) { xAxis.setFromMatrix3Column( this, 0 ); @@ -69,6 +158,12 @@ class Matrix3 { } + /** + * Set this matrix to the upper 3x3 matrix of the given 4x4 matrix. + * + * @param {Matrix4} m - The 4x4 matrix. + * @return {Matrix3} A reference to this matrix. + */ setFromMatrix4( m ) { const me = m.elements; @@ -85,18 +180,38 @@ class Matrix3 { } + /** + * Post-multiplies this matrix by the given 3x3 matrix. + * + * @param {Matrix3} m - The matrix to multiply with. + * @return {Matrix3} A reference to this matrix. + */ multiply( m ) { return this.multiplyMatrices( this, m ); } + /** + * Pre-multiplies this matrix by the given 3x3 matrix. + * + * @param {Matrix3} m - The matrix to multiply with. + * @return {Matrix3} A reference to this matrix. + */ premultiply( m ) { return this.multiplyMatrices( m, this ); } + /** + * Multiples the given 3x3 matrices and stores the result + * in this matrix. + * + * @param {Matrix3} a - The first matrix. + * @param {Matrix3} b - The second matrix. + * @return {Matrix3} A reference to this matrix. + */ multiplyMatrices( a, b ) { const ae = a.elements; @@ -127,6 +242,12 @@ class Matrix3 { } + /** + * Multiplies every component of the matrix by the given scalar. + * + * @param {number} s - The scalar. + * @return {Matrix3} A reference to this matrix. + */ multiplyScalar( s ) { const te = this.elements; @@ -139,6 +260,11 @@ class Matrix3 { } + /** + * Computes and returns the determinant of this matrix. + * + * @return {number} The determinant. + */ determinant() { const te = this.elements; @@ -151,6 +277,13 @@ class Matrix3 { } + /** + * Inverts this matrix, using the [analytic method]{@link https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution}. + * You can not invert with a determinant of zero. If you attempt this, the method produces + * a zero matrix instead. + * + * @return {Matrix3} A reference to this matrix. + */ invert() { const te = this.elements, @@ -185,6 +318,11 @@ class Matrix3 { } + /** + * Transposes this matrix in place. + * + * @return {Matrix3} A reference to this matrix. + */ transpose() { let tmp; @@ -198,12 +336,25 @@ class Matrix3 { } + /** + * Computes the normal matrix which is the inverse transpose of the upper + * left 3x3 portion of the given 4x4 matrix. + * + * @param {Matrix4} matrix4 - The 4x4 matrix. + * @return {Matrix3} A reference to this matrix. + */ getNormalMatrix( matrix4 ) { return this.setFromMatrix4( matrix4 ).invert().transpose(); } + /** + * Transposes this matrix into the supplied array, and returns itself unchanged. + * + * @param {Array} r - An arry to store the transposed matrix elements. + * @return {Matrix3} A reference to this matrix. + */ transposeIntoArray( r ) { const m = this.elements; @@ -222,6 +373,18 @@ class Matrix3 { } + /** + * Sets the UV transform matrix from offset, repeat, rotation, and center. + * + * @param {number} tx - Offset x. + * @param {number} ty - Offset y. + * @param {number} sx - Repeat x. + * @param {number} sy - Repeat y. + * @param {number} rotation - Rotation, in radians. Positive values rotate counterclockwise. + * @param {number} cx - Center x of rotation. + * @param {number} cy - Center y of rotation + * @return {Matrix3} A reference to this matrix. + */ setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { const c = Math.cos( rotation ); @@ -237,8 +400,13 @@ class Matrix3 { } - // - + /** + * Scales this matrix with the given scalar values. + * + * @param {number} sx - The amount to scale in the X axis. + * @param {number} sy - The amount to scale in the Y axis. + * @return {Matrix3} A reference to this matrix. + */ scale( sx, sy ) { this.premultiply( _m3.makeScale( sx, sy ) ); @@ -247,6 +415,12 @@ class Matrix3 { } + /** + * Rotates this matrix by the given angle. + * + * @param {number} theta - The rotation in radians. + * @return {Matrix3} A reference to this matrix. + */ rotate( theta ) { this.premultiply( _m3.makeRotation( - theta ) ); @@ -255,6 +429,13 @@ class Matrix3 { } + /** + * Translates this matrix by the given scalar values. + * + * @param {number} tx - The amount to translate in the X axis. + * @param {number} ty - The amount to translate in the Y axis. + * @return {Matrix3} A reference to this matrix. + */ translate( tx, ty ) { this.premultiply( _m3.makeTranslation( tx, ty ) ); @@ -265,6 +446,13 @@ class Matrix3 { // for 2D Transforms + /** + * Sets this matrix as a 2D translation transform. + * + * @param {number|Vector2} x - The amount to translate in the X axis or alternatively a translation vector. + * @param {number} y - The amount to translate in the Y axis. + * @return {Matrix3} A reference to this matrix. + */ makeTranslation( x, y ) { if ( x.isVector2 ) { @@ -293,6 +481,12 @@ class Matrix3 { } + /** + * Sets this matrix as a 2D rotational transformation. + * + * @param {number} theta - The rotation in radians. + * @return {Matrix3} A reference to this matrix. + */ makeRotation( theta ) { // counterclockwise @@ -312,6 +506,13 @@ class Matrix3 { } + /** + * Sets this matrix as a 2D scale transform. + * + * @param {number} x - The amount to scale in the X axis. + * @param {number} y - The amount to scale in the Y axis. + * @return {Matrix3} A reference to this matrix. + */ makeScale( x, y ) { this.set( @@ -326,8 +527,12 @@ class Matrix3 { } - // - + /** + * Returns `true` if this matrix is equal with the given one. + * + * @param {Matrix3} matrix - The matrix to test for equality. + * @return {boolean} Whether this matrix is equal with the given one. + */ equals( matrix ) { const te = this.elements; @@ -343,6 +548,13 @@ class Matrix3 { } + /** + * Sets the elements of the matrix from the given array. + * + * @param {Array} array - The matrix elements in column-major order. + * @param {number} [offset=0] - Index of the first element in the array. + * @return {Matrix3} A reference to this matrix. + */ fromArray( array, offset = 0 ) { for ( let i = 0; i < 9; i ++ ) { @@ -355,6 +567,14 @@ class Matrix3 { } + /** + * Writes the elements of this matrix to the given array. If no array is provided, + * the method returns a new instance. + * + * @param {Array} [array=[]] - The target array holding the matrix elements in column-major order. + * @param {number} [offset=0] - Index of the first element in the array. + * @return {Array} The matrix elements in column-major order. + */ toArray( array = [], offset = 0 ) { const te = this.elements; @@ -375,6 +595,11 @@ class Matrix3 { } + /** + * Returns a matrix with copied values from this instance. + * + * @return {Matrix3} A clone of this instance. + */ clone() { return new this.constructor().fromArray( this.elements ); diff --git a/src/math/Matrix4.js b/src/math/Matrix4.js index bf5bc032f4f562..2e1eebfdf77029 100644 --- a/src/math/Matrix4.js +++ b/src/math/Matrix4.js @@ -1,12 +1,84 @@ import { WebGLCoordinateSystem, WebGPUCoordinateSystem } from '../constants.js'; import { Vector3 } from './Vector3.js'; +/** + * Represents a 4x4 matrix. + * + * The most common use of a 4x4 matrix in 3D computer graphics is as a transformation matrix. + * For an introduction to transformation matrices as used in WebGL, check out [this tutorial]{@link https://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices} + * + * This allows a 3D vector representing a point in 3D space to undergo + * transformations such as translation, rotation, shear, scale, reflection, + * orthogonal or perspective projection and so on, by being multiplied by the + * matrix. This is known as `applying` the matrix to the vector. + * + * A Note on Row-Major and Column-Major Ordering: + * + * The constructor and {@link Matrix3#set} method take arguments in + * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order} + * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order. + * This means that calling: + * ```js + * const m = new THREE.Matrix4(); + * m.set( 11, 12, 13, 14, + * 21, 22, 23, 24, + * 31, 32, 33, 34, + * 41, 42, 43, 44 ); + * ``` + * will result in the elements array containing: + * ```js + * m.elements = [ 11, 21, 31, 41, + * 12, 22, 32, 42, + * 13, 23, 33, 43, + * 14, 24, 34, 44 ]; + * ``` + * and internally all calculations are performed using column-major ordering. + * However, as the actual ordering makes no difference mathematically and + * most people are used to thinking about matrices in row-major order, the + * three.js documentation shows matrices in row-major order. Just bear in + * mind that if you are reading the source code, you'll have to take the + * transpose of any matrices outlined here to make sense of the calculations. + */ class Matrix4 { + /** + * Constructs a new 4x4 matrix. The arguments are supposed to be + * in row-major order. If no arguments are provided, the constructor + * initializes the matrix as an identity matrix. + * + * @param {number} [n11] - 1-1 matrix element. + * @param {number} [n12] - 1-2 matrix element. + * @param {number} [n13] - 1-3 matrix element. + * @param {number} [n14] - 1-4 matrix element. + * @param {number} [n21] - 2-1 matrix element. + * @param {number} [n22] - 2-2 matrix element. + * @param {number} [n23] - 2-3 matrix element. + * @param {number} [n24] - 2-4 matrix element. + * @param {number} [n31] - 3-1 matrix element. + * @param {number} [n32] - 3-2 matrix element. + * @param {number} [n33] - 3-3 matrix element. + * @param {number} [n34] - 3-4 matrix element. + * @param {number} [n41] - 4-1 matrix element. + * @param {number} [n42] - 4-2 matrix element. + * @param {number} [n43] - 4-3 matrix element. + * @param {number} [n44] - 4-4 matrix element. + */ constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ Matrix4.prototype.isMatrix4 = true; + /** + * A column-major list of matrix values. + * + * @type {Array} + */ this.elements = [ 1, 0, 0, 0, @@ -24,6 +96,28 @@ class Matrix4 { } + /** + * Sets the elements of the matrix.The arguments are supposed to be + * in row-major order. + * + * @param {number} [n11] - 1-1 matrix element. + * @param {number} [n12] - 1-2 matrix element. + * @param {number} [n13] - 1-3 matrix element. + * @param {number} [n14] - 1-4 matrix element. + * @param {number} [n21] - 2-1 matrix element. + * @param {number} [n22] - 2-2 matrix element. + * @param {number} [n23] - 2-3 matrix element. + * @param {number} [n24] - 2-4 matrix element. + * @param {number} [n31] - 3-1 matrix element. + * @param {number} [n32] - 3-2 matrix element. + * @param {number} [n33] - 3-3 matrix element. + * @param {number} [n34] - 3-4 matrix element. + * @param {number} [n41] - 4-1 matrix element. + * @param {number} [n42] - 4-2 matrix element. + * @param {number} [n43] - 4-3 matrix element. + * @param {number} [n44] - 4-4 matrix element. + * @return {Matrix4} A reference to this matrix. + */ set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { const te = this.elements; @@ -37,6 +131,11 @@ class Matrix4 { } + /** + * Sets this matrix to the 4x4 identity matrix. + * + * @return {Matrix4} A reference to this matrix. + */ identity() { this.set( @@ -52,12 +151,23 @@ class Matrix4 { } + /** + * Returns a matrix with copied values from this instance. + * + * @return {Matrix4} A clone of this instance. + */ clone() { return new Matrix4().fromArray( this.elements ); } + /** + * Copies the values of the given matrix to this instance. + * + * @param {Matrix4} m - The matrix to copy. + * @return {Matrix4} A reference to this matrix. + */ copy( m ) { const te = this.elements; @@ -72,6 +182,13 @@ class Matrix4 { } + /** + * Copies the translation component of the given matrix + * into this matrix's translation component. + * + * @param {Matrix4} m - The matrix to copy the translation component. + * @return {Matrix4} A reference to this matrix. + */ copyPosition( m ) { const te = this.elements, me = m.elements; @@ -84,6 +201,12 @@ class Matrix4 { } + /** + * Set the upper 3x3 elements of this matrix to the values of given 3x3 matrix. + * + * @param {Matrix3} m - The 3x3 matrix. + * @return {Matrix4} A reference to this matrix. + */ setFromMatrix3( m ) { const me = m.elements; @@ -101,6 +224,14 @@ class Matrix4 { } + /** + * Extracts the basis of this matrix into the three axis vectors provided. + * + * @param {Vector3} xAxis - The basis's x axis. + * @param {Vector3} yAxis - The basis's y axis. + * @param {Vector3} zAxis - The basis's z axis. + * @return {Matrix4} A reference to this matrix. + */ extractBasis( xAxis, yAxis, zAxis ) { xAxis.setFromMatrixColumn( this, 0 ); @@ -111,6 +242,14 @@ class Matrix4 { } + /** + * Sets the given basis vectors to this matrix. + * + * @param {Vector3} xAxis - The basis's x axis. + * @param {Vector3} yAxis - The basis's y axis. + * @param {Vector3} zAxis - The basis's z axis. + * @return {Matrix4} A reference to this matrix. + */ makeBasis( xAxis, yAxis, zAxis ) { this.set( @@ -124,10 +263,17 @@ class Matrix4 { } + /** + * Extracts the rotation component of the given matrix + * into this matrix's rotation component. + * + * Note: This method does not support reflection matrices. + * + * @param {Matrix4} m - The matrix. + * @return {Matrix4} A reference to this matrix. + */ extractRotation( m ) { - // this method does not support reflection matrices - const te = this.elements; const me = m.elements; @@ -159,6 +305,16 @@ class Matrix4 { } + /** + * Sets the rotation component (the upper left 3x3 matrix) of this matrix to + * the rotation specified by the given Euler angles. The rest of + * the matrix is set to the identity. Depending on the {@link Euler#order}, + * there are six possible outcomes. See [this page]{@link https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix} + * for a complete list. + * + * @param {Euler} euler - The Euler angles. + * @return {Matrix4} A reference to this matrix. + */ makeRotationFromEuler( euler ) { const te = this.elements; @@ -281,12 +437,29 @@ class Matrix4 { } + /** + * Sets the rotation component of this matrix to the rotation specified by + * the given Quaternion as outlined [here]{@link https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion} + * The rest of the matrix is set to the identity. + * + * @param {Quaternion} q - The Quaternion. + * @return {Matrix4} A reference to this matrix. + */ makeRotationFromQuaternion( q ) { return this.compose( _zero, q, _one ); } + /** + * Sets the rotation component of the transformation matrix, looking from `eye` towards + * `target`, and oriented by the up-direction. + * + * @param {Vector3} eye - The eye vector. + * @param {Vector3} target - The target vector. + * @param {Vector3} up - The up vector. + * @return {Matrix4} A reference to this matrix. + */ lookAt( eye, target, up ) { const te = this.elements; @@ -334,18 +507,38 @@ class Matrix4 { } + /** + * Post-multiplies this matrix by the given 4x4 matrix. + * + * @param {Matrix4} m - The matrix to multiply with. + * @return {Matrix4} A reference to this matrix. + */ multiply( m ) { return this.multiplyMatrices( this, m ); } + /** + * Pre-multiplies this matrix by the given 4x4 matrix. + * + * @param {Matrix4} m - The matrix to multiply with. + * @return {Matrix4} A reference to this matrix. + */ premultiply( m ) { return this.multiplyMatrices( m, this ); } + /** + * Multiples the given 4x4 matrices and stores the result + * in this matrix. + * + * @param {Matrix4} a - The first matrix. + * @param {Matrix4} b - The second matrix. + * @return {Matrix4} A reference to this matrix. + */ multiplyMatrices( a, b ) { const ae = a.elements; @@ -386,6 +579,12 @@ class Matrix4 { } + /** + * Multiplies every component of the matrix by the given scalar. + * + * @param {number} s - The scalar. + * @return {Matrix4} A reference to this matrix. + */ multiplyScalar( s ) { const te = this.elements; @@ -399,6 +598,13 @@ class Matrix4 { } + /** + * Computes and returns the determinant of this matrix. + * + * Based on the method outlined [here]{@link http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.html}. + * + * @return {number} The determinant. + */ determinant() { const te = this.elements; @@ -409,7 +615,6 @@ class Matrix4 { const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; //TODO: make this more efficient - //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) return ( n41 * ( @@ -449,6 +654,11 @@ class Matrix4 { } + /** + * Transposes this matrix in place. + * + * @return {Matrix4} A reference to this matrix. + */ transpose() { const te = this.elements; @@ -466,6 +676,15 @@ class Matrix4 { } + /** + * Sets the position component for this matrix from the given vector, + * without affecting the rest of the matrix. + * + * @param {number|Vector3} x - The x component of the vector or alternativley the vector object. + * @param {number} y - The y component of the vector. + * @param {number} z - The z component of the vector. + * @return {Matrix4} A reference to this matrix. + */ setPosition( x, y, z ) { const te = this.elements; @@ -488,6 +707,13 @@ class Matrix4 { } + /** + * Inverts this matrix, using the [analytic method]{@link https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution}. + * You can not invert with a determinant of zero. If you attempt this, the method produces + * a zero matrix instead. + * + * @return {Matrix4} A reference to this matrix. + */ invert() { // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm @@ -533,6 +759,12 @@ class Matrix4 { } + /** + * Multiplies the columns of this matrix by the given vector. + * + * @param {Vector3} v - The scale vector. + * @return {Matrix4} A reference to this matrix. + */ scale( v ) { const te = this.elements; @@ -547,6 +779,11 @@ class Matrix4 { } + /** + * Gets the maximum scale value of the three axes. + * + * @return {number} The maxium scale. + */ getMaxScaleOnAxis() { const te = this.elements; @@ -559,6 +796,14 @@ class Matrix4 { } + /** + * Sets this matrix as a translation transform from the given vector. + * + * @param {number|Vector3} x - The amount to translate in the X axis or alternatively a translation vector. + * @param {number} y - The amount to translate in the Y axis. + * @param {number} z - The amount to translate in the z axis. + * @return {Matrix4} A reference to this matrix. + */ makeTranslation( x, y, z ) { if ( x.isVector3 ) { @@ -589,6 +834,13 @@ class Matrix4 { } + /** + * Sets this matrix as a rotational transformation around the X axis by + * the given angle. + * + * @param {number} theta - The rotation in radians. + * @return {Matrix4} A reference to this matrix. + */ makeRotationX( theta ) { const c = Math.cos( theta ), s = Math.sin( theta ); @@ -606,6 +858,13 @@ class Matrix4 { } + /** + * Sets this matrix as a rotational transformation around the Y axis by + * the given angle. + * + * @param {number} theta - The rotation in radians. + * @return {Matrix4} A reference to this matrix. + */ makeRotationY( theta ) { const c = Math.cos( theta ), s = Math.sin( theta ); @@ -623,6 +882,13 @@ class Matrix4 { } + /** + * Sets this matrix as a rotational transformation around the Z axis by + * the given angle. + * + * @param {number} theta - The rotation in radians. + * @return {Matrix4} A reference to this matrix. + */ makeRotationZ( theta ) { const c = Math.cos( theta ), s = Math.sin( theta ); @@ -640,6 +906,17 @@ class Matrix4 { } + /** + * Sets this matrix as a rotational transformation around the given axis by + * the given angle. + * + * This is a somewhat controversial but mathematically sound alternative to + * rotating via Quaternions. See the discussion [here]{@link https://www.gamedev.net/articles/programming/math-and-physics/do-we-really-need-quaternions-r1199}. + * + * @param {Vector3} axis - The normalized rotation axis. + * @param {number} angle - The rotation in radians. + * @return {Matrix4} A reference to this matrix. + */ makeRotationAxis( axis, angle ) { // Based on http://www.gamedev.net/reference/articles/article1199.asp @@ -663,6 +940,14 @@ class Matrix4 { } + /** + * Sets this matrix as a scale transformation. + * + * @param {number} x - The amount to scale in the X axis. + * @param {number} y - The amount to scale in the Y axis. + * @param {number} z - The amount to scale in the Z axis. + * @return {Matrix4} A reference to this matrix. + */ makeScale( x, y, z ) { this.set( @@ -678,6 +963,17 @@ class Matrix4 { } + /** + * Sets this matrix as a shear transformation. + * + * @param {number} xy - The amount to shear X by Y. + * @param {number} xz - The amount to shear X by Z. + * @param {number} yx - The amount to shear Y by X. + * @param {number} yz - The amount to shear Y by Z. + * @param {number} zx - The amount to shear Z by X. + * @param {number} zy - The amount to shear Z by Y. + * @return {Matrix4} A reference to this matrix. + */ makeShear( xy, xz, yx, yz, zx, zy ) { this.set( @@ -693,6 +989,15 @@ class Matrix4 { } + /** + * Sets this matrix to the transformation composed of the given position, + * rotation (Quaternion) and scale. + * + * @param {Vector3} position - The position vector. + * @param {Quaternion} quaternion - The rotation as a Quaternion. + * @param {Vector3} scale - The scale vector. + * @return {Matrix4} A reference to this matrix. + */ compose( position, quaternion, scale ) { const te = this.elements; @@ -729,6 +1034,19 @@ class Matrix4 { } + /** + * Decomposes this matrix into its positon, rotation and scale components + * and provides the result in the given objects. + * + * Note: Not all matrices are decomposable in this way. For example, if an + * object has a non-uniformly scaled parent, then the object's world matrix + * may not be decomposable, and this method may not be appropriate. + * + * @param {Vector3} position - The position vector. + * @param {Quaternion} quaternion - The rotation as a Quaternion. + * @param {Vector3} scale - The scale vector. + * @return {Matrix4} A reference to this matrix. + */ decompose( position, quaternion, scale ) { const te = this.elements; @@ -774,6 +1092,19 @@ class Matrix4 { } + /** + * Creates a perspective projection matrix. This is used internally by + * {@link PerspectiveCamera#updateProjectionMatrix}. + + * @param {number} left - Left boundary of the viewing frustum at the near plane. + * @param {number} right - Right boundary of the viewing frustum at the near plane. + * @param {number} top - Top boundary of the viewing frustum at the near plane. + * @param {number} bottom - Bottom boundary of the viewing frustum at the near plane. + * @param {number} near - The distance from the camera to the near plane. + * @param {number} far - The distance from the camera to the far plane. + * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} [coordinateSystem=WebGLCoordinateSystem] - The coordinate system. + * @return {Matrix4} A reference to this matrix. + */ makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { const te = this.elements; @@ -810,6 +1141,19 @@ class Matrix4 { } + /** + * Creates a orthographic projection matrix. This is used internally by + * {@link OrthographicCamera#updateProjectionMatrix}. + + * @param {number} left - Left boundary of the viewing frustum at the near plane. + * @param {number} right - Right boundary of the viewing frustum at the near plane. + * @param {number} top - Top boundary of the viewing frustum at the near plane. + * @param {number} bottom - Bottom boundary of the viewing frustum at the near plane. + * @param {number} near - The distance from the camera to the near plane. + * @param {number} far - The distance from the camera to the far plane. + * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} [coordinateSystem=WebGLCoordinateSystem] - The coordinate system. + * @return {Matrix4} A reference to this matrix. + */ makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { const te = this.elements; @@ -847,6 +1191,12 @@ class Matrix4 { } + /** + * Returns `true` if this matrix is equal with the given one. + * + * @param {Matrix4} matrix - The matrix to test for equality. + * @return {boolean} Whether this matrix is equal with the given one. + */ equals( matrix ) { const te = this.elements; @@ -862,6 +1212,13 @@ class Matrix4 { } + /** + * Sets the elements of the matrix from the given array. + * + * @param {Array} array - The matrix elements in column-major order. + * @param {number} [offset=0] - Index of the first element in the array. + * @return {Matrix4} A reference to this matrix. + */ fromArray( array, offset = 0 ) { for ( let i = 0; i < 16; i ++ ) { @@ -874,6 +1231,14 @@ class Matrix4 { } + /** + * Writes the elements of this matrix to the given array. If no array is provided, + * the method returns a new instance. + * + * @param {Array} [array=[]] - The target array holding the matrix elements in column-major order. + * @param {number} [offset=0] - Index of the first element in the array. + * @return {Array} The matrix elements in column-major order. + */ toArray( array = [], offset = 0 ) { const te = this.elements; diff --git a/src/math/Vector2.js b/src/math/Vector2.js index eee0a1c2b2cf8a..70178036440577 100644 --- a/src/math/Vector2.js +++ b/src/math/Vector2.js @@ -1,16 +1,70 @@ import { clamp } from './MathUtils.js'; +/** + * Class representing a 2D vector. A 2D vector is an ordered pair of numbers + * (labeled x and y), which can be used to represent a number of things, such as: + * + * - A point in 2D space (i.e. a position on a plane). + * - A direction and length across a plane. In three.js the length will + * always be the Euclidean distance(straight-line distance) from `(0, 0)` to `(x, y)` + * and the direction is also measured from `(0, 0)` towards `(x, y)`. + * - Any arbitrary ordered pair of numbers. + * + * There are other things a 2D vector can be used to represent, such as + * momentum vectors, complex numbers and so on, however these are the most + * common uses in three.js. + * + * Iterating through a vector instance will yield its components `(x, y)` in + * the corresponding order. + * ```js + * const a = new THREE.Vector2( 0, 1 ); + * + * //no arguments; will be initialised to (0, 0) + * const b = new THREE.Vector2( ); + * + * const d = a.distanceTo( b ); + * ``` + */ class Vector2 { + /** + * Constructs a new 2D vector. + * + * @param {number} [x=0] - The x value of this vector. + * @param {number} [y=0] - The y value of this vector. + */ constructor( x = 0, y = 0 ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ Vector2.prototype.isVector2 = true; + /** + * The x value of this vector. + * + * @type {number} + */ this.x = x; + + /** + * The y value of this vector. + * + * @type {number} + */ this.y = y; } + /** + * Alias for {@link Vector2#x}. + * + * @type {number} + */ get width() { return this.x; @@ -23,6 +77,11 @@ class Vector2 { } + /** + * Alias for {@link Vector2#y}. + * + * @type {number} + */ get height() { return this.y; @@ -35,6 +94,13 @@ class Vector2 { } + /** + * Sets the vector components. + * + * @param {number} x - The value of the x component. + * @param {number} y - The value of the y component. + * @return {Vector2} A reference to this vector. + */ set( x, y ) { this.x = x; @@ -44,6 +110,12 @@ class Vector2 { } + /** + * Sets the vector components to the same value. + * + * @param {number} scalar - The value to set for all vector components. + * @return {Vector2} A reference to this vector. + */ setScalar( scalar ) { this.x = scalar; @@ -53,6 +125,12 @@ class Vector2 { } + /** + * Sets the vector's x component to the given value + * + * @param {number} x - The value to set. + * @return {Vector2} A reference to this vector. + */ setX( x ) { this.x = x; @@ -61,6 +139,12 @@ class Vector2 { } + /** + * Sets the vector's y component to the given value + * + * @param {number} y - The value to set. + * @return {Vector2} A reference to this vector. + */ setY( y ) { this.y = y; @@ -69,6 +153,13 @@ class Vector2 { } + /** + * Allows to set a vector component with an index. + * + * @param {number} index - The component index. `0` equals to x, `1` equals to y. + * @param {number} value - The value to set. + * @return {Vector2} A reference to this vector. + */ setComponent( index, value ) { switch ( index ) { @@ -83,6 +174,12 @@ class Vector2 { } + /** + * Returns the value of the vector component which matches the given index. + * + * @param {number} index - The component index. `0` equals to x, `1` equals to y. + * @return {number} A vector component value. + */ getComponent( index ) { switch ( index ) { @@ -95,12 +192,23 @@ class Vector2 { } + /** + * Returns a new vector with copied values from this instance. + * + * @return {Vector2} A clone of this instance. + */ clone() { return new this.constructor( this.x, this.y ); } + /** + * Copies the values of the given vector to this instance. + * + * @param {Vector2} v - The vector to copy. + * @return {Vector2} A reference to this vector. + */ copy( v ) { this.x = v.x; @@ -110,6 +218,12 @@ class Vector2 { } + /** + * Adds the given vector to this instance. + * + * @param {Vector2} v - The vector to add. + * @return {Vector2} A reference to this vector. + */ add( v ) { this.x += v.x; @@ -119,6 +233,12 @@ class Vector2 { } + /** + * Adds the given scalar value to all components of this instance. + * + * @param {number} s - The scalar to add. + * @return {Vector2} A reference to this vector. + */ addScalar( s ) { this.x += s; @@ -128,6 +248,13 @@ class Vector2 { } + /** + * Adds the given vectors and stores the result in this instance. + * + * @param {Vector2} a - The first vector. + * @param {Vector2} b - The second vector. + * @return {Vector2} A reference to this vector. + */ addVectors( a, b ) { this.x = a.x + b.x; @@ -137,6 +264,13 @@ class Vector2 { } + /** + * Adds the given vector scaled by the given factor to this instance. + * + * @param {Vector2} v - The vector. + * @param {number} s - The factor that scales `v`. + * @return {Vector2} A reference to this vector. + */ addScaledVector( v, s ) { this.x += v.x * s; @@ -146,6 +280,12 @@ class Vector2 { } + /** + * Subtracts the given vector from this instance. + * + * @param {Vector2} v - The vector to subtract. + * @return {Vector2} A reference to this vector. + */ sub( v ) { this.x -= v.x; @@ -155,6 +295,12 @@ class Vector2 { } + /** + * Subtracts the given scalar value from all components of this instance. + * + * @param {number} s - The scalar to subtract. + * @return {Vector2} A reference to this vector. + */ subScalar( s ) { this.x -= s; @@ -164,6 +310,13 @@ class Vector2 { } + /** + * Subtracts the given vectors and stores the result in this instance. + * + * @param {Vector2} a - The first vector. + * @param {Vector2} b - The second vector. + * @return {Vector2} A reference to this vector. + */ subVectors( a, b ) { this.x = a.x - b.x; @@ -173,6 +326,12 @@ class Vector2 { } + /** + * Multiplies the given vector with this instance. + * + * @param {Vector2} v - The vector to multiply. + * @return {Vector2} A reference to this vector. + */ multiply( v ) { this.x *= v.x; @@ -182,6 +341,12 @@ class Vector2 { } + /** + * Multiplies the given scalar value with all components of this instance. + * + * @param {number} scalar - The scalar to multiply. + * @return {Vector2} A reference to this vector. + */ multiplyScalar( scalar ) { this.x *= scalar; @@ -191,6 +356,12 @@ class Vector2 { } + /** + * Divides this instance by the given vector. + * + * @param {Vector2} v - The vector to divide. + * @return {Vector2} A reference to this vector. + */ divide( v ) { this.x /= v.x; @@ -200,12 +371,25 @@ class Vector2 { } + /** + * Divides this vector by the given scalar. + * + * @param {number} scalar - The scalar to divide. + * @return {Vector2} A reference to this vector. + */ divideScalar( scalar ) { return this.multiplyScalar( 1 / scalar ); } + /** + * Multiplies this vector (with an implicit 1 as the 3rd component) by + * the given 3x3 matrix. + * + * @param {Matrix3} m - The matrix to apply. + * @return {Vector2} A reference to this vector. + */ applyMatrix3( m ) { const x = this.x, y = this.y; @@ -218,6 +402,13 @@ class Vector2 { } + /** + * If this vector's x or y value is greater than the given vector's x or y + * value, replace that value with the corresponding min value. + * + * @param {Vector2} v - The vector. + * @return {Vector2} A reference to this vector. + */ min( v ) { this.x = Math.min( this.x, v.x ); @@ -227,6 +418,13 @@ class Vector2 { } + /** + * If this vector's x or y value is less than the given vector's x or y + * value, replace that value with the corresponding max value. + * + * @param {Vector2} v - The vector. + * @return {Vector2} A reference to this vector. + */ max( v ) { this.x = Math.max( this.x, v.x ); @@ -236,6 +434,16 @@ class Vector2 { } + /** + * If this vector's x or y value is greater than the max vector's x or y + * value, it is replaced by the corresponding value. + * If this vector's x or y value is less than the min vector's x or y value, + * it is replaced by the corresponding value. + * + * @param {Vector2} min - The minimum x and y values. + * @param {Vector2} max - The maximum x and y values in the desired range. + * @return {Vector2} A reference to this vector. + */ clamp( min, max ) { // assumes min < max, componentwise @@ -247,6 +455,16 @@ class Vector2 { } + /** + * If this vector's x or y values are greater than the max value, they are + * replaced by the max value. + * If this vector's x or y values are less than the min value, they are + * replaced by the min value. + * + * @param {number} minVal - The minimum value the components will be clamped to. + * @param {number} maxVal - The maximum value the components will be clamped to. + * @return {Vector2} A reference to this vector. + */ clampScalar( minVal, maxVal ) { this.x = clamp( this.x, minVal, maxVal ); @@ -256,6 +474,16 @@ class Vector2 { } + /** + * If this vector's length is greater than the max value, it is replaced by + * the max value. + * If this vector's length is less than the min value, it is replaced by the + * min value. + * + * @param {number} min - The minimum value the vector length will be clamped to. + * @param {number} max - The maximum value the vector length will be clamped to. + * @return {Vector2} A reference to this vector. + */ clampLength( min, max ) { const length = this.length(); @@ -264,6 +492,11 @@ class Vector2 { } + /** + * The components of this vector are rounded down to the nearest integer value. + * + * @return {Vector2} A reference to this vector. + */ floor() { this.x = Math.floor( this.x ); @@ -273,6 +506,11 @@ class Vector2 { } + /** + * The components of this vector are rounded up to the nearest integer value. + * + * @return {Vector2} A reference to this vector. + */ ceil() { this.x = Math.ceil( this.x ); @@ -282,6 +520,11 @@ class Vector2 { } + /** + * The components of this vector are rounded to the nearest integer value + * + * @return {Vector2} A reference to this vector. + */ round() { this.x = Math.round( this.x ); @@ -291,6 +534,12 @@ class Vector2 { } + /** + * The components of this vector are rounded towards zero (up if negative, + * down if positive) to an integer value. + * + * @return {Vector2} A reference to this vector. + */ roundToZero() { this.x = Math.trunc( this.x ); @@ -300,6 +549,11 @@ class Vector2 { } + /** + * Inverts this vector - i.e. sets x = -x and y = -y. + * + * @return {Vector2} A reference to this vector. + */ negate() { this.x = - this.x; @@ -309,52 +563,96 @@ class Vector2 { } + /** + * Calculates the dot product of the given vector with this instance. + * + * @param {Vector2} v - The vector to compute the dot product with. + * @return {number} The result of the dot product. + */ dot( v ) { return this.x * v.x + this.y * v.y; } + /** + * Calculates the cross product of the given vector with this instance. + * + * @param {Vector2} v - The vector to compute the cross product with. + * @return {Vector2} The result of the cross product. + */ cross( v ) { return this.x * v.y - this.y * v.x; } + /** + * Computes the square of the Euclidean length (straight-line length) from + * (0, 0) to (x, y). If you are comparing the lengths of vectors, you should + * compare the length squared instead as it is slightly more efficient to calculate. + * + * @return {number} The square length of this vector. + */ lengthSq() { return this.x * this.x + this.y * this.y; } + /** + * Computes the Euclidean length (straight-line length) from (0, 0) to (x, y). + * + * @return {number} The length of this vector. + */ length() { return Math.sqrt( this.x * this.x + this.y * this.y ); } + /** + * Computes the Manhattan length of this vector. + * + * @return {number} The length of this vector. + */ manhattanLength() { return Math.abs( this.x ) + Math.abs( this.y ); } + /** + * Converts this vector to a unit vector - that is, sets it equal to a vector + * with the same direction as this one, but with a vector length of `1`. + * + * @return {Vector2} A reference to this vector. + */ normalize() { return this.divideScalar( this.length() || 1 ); } + /** + * Computes the angle in radians of this vector with respect to the positive x-axis. + * + * @return {number} The angle in radians. + */ angle() { - // computes the angle in radians with respect to the positive x-axis - const angle = Math.atan2( - this.y, - this.x ) + Math.PI; return angle; } + /** + * Returns the angle between the given vector and this instance in radians. + * + * @param {Vector2} v - The vector to compute the angle with. + * @return {number} The angle in radians. + */ angleTo( v ) { const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); @@ -369,12 +667,26 @@ class Vector2 { } + /** + * Computes the distance from the given vector to this instance. + * + * @param {Vector2} v - The vector to compute the distance to. + * @return {number} The distance. + */ distanceTo( v ) { return Math.sqrt( this.distanceToSquared( v ) ); } + /** + * Computes the squared distance from the given vector to this instance. + * If you are just comparing the distance with another distance, you should compare + * the distance squared instead as it is slightly more efficient to calculate. + * + * @param {Vector2} v - The vector to compute the squared distance to. + * @return {number} The squared distance. + */ distanceToSquared( v ) { const dx = this.x - v.x, dy = this.y - v.y; @@ -382,18 +694,40 @@ class Vector2 { } + /** + * Computes the Manhattan distance from the given vector to this instance. + * + * @param {Vector2} v - The vector to compute the Manhattan distance to. + * @return {number} The Manhattan distance. + */ manhattanDistanceTo( v ) { return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); } + /** + * Sets this vector to a vector with the same direction as this one, but + * with the specified length. + * + * @param {number} length - The new length of this vector. + * @return {Vector2} A reference to this vector. + */ setLength( length ) { return this.normalize().multiplyScalar( length ); } + /** + * Linearly interpolates between the given vector and this instance, where + * alpha is the percent distance along the line - alpha = 0 will be this + * vector, and alpha = 1 will be the given one. + * + * @param {Vector2} v - The vector to interpolate towards. + * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. + * @return {Vector2} A reference to this vector. + */ lerp( v, alpha ) { this.x += ( v.x - this.x ) * alpha; @@ -403,6 +737,16 @@ class Vector2 { } + /** + * Linearly interpolates between the given vectors, where alpha is the percent + * distance along the line - alpha = 0 will be first vector, and alpha = 1 will + * be the second one. The result is stored in this instance. + * + * @param {Vector2} v1 - The first vector. + * @param {Vector2} v2 - The second vector. + * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. + * @return {Vector2} A reference to this vector. + */ lerpVectors( v1, v2, alpha ) { this.x = v1.x + ( v2.x - v1.x ) * alpha; @@ -412,12 +756,26 @@ class Vector2 { } + /** + * Returns `true` if this vector is equal with the given one. + * + * @param {Vector2} v - The vector to test for equality. + * @return {boolean} Whether this vector is equal with the given one. + */ equals( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) ); } + /** + * Sets this vector's x value to be `array[ offset ]` and y + * value to be `array[ offset + 1 ]`. + * + * @param {Array} array - An array holding the vector component values. + * @param {number} [offset=0] - The offset into the array. + * @return {Vector2} A reference to this vector. + */ fromArray( array, offset = 0 ) { this.x = array[ offset ]; @@ -427,6 +785,14 @@ class Vector2 { } + /** + * Writes the components of this vector to the given array. If no array is provided, + * the method returns a new instance. + * + * @param {Array} [array=[]] - The target array holding the vector components. + * @param {number} [offset=0] - Index of the first element in the array. + * @return {Array} The vector components. + */ toArray( array = [], offset = 0 ) { array[ offset ] = this.x; @@ -436,6 +802,13 @@ class Vector2 { } + /** + * Sets the components of this vector from the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute holding vector data. + * @param {number} index - The index into the attribute. + * @return {Vector2} A reference to this vector. + */ fromBufferAttribute( attribute, index ) { this.x = attribute.getX( index ); @@ -445,6 +818,13 @@ class Vector2 { } + /** + * Rotates this vector around the given center by the given angle. + * + * @param {Vector2} center - The point around which to rotate. + * @param {number} angle - The angle to rotate, in radians. + * @return {Vector2} A reference to this vector. + */ rotateAround( center, angle ) { const c = Math.cos( angle ), s = Math.sin( angle ); @@ -459,6 +839,12 @@ class Vector2 { } + /** + * Sets each component of this vector to a pseudo-random value between `0` and + * `1`, excluding `1`. + * + * @return {Vector2} A reference to this vector. + */ random() { this.x = Math.random(); diff --git a/src/math/Vector3.js b/src/math/Vector3.js index 5d9a390ace39ee..a8e453ce073214 100644 --- a/src/math/Vector3.js +++ b/src/math/Vector3.js @@ -1,18 +1,82 @@ import { clamp } from './MathUtils.js'; import { Quaternion } from './Quaternion.js'; +/** + * Class representing a 3D vector. A 3D vector is an ordered triplet of numbers + * (labeled x, y and z), which can be used to represent a number of things, such as: + * + * - A point in 3D space. + * - A direction and length in 3D space. In three.js the length 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)`. + * - Any arbitrary ordered triplet of numbers. + * + * There are other things a 3D vector can be used to represent, such as + * momentum vectors and so on, however these are the most + * common uses in three.js. + * + * Iterating through a vector instance will yield its components `(x, y, z)` in + * the corresponding order. + * ```js + * const a = new THREE.Vector3( 0, 1, 0 ); + * + * //no arguments; will be initialised to (0, 0, 0) + * const b = new THREE.Vector3( ); + * + * const d = a.distanceTo( b ); + * ``` + */ class Vector3 { + /** + * Constructs a new 3D vector. + * + * @param {number} [x=0] - The x value of this vector. + * @param {number} [y=0] - The y value of this vector. + * @param {number} [z=0] - The z value of this vector. + */ constructor( x = 0, y = 0, z = 0 ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ Vector3.prototype.isVector3 = true; + /** + * The x value of this vector. + * + * @type {number} + */ this.x = x; + + /** + * The y value of this vector. + * + * @type {number} + */ this.y = y; + + /** + * The z value of this vector. + * + * @type {number} + */ this.z = z; } + /** + * Sets the vector components. + * + * @param {number} x - The value of the x component. + * @param {number} y - The value of the y component. + * @param {number} z - The value of the z component. + * @return {Vector3} A reference to this vector. + */ set( x, y, z ) { if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) @@ -25,6 +89,12 @@ class Vector3 { } + /** + * Sets the vector components to the same value. + * + * @param {number} scalar - The value to set for all vector components. + * @return {Vector3} A reference to this vector. + */ setScalar( scalar ) { this.x = scalar; @@ -35,6 +105,12 @@ class Vector3 { } + /** + * Sets the vector's x component to the given value + * + * @param {number} x - The value to set. + * @return {Vector3} A reference to this vector. + */ setX( x ) { this.x = x; @@ -43,6 +119,12 @@ class Vector3 { } + /** + * Sets the vector's y component to the given value + * + * @param {number} y - The value to set. + * @return {Vector3} A reference to this vector. + */ setY( y ) { this.y = y; @@ -51,6 +133,12 @@ class Vector3 { } + /** + * Sets the vector's z component to the given value + * + * @param {number} z - The value to set. + * @return {Vector3} A reference to this vector. + */ setZ( z ) { this.z = z; @@ -59,6 +147,13 @@ class Vector3 { } + /** + * Allows to set a vector component with an index. + * + * @param {number} index - The component index. `0` equals to x, `1` equals to y, `2` equals to z. + * @param {number} value - The value to set. + * @return {Vector3} A reference to this vector. + */ setComponent( index, value ) { switch ( index ) { @@ -74,6 +169,12 @@ class Vector3 { } + /** + * Returns the value of the vector component which matches the given index. + * + * @param {number} index - The component index. `0` equals to x, `1` equals to y, `2` equals to z. + * @return {number} A vector component value. + */ getComponent( index ) { switch ( index ) { @@ -87,12 +188,23 @@ class Vector3 { } + /** + * Returns a new vector with copied values from this instance. + * + * @return {Vector3} A clone of this instance. + */ clone() { return new this.constructor( this.x, this.y, this.z ); } + /** + * Copies the values of the given vector to this instance. + * + * @param {Vector3} v - The vector to copy. + * @return {Vector3} A reference to this vector. + */ copy( v ) { this.x = v.x; @@ -103,6 +215,12 @@ class Vector3 { } + /** + * Adds the given vector to this instance. + * + * @param {Vector3} v - The vector to add. + * @return {Vector3} A reference to this vector. + */ add( v ) { this.x += v.x; @@ -113,6 +231,12 @@ class Vector3 { } + /** + * Adds the given scalar value to all components of this instance. + * + * @param {number} s - The scalar to add. + * @return {Vector3} A reference to this vector. + */ addScalar( s ) { this.x += s; @@ -123,6 +247,13 @@ class Vector3 { } + /** + * Adds the given vectors and stores the result in this instance. + * + * @param {Vector3} a - The first vector. + * @param {Vector3} b - The second vector. + * @return {Vector3} A reference to this vector. + */ addVectors( a, b ) { this.x = a.x + b.x; @@ -133,6 +264,13 @@ class Vector3 { } + /** + * Adds the given vector scaled by the given factor to this instance. + * + * @param {Vector3} v - The vector. + * @param {number} s - The factor that scales `v`. + * @return {Vector3} A reference to this vector. + */ addScaledVector( v, s ) { this.x += v.x * s; @@ -143,6 +281,12 @@ class Vector3 { } + /** + * Subtracts the given vector from this instance. + * + * @param {Vector3} v - The vector to subtract. + * @return {Vector3} A reference to this vector. + */ sub( v ) { this.x -= v.x; @@ -153,6 +297,12 @@ class Vector3 { } + /** + * Subtracts the given scalar value from all components of this instance. + * + * @param {number} s - The scalar to subtract. + * @return {Vector3} A reference to this vector. + */ subScalar( s ) { this.x -= s; @@ -163,6 +313,13 @@ class Vector3 { } + /** + * Subtracts the given vectors and stores the result in this instance. + * + * @param {Vector3} a - The first vector. + * @param {Vector3} b - The second vector. + * @return {Vector3} A reference to this vector. + */ subVectors( a, b ) { this.x = a.x - b.x; @@ -173,6 +330,12 @@ class Vector3 { } + /** + * Multiplies the given vector with this instance. + * + * @param {Vector3} v - The vector to multiply. + * @return {Vector3} A reference to this vector. + */ multiply( v ) { this.x *= v.x; @@ -183,6 +346,12 @@ class Vector3 { } + /** + * Multiplies the given scalar value with all components of this instance. + * + * @param {number} scalar - The scalar to multiply. + * @return {Vector3} A reference to this vector. + */ multiplyScalar( scalar ) { this.x *= scalar; @@ -193,6 +362,13 @@ class Vector3 { } + /** + * Multiplies the given vectors and stores the result in this instance. + * + * @param {Vector3} a - The first vector. + * @param {Vector3} b - The second vector. + * @return {Vector3} A reference to this vector. + */ multiplyVectors( a, b ) { this.x = a.x * b.x; @@ -203,18 +379,37 @@ class Vector3 { } + /** + * Applies the given Euler rotation to this vector. + * + * @param {Euler} euler - The Euler angles. + * @return {Vector3} A reference to this vector. + */ applyEuler( euler ) { return this.applyQuaternion( _quaternion.setFromEuler( euler ) ); } + /** + * Applies a rotation specified by an axis and an angle to this vector. + * + * @param {Vector3} axis - A normalized vector representing the rotation axis. + * @param {number} angle - The angle in radians. + * @return {Vector3} A reference to this vector. + */ applyAxisAngle( axis, angle ) { return this.applyQuaternion( _quaternion.setFromAxisAngle( axis, angle ) ); } + /** + * Multiplies this vector with the given 3x3 matrix. + * + * @param {Matrix3} m - The 3x3 matrix. + * @return {Vector3} A reference to this vector. + */ applyMatrix3( m ) { const x = this.x, y = this.y, z = this.z; @@ -228,12 +423,26 @@ class Vector3 { } + /** + * Multiplies this vector by the given normal matrix and normalizes + * the result. + * + * @param {Matrix3} m - The normal matrix. + * @return {Vector3} A reference to this vector. + */ applyNormalMatrix( m ) { return this.applyMatrix3( m ).normalize(); } + /** + * Multiplies this vector (with an implicit 1 in the 4th dimension) by m, and + * divides by perspective. + * + * @param {Matrix4} m - The matrix to apply. + * @return {Vector3} A reference to this vector. + */ applyMatrix4( m ) { const x = this.x, y = this.y, z = this.z; @@ -249,6 +458,12 @@ class Vector3 { } + /** + * Applies the given Quaternion to this vector. + * + * @param {Quaternion} q - The Quaternion. + * @return {Vector3} A reference to this vector. + */ applyQuaternion( q ) { // quaternion q is assumed to have unit length @@ -270,18 +485,39 @@ class Vector3 { } + /** + * Projects this vector from world space into the camera's normalized + * device coordinate (NDC) space. + * + * @param {Camera} camera - The camera. + * @return {Vector3} A reference to this vector. + */ project( camera ) { return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); } + /** + * Unprojects this vector from the camera's normalized device coordinate (NDC) + * space into world space. + * + * @param {Camera} camera - The camera. + * @return {Vector3} A reference to this vector. + */ unproject( camera ) { return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); } + /** + * Transforms the direction of this vector by a matrix (the upper left 3 x 3 + * subset of the given 4x4 matrix and then normalizes the result. + * + * @param {Matrix4} m - The matrix. + * @return {Vector3} A reference to this vector. + */ transformDirection( m ) { // input: THREE.Matrix4 affine matrix @@ -298,6 +534,12 @@ class Vector3 { } + /** + * Divides this instance by the given vector. + * + * @param {Vector3} v - The vector to divide. + * @return {Vector3} A reference to this vector. + */ divide( v ) { this.x /= v.x; @@ -308,12 +550,25 @@ class Vector3 { } + /** + * Divides this vector by the given scalar. + * + * @param {number} scalar - The scalar to divide. + * @return {Vector3} A reference to this vector. + */ divideScalar( scalar ) { return this.multiplyScalar( 1 / scalar ); } + /** + * If this vector's x, y or z value is greater than the given vector's x, y or z + * value, replace that value with the corresponding min value. + * + * @param {Vector3} v - The vector. + * @return {Vector3} A reference to this vector. + */ min( v ) { this.x = Math.min( this.x, v.x ); @@ -324,6 +579,13 @@ class Vector3 { } + /** + * If this vector's x, y or z value is less than the given vector's x, y or z + * value, replace that value with the corresponding max value. + * + * @param {Vector3} v - The vector. + * @return {Vector3} A reference to this vector. + */ max( v ) { this.x = Math.max( this.x, v.x ); @@ -334,6 +596,16 @@ class Vector3 { } + /** + * If this vector's x, y or z value is greater than the max vector's x, y or z + * value, it is replaced by the corresponding value. + * If this vector's x, y or z value is less than the min vector's x, y or z value, + * it is replaced by the corresponding value. + * + * @param {Vector3} min - The minimum x, y and z values. + * @param {Vector3} max - The maximum x, y and z values in the desired range. + * @return {Vector3} A reference to this vector. + */ clamp( min, max ) { // assumes min < max, componentwise @@ -346,6 +618,16 @@ class Vector3 { } + /** + * If this vector's x, y or z values are greater than the max value, they are + * replaced by the max value. + * If this vector's x, y or z values are less than the min value, they are + * replaced by the min value. + * + * @param {number} minVal - The minimum value the components will be clamped to. + * @param {number} maxVal - The maximum value the components will be clamped to. + * @return {Vector3} A reference to this vector. + */ clampScalar( minVal, maxVal ) { this.x = clamp( this.x, minVal, maxVal ); @@ -356,6 +638,16 @@ class Vector3 { } + /** + * If this vector's length is greater than the max value, it is replaced by + * the max value. + * If this vector's length is less than the min value, it is replaced by the + * min value. + * + * @param {number} min - The minimum value the vector length will be clamped to. + * @param {number} max - The maximum value the vector length will be clamped to. + * @return {Vector3} A reference to this vector. + */ clampLength( min, max ) { const length = this.length(); @@ -364,6 +656,11 @@ class Vector3 { } + /** + * The components of this vector are rounded down to the nearest integer value. + * + * @return {Vector3} A reference to this vector. + */ floor() { this.x = Math.floor( this.x ); @@ -374,6 +671,11 @@ class Vector3 { } + /** + * The components of this vector are rounded up to the nearest integer value. + * + * @return {Vector3} A reference to this vector. + */ ceil() { this.x = Math.ceil( this.x ); @@ -384,6 +686,11 @@ class Vector3 { } + /** + * The components of this vector are rounded to the nearest integer value + * + * @return {Vector3} A reference to this vector. + */ round() { this.x = Math.round( this.x ); @@ -394,6 +701,12 @@ class Vector3 { } + /** + * The components of this vector are rounded towards zero (up if negative, + * down if positive) to an integer value. + * + * @return {Vector3} A reference to this vector. + */ roundToZero() { this.x = Math.trunc( this.x ); @@ -404,6 +717,11 @@ class Vector3 { } + /** + * Inverts this vector - i.e. sets x = -x, y = -y and z = -z. + * + * @return {Vector3} A reference to this vector. + */ negate() { this.x = - this.x; @@ -414,6 +732,12 @@ class Vector3 { } + /** + * Calculates the dot product of the given vector with this instance. + * + * @param {Vector3} v - The vector to compute the dot product with. + * @return {number} The result of the dot product. + */ dot( v ) { return this.x * v.x + this.y * v.y + this.z * v.z; @@ -422,36 +746,75 @@ class Vector3 { // TODO lengthSquared? + /** + * Computes the square of the Euclidean length (straight-line length) from + * (0, 0, 0) to (x, y, z). If you are comparing the lengths of vectors, you should + * compare the length squared instead as it is slightly more efficient to calculate. + * + * @return {number} The square length of this vector. + */ lengthSq() { return this.x * this.x + this.y * this.y + this.z * this.z; } + /** + * Computes the Euclidean length (straight-line length) from (0, 0, 0) to (x, y, z). + * + * @return {number} The length of this vector. + */ length() { return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); } + /** + * Computes the Manhattan length of this vector. + * + * @return {number} The length of this vector. + */ manhattanLength() { return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); } + /** + * Converts this vector to a unit vector - that is, sets it equal to a vector + * with the same direction as this one, but with a vector length of `1`. + * + * @return {Vector3} A reference to this vector. + */ normalize() { return this.divideScalar( this.length() || 1 ); } + /** + * Sets this vector to a vector with the same direction as this one, but + * with the specified length. + * + * @param {number} length - The new length of this vector. + * @return {Vector3} A reference to this vector. + */ setLength( length ) { return this.normalize().multiplyScalar( length ); } + /** + * Linearly interpolates between the given vector and this instance, where + * alpha is the percent distance along the line - alpha = 0 will be this + * vector, and alpha = 1 will be the given one. + * + * @param {Vector3} v - The vector to interpolate towards. + * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. + * @return {Vector3} A reference to this vector. + */ lerp( v, alpha ) { this.x += ( v.x - this.x ) * alpha; @@ -462,6 +825,16 @@ class Vector3 { } + /** + * Linearly interpolates between the given vectors, where alpha is the percent + * distance along the line - alpha = 0 will be first vector, and alpha = 1 will + * be the second one. The result is stored in this instance. + * + * @param {Vector3} v1 - The first vector. + * @param {Vector3} v2 - The second vector. + * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. + * @return {Vector3} A reference to this vector. + */ lerpVectors( v1, v2, alpha ) { this.x = v1.x + ( v2.x - v1.x ) * alpha; @@ -472,12 +845,26 @@ class Vector3 { } + /** + * Calculates the cross product of the given vector with this instance. + * + * @param {Vector3} v - The vector to compute the cross product with. + * @return {Vector3} The result of the cross product. + */ cross( v ) { return this.crossVectors( this, v ); } + /** + * Calculates the cross product of the given vectors and stores the result + * in this instance. + * + * @param {Vector3} a - The first vector. + * @param {Vector3} b - The second vector. + * @return {Vector3} A reference to this vector. + */ crossVectors( a, b ) { const ax = a.x, ay = a.y, az = a.z; @@ -491,6 +878,12 @@ class Vector3 { } + /** + * Projects this vector onto the given one. + * + * @param {Vector3} v - The vector to project to. + * @return {Vector3} A reference to this vector. + */ projectOnVector( v ) { const denominator = v.lengthSq(); @@ -503,6 +896,13 @@ class Vector3 { } + /** + * Projects this vector onto a plane by subtracting this + * vector projected onto the plane's normal from this vector. + * + * @param {Vector3} planeNormal - The plane normal. + * @return {Vector3} A reference to this vector. + */ projectOnPlane( planeNormal ) { _vector.copy( this ).projectOnVector( planeNormal ); @@ -511,15 +911,23 @@ class Vector3 { } + /** + * Reflects this vector off a plane orthogonal to the given normal vector. + * + * @param {Vector3} normal - The (normalized) normal vector. + * @return {Vector3} A reference to this vector. + */ reflect( normal ) { - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length - return this.sub( _vector.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); } - + /** + * Returns the angle between the given vector and this instance in radians. + * + * @param {Vector3} v - The vector to compute the angle with. + * @return {number} The angle in radians. + */ angleTo( v ) { const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); @@ -534,12 +942,26 @@ class Vector3 { } + /** + * Computes the distance from the given vector to this instance. + * + * @param {Vector3} v - The vector to compute the distance to. + * @return {number} The distance. + */ distanceTo( v ) { return Math.sqrt( this.distanceToSquared( v ) ); } + /** + * Computes the squared distance from the given vector to this instance. + * If you are just comparing the distance with another distance, you should compare + * the distance squared instead as it is slightly more efficient to calculate. + * + * @param {Vector3} v - The vector to compute the squared distance to. + * @return {number} The squared distance. + */ distanceToSquared( v ) { const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; @@ -548,18 +970,38 @@ class Vector3 { } + /** + * Computes the Manhattan distance from the given vector to this instance. + * + * @param {Vector3} v - The vector to compute the Manhattan distance to. + * @return {number} The Manhattan distance. + */ manhattanDistanceTo( v ) { return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); } + /** + * Sets the vector components from the given spherical coordinates. + * + * @param {Spherical} s - The spherical coordinates. + * @return {Vector3} A reference to this vector. + */ setFromSpherical( s ) { return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); } + /** + * Sets the vector components from the given spherical coordinates. + * + * @param {number} radius - The radius. + * @param {number} phi - The phi angle in radians. + * @param {number} theta - The theta angle in radians. + * @return {Vector3} A reference to this vector. + */ setFromSphericalCoords( radius, phi, theta ) { const sinPhiRadius = Math.sin( phi ) * radius; @@ -572,12 +1014,26 @@ class Vector3 { } + /** + * Sets the vector components from the given cylindrical coordinates. + * + * @param {Cylindrical} c - The cylindrical coordinates. + * @return {Vector3} A reference to this vector. + */ setFromCylindrical( c ) { return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); } + /** + * Sets the vector components from the given cylindrical coordinates. + * + * @param {number} radius - The radius. + * @param {number} theta - The theta angle in radians. + * @param {number} y - The y value. + * @return {Vector3} A reference to this vector. + */ setFromCylindricalCoords( radius, theta, y ) { this.x = radius * Math.sin( theta ); @@ -588,6 +1044,13 @@ class Vector3 { } + /** + * Sets the vector components to the position elements of the + * given transformation matrix. + * + * @param {Matrix4} m - The 4x4 matrix. + * @return {Vector3} A reference to this vector. + */ setFromMatrixPosition( m ) { const e = m.elements; @@ -600,6 +1063,13 @@ class Vector3 { } + /** + * Sets the vector components to the scale elements of the + * given transformation matrix. + * + * @param {Matrix4} m - The 4x4 matrix. + * @return {Vector3} A reference to this vector. + */ setFromMatrixScale( m ) { const sx = this.setFromMatrixColumn( m, 0 ).length(); @@ -614,18 +1084,38 @@ class Vector3 { } + /** + * Sets the vector components from the specified matrix column. + * + * @param {Matrix4} m - The 4x4 matrix. + * @param {number} index - The column index. + * @return {Vector3} A reference to this vector. + */ setFromMatrixColumn( m, index ) { return this.fromArray( m.elements, index * 4 ); } + /** + * Sets the vector components from the specified matrix column. + * + * @param {Matrix3} m - The 3x3 matrix. + * @param {number} index - The column index. + * @return {Vector3} A reference to this vector. + */ setFromMatrix3Column( m, index ) { return this.fromArray( m.elements, index * 3 ); } + /** + * Sets the vector components from the given Euler angles. + * + * @param {Euler} e - The Euler angles to set. + * @return {Vector3} A reference to this vector. + */ setFromEuler( e ) { this.x = e._x; @@ -636,6 +1126,13 @@ class Vector3 { } + /** + * Sets the vector components from the RGB components of the + * given color. + * + * @param {Color} c - The color to set. + * @return {Vector3} A reference to this vector. + */ setFromColor( c ) { this.x = c.r; @@ -646,12 +1143,26 @@ class Vector3 { } + /** + * Returns `true` if this vector is equal with the given one. + * + * @param {Vector3} v - The vector to test for equality. + * @return {boolean} Whether this vector is equal with the given one. + */ equals( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); } + /** + * Sets this vector's x value to be `array[ offset ]`, y value to be `array[ offset + 1 ]` + * and z value to be `array[ offset + 2 ]`. + * + * @param {Array} array - An array holding the vector component values. + * @param {number} [offset=0] - The offset into the array. + * @return {Vector3} A reference to this vector. + */ fromArray( array, offset = 0 ) { this.x = array[ offset ]; @@ -662,6 +1173,14 @@ class Vector3 { } + /** + * Writes the components of this vector to the given array. If no array is provided, + * the method returns a new instance. + * + * @param {Array} [array=[]] - The target array holding the vector components. + * @param {number} [offset=0] - Index of the first element in the array. + * @return {Array} The vector components. + */ toArray( array = [], offset = 0 ) { array[ offset ] = this.x; @@ -672,6 +1191,13 @@ class Vector3 { } + /** + * Sets the components of this vector from the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute holding vector data. + * @param {number} index - The index into the attribute. + * @return {Vector3} A reference to this vector. + */ fromBufferAttribute( attribute, index ) { this.x = attribute.getX( index ); @@ -682,6 +1208,12 @@ class Vector3 { } + /** + * Sets each component of this vector to a pseudo-random value between `0` and + * `1`, excluding `1`. + * + * @return {Vector3} A reference to this vector. + */ random() { this.x = Math.random(); @@ -692,6 +1224,11 @@ class Vector3 { } + /** + * Sets this vector to a uniformly random point on a unit sphere. + * + * @return {Vector3} A reference to this vector. + */ randomDirection() { // https://mathworld.wolfram.com/SpherePointPicking.html diff --git a/src/math/Vector4.js b/src/math/Vector4.js index f7fc1b68ce295a..52c7d29407bf5f 100644 --- a/src/math/Vector4.js +++ b/src/math/Vector4.js @@ -1,18 +1,85 @@ import { clamp } from './MathUtils.js'; +/** + * Class representing a 4D vector. A 4D vector is an ordered quadruplet of numbers + * (labeled x, y, z and w), which can be used to represent a number of things, such as: + * + * - A point in 4D space. + * - A direction and length in 4D space. In three.js the length will + * always be the Euclidean distance(straight-line distance) from `(0, 0, 0, 0)` to `(x, y, z, w)` + * and the direction is also measured from `(0, 0, 0, 0)` towards `(x, y, z, w)`. + * - Any arbitrary ordered quadruplet of numbers. + * + * There are other things a 4D vector can be used to represent, however these + * are the most common uses in *three.js*. + * + * Iterating through a vector instance will yield its components `(x, y, z, w)` in + * the corresponding order. + * ```js + * const a = new THREE.Vector4( 0, 1, 0, 0 ); + * + * //no arguments; will be initialised to (0, 0, 0, 1) + * const b = new THREE.Vector4( ); + * + * const d = a.dot( b ); + * ``` + */ class Vector4 { + /** + * Constructs a new 4D vector. + * + * @param {number} [x=0] - The x value of this vector. + * @param {number} [y=0] - The y value of this vector. + * @param {number} [z=0] - The z value of this vector. + * @param {number} [w=1] - The w value of this vector. + */ constructor( x = 0, y = 0, z = 0, w = 1 ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ Vector4.prototype.isVector4 = true; + /** + * The x value of this vector. + * + * @type {number} + */ this.x = x; + + /** + * The y value of this vector. + * + * @type {number} + */ this.y = y; + + /** + * The z value of this vector. + * + * @type {number} + */ this.z = z; + + /** + * The w value of this vector. + * + * @type {number} + */ this.w = w; } + /** + * Alias for {@link Vector4#z}. + * + * @type {number} + */ get width() { return this.z; @@ -25,6 +92,11 @@ class Vector4 { } + /** + * Alias for {@link Vector4#w}. + * + * @type {number} + */ get height() { return this.w; @@ -37,6 +109,15 @@ class Vector4 { } + /** + * Sets the vector components. + * + * @param {number} x - The value of the x component. + * @param {number} y - The value of the y component. + * @param {number} z - The value of the z component. + * @param {number} w - The value of the w component. + * @return {Vector4} A reference to this vector. + */ set( x, y, z, w ) { this.x = x; @@ -48,6 +129,12 @@ class Vector4 { } + /** + * Sets the vector components to the same value. + * + * @param {number} scalar - The value to set for all vector components. + * @return {Vector4} A reference to this vector. + */ setScalar( scalar ) { this.x = scalar; @@ -59,6 +146,12 @@ class Vector4 { } + /** + * Sets the vector's x component to the given value + * + * @param {number} x - The value to set. + * @return {Vector4} A reference to this vector. + */ setX( x ) { this.x = x; @@ -67,6 +160,12 @@ class Vector4 { } + /** + * Sets the vector's y component to the given value + * + * @param {number} y - The value to set. + * @return {Vector4} A reference to this vector. + */ setY( y ) { this.y = y; @@ -75,6 +174,12 @@ class Vector4 { } + /** + * Sets the vector's z component to the given value + * + * @param {number} z - The value to set. + * @return {Vector4} A reference to this vector. + */ setZ( z ) { this.z = z; @@ -83,6 +188,12 @@ class Vector4 { } + /** + * Sets the vector's w component to the given value + * + * @param {number} w - The value to set. + * @return {Vector4} A reference to this vector. + */ setW( w ) { this.w = w; @@ -91,6 +202,14 @@ class Vector4 { } + /** + * Allows to set a vector component with an index. + * + * @param {number} index - The component index. `0` equals to x, `1` equals to y, + * `2` equals to z, `3` equals to w. + * @param {number} value - The value to set. + * @return {Vector4} A reference to this vector. + */ setComponent( index, value ) { switch ( index ) { @@ -107,6 +226,13 @@ class Vector4 { } + /** + * Returns the value of the vector component which matches the given index. + * + * @param {number} index - The component index. `0` equals to x, `1` equals to y, + * `2` equals to z, `3` equals to w. + * @return {number} A vector component value. + */ getComponent( index ) { switch ( index ) { @@ -121,12 +247,23 @@ class Vector4 { } + /** + * Returns a new vector with copied values from this instance. + * + * @return {Vector4} A clone of this instance. + */ clone() { return new this.constructor( this.x, this.y, this.z, this.w ); } + /** + * Copies the values of the given vector to this instance. + * + * @param {Vector3|Vector4} v - The vector to copy. + * @return {Vector4} A reference to this vector. + */ copy( v ) { this.x = v.x; @@ -138,6 +275,12 @@ class Vector4 { } + /** + * Adds the given vector to this instance. + * + * @param {Vector4} v - The vector to add. + * @return {Vector4} A reference to this vector. + */ add( v ) { this.x += v.x; @@ -149,6 +292,12 @@ class Vector4 { } + /** + * Adds the given scalar value to all components of this instance. + * + * @param {number} s - The scalar to add. + * @return {Vector4} A reference to this vector. + */ addScalar( s ) { this.x += s; @@ -160,6 +309,13 @@ class Vector4 { } + /** + * Adds the given vectors and stores the result in this instance. + * + * @param {Vector4} a - The first vector. + * @param {Vector4} b - The second vector. + * @return {Vector4} A reference to this vector. + */ addVectors( a, b ) { this.x = a.x + b.x; @@ -171,6 +327,13 @@ class Vector4 { } + /** + * Adds the given vector scaled by the given factor to this instance. + * + * @param {Vector4} v - The vector. + * @param {number} s - The factor that scales `v`. + * @return {Vector4} A reference to this vector. + */ addScaledVector( v, s ) { this.x += v.x * s; @@ -182,6 +345,12 @@ class Vector4 { } + /** + * Subtracts the given vector from this instance. + * + * @param {Vector4} v - The vector to subtract. + * @return {Vector4} A reference to this vector. + */ sub( v ) { this.x -= v.x; @@ -193,6 +362,12 @@ class Vector4 { } + /** + * Subtracts the given scalar value from all components of this instance. + * + * @param {number} s - The scalar to subtract. + * @return {Vector4} A reference to this vector. + */ subScalar( s ) { this.x -= s; @@ -204,6 +379,13 @@ class Vector4 { } + /** + * Subtracts the given vectors and stores the result in this instance. + * + * @param {Vector4} a - The first vector. + * @param {Vector4} b - The second vector. + * @return {Vector4} A reference to this vector. + */ subVectors( a, b ) { this.x = a.x - b.x; @@ -215,6 +397,12 @@ class Vector4 { } + /** + * Multiplies the given vector with this instance. + * + * @param {Vector4} v - The vector to multiply. + * @return {Vector4} A reference to this vector. + */ multiply( v ) { this.x *= v.x; @@ -226,6 +414,12 @@ class Vector4 { } + /** + * Multiplies the given scalar value with all components of this instance. + * + * @param {number} scalar - The scalar to multiply. + * @return {Vector4} A reference to this vector. + */ multiplyScalar( scalar ) { this.x *= scalar; @@ -237,6 +431,12 @@ class Vector4 { } + /** + * Multiplies this vector with the given 4x4 matrix. + * + * @param {Matrix4} m - The 4x4 matrix. + * @return {Vector4} A reference to this vector. + */ applyMatrix4( m ) { const x = this.x, y = this.y, z = this.z, w = this.w; @@ -251,6 +451,12 @@ class Vector4 { } + /** + * Divides this instance by the given vector. + * + * @param {Vector4} v - The vector to divide. + * @return {Vector4} A reference to this vector. + */ divide( v ) { this.x /= v.x; @@ -262,12 +468,25 @@ class Vector4 { } + /** + * Divides this vector by the given scalar. + * + * @param {number} scalar - The scalar to divide. + * @return {Vector4} A reference to this vector. + */ divideScalar( scalar ) { return this.multiplyScalar( 1 / scalar ); } + /** + * Sets the x, y and z components of this + * vector to the quaternion's axis and w to the angle. + * + * @param {Quaternion} q - The Quaternion to set. + * @return {Vector4} A reference to this vector. + */ setAxisAngleFromQuaternion( q ) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm @@ -296,6 +515,13 @@ class Vector4 { } + /** + * Sets the x, y and z components of this + * vector to the axis of rotation and w to the angle. + * + * @param {Matrix4} m - A 4x4 matrix of which the upper left 3x3 matrix is a pure rotation matrix. + * @return {Vector4} A reference to this vector. + */ setAxisAngleFromRotationMatrix( m ) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm @@ -426,6 +652,13 @@ class Vector4 { } + /** + * Sets the vector components to the position elements of the + * given transformation matrix. + * + * @param {Matrix4} m - The 4x4 matrix. + * @return {Vector4} A reference to this vector. + */ setFromMatrixPosition( m ) { const e = m.elements; @@ -439,6 +672,13 @@ class Vector4 { } + /** + * If this vector's x, y, z or w value is greater than the given vector's x, y, z or w + * value, replace that value with the corresponding min value. + * + * @param {Vector4} v - The vector. + * @return {Vector4} A reference to this vector. + */ min( v ) { this.x = Math.min( this.x, v.x ); @@ -450,6 +690,13 @@ class Vector4 { } + /** + * If this vector's x, y, z or w value is less than the given vector's x, y, z or w + * value, replace that value with the corresponding max value. + * + * @param {Vector4} v - The vector. + * @return {Vector4} A reference to this vector. + */ max( v ) { this.x = Math.max( this.x, v.x ); @@ -461,6 +708,16 @@ class Vector4 { } + /** + * If this vector's x, y, z or w value is greater than the max vector's x, y, z or w + * value, it is replaced by the corresponding value. + * If this vector's x, y, z or w value is less than the min vector's x, y, z or w value, + * it is replaced by the corresponding value. + * + * @param {Vector4} min - The minimum x, y and z values. + * @param {Vector4} max - The maximum x, y and z values in the desired range. + * @return {Vector4} A reference to this vector. + */ clamp( min, max ) { // assumes min < max, componentwise @@ -474,6 +731,16 @@ class Vector4 { } + /** + * If this vector's x, y, z or w values are greater than the max value, they are + * replaced by the max value. + * If this vector's x, y, z or w values are less than the min value, they are + * replaced by the min value. + * + * @param {number} minVal - The minimum value the components will be clamped to. + * @param {number} maxVal - The maximum value the components will be clamped to. + * @return {Vector4} A reference to this vector. + */ clampScalar( minVal, maxVal ) { this.x = clamp( this.x, minVal, maxVal ); @@ -485,6 +752,16 @@ class Vector4 { } + /** + * If this vector's length is greater than the max value, it is replaced by + * the max value. + * If this vector's length is less than the min value, it is replaced by the + * min value. + * + * @param {number} min - The minimum value the vector length will be clamped to. + * @param {number} max - The maximum value the vector length will be clamped to. + * @return {Vector4} A reference to this vector. + */ clampLength( min, max ) { const length = this.length(); @@ -493,6 +770,11 @@ class Vector4 { } + /** + * The components of this vector are rounded down to the nearest integer value. + * + * @return {Vector4} A reference to this vector. + */ floor() { this.x = Math.floor( this.x ); @@ -504,6 +786,11 @@ class Vector4 { } + /** + * The components of this vector are rounded up to the nearest integer value. + * + * @return {Vector4} A reference to this vector. + */ ceil() { this.x = Math.ceil( this.x ); @@ -515,6 +802,11 @@ class Vector4 { } + /** + * The components of this vector are rounded to the nearest integer value + * + * @return {Vector4} A reference to this vector. + */ round() { this.x = Math.round( this.x ); @@ -526,6 +818,12 @@ class Vector4 { } + /** + * The components of this vector are rounded towards zero (up if negative, + * down if positive) to an integer value. + * + * @return {Vector4} A reference to this vector. + */ roundToZero() { this.x = Math.trunc( this.x ); @@ -537,6 +835,11 @@ class Vector4 { } + /** + * Inverts this vector - i.e. sets x = -x, y = -y, z = -z, w = -w. + * + * @return {Vector4} A reference to this vector. + */ negate() { this.x = - this.x; @@ -548,42 +851,87 @@ class Vector4 { } + /** + * Calculates the dot product of the given vector with this instance. + * + * @param {Vector4} v - The vector to compute the dot product with. + * @return {number} The result of the dot product. + */ dot( v ) { return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; } + /** + * Computes the square of the Euclidean length (straight-line length) from + * (0, 0, 0, 0) to (x, y, z, w). If you are comparing the lengths of vectors, you should + * compare the length squared instead as it is slightly more efficient to calculate. + * + * @return {number} The square length of this vector. + */ lengthSq() { return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; } + /** + * Computes the Euclidean length (straight-line length) from (0, 0, 0, 0) to (x, y, z, w). + * + * @return {number} The length of this vector. + */ length() { return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); } + /** + * Computes the Manhattan length of this vector. + * + * @return {number} The length of this vector. + */ manhattanLength() { return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); } + /** + * Converts this vector to a unit vector - that is, sets it equal to a vector + * with the same direction as this one, but with a vector length of `1`. + * + * @return {Vector4} A reference to this vector. + */ normalize() { return this.divideScalar( this.length() || 1 ); } + /** + * Sets this vector to a vector with the same direction as this one, but + * with the specified length. + * + * @param {number} length - The new length of this vector. + * @return {Vector4} A reference to this vector. + */ setLength( length ) { return this.normalize().multiplyScalar( length ); } + /** + * Linearly interpolates between the given vector and this instance, where + * alpha is the percent distance along the line - alpha = 0 will be this + * vector, and alpha = 1 will be the given one. + * + * @param {Vector4} v - The vector to interpolate towards. + * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. + * @return {Vector4} A reference to this vector. + */ lerp( v, alpha ) { this.x += ( v.x - this.x ) * alpha; @@ -595,6 +943,16 @@ class Vector4 { } + /** + * Linearly interpolates between the given vectors, where alpha is the percent + * distance along the line - alpha = 0 will be first vector, and alpha = 1 will + * be the second one. The result is stored in this instance. + * + * @param {Vector4} v1 - The first vector. + * @param {Vector4} v2 - The second vector. + * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. + * @return {Vector4} A reference to this vector. + */ lerpVectors( v1, v2, alpha ) { this.x = v1.x + ( v2.x - v1.x ) * alpha; @@ -606,12 +964,26 @@ class Vector4 { } + /** + * Returns `true` if this vector is equal with the given one. + * + * @param {Vector4} v - The vector to test for equality. + * @return {boolean} Whether this vector is equal with the given one. + */ equals( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); } + /** + * Sets this vector's x value to be `array[ offset ]`, y value to be `array[ offset + 1 ]`, + * z value to be `array[ offset + 2 ]`, w value to be `array[ offset + 3 ]`. + * + * @param {Array} array - An array holding the vector component values. + * @param {number} [offset=0] - The offset into the array. + * @return {Vector4} A reference to this vector. + */ fromArray( array, offset = 0 ) { this.x = array[ offset ]; @@ -623,6 +995,14 @@ class Vector4 { } + /** + * Writes the components of this vector to the given array. If no array is provided, + * the method returns a new instance. + * + * @param {Array} [array=[]] - The target array holding the vector components. + * @param {number} [offset=0] - Index of the first element in the array. + * @return {Array} The vector components. + */ toArray( array = [], offset = 0 ) { array[ offset ] = this.x; @@ -634,6 +1014,13 @@ class Vector4 { } + /** + * Sets the components of this vector from the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute holding vector data. + * @param {number} index - The index into the attribute. + * @return {Vector4} A reference to this vector. + */ fromBufferAttribute( attribute, index ) { this.x = attribute.getX( index ); @@ -645,6 +1032,12 @@ class Vector4 { } + /** + * Sets each component of this vector to a pseudo-random value between `0` and + * `1`, excluding `1`. + * + * @return {Vector4} A reference to this vector. + */ random() { this.x = Math.random(); diff --git a/utils/docs/jsdoc.config.json b/utils/docs/jsdoc.config.json index 2b1dc94bcde7a1..65395146ab2a37 100644 --- a/utils/docs/jsdoc.config.json +++ b/utils/docs/jsdoc.config.json @@ -19,7 +19,7 @@ "src/materials/nodes", "src/materials/Material.js", "src/nodes", - "src/math/Box3.js", + "src/math", "src/renderers/common", "src/renderers/webgpu" , "src/scenes" , From 941232c14b40a799a1c4158acc27349395b81960 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sat, 22 Feb 2025 11:09:05 +0100 Subject: [PATCH 2/3] Docs: More JSDoc. --- src/math/Cylindrical.js | 71 ++++++++++++-- src/math/Frustum.js | 83 ++++++++++++++++ src/math/Line3.js | 94 ++++++++++++++++++ src/math/Plane.js | 166 +++++++++++++++++++++++++++++++- src/math/Spherical.js | 78 +++++++++++++-- src/math/SphericalHarmonics3.js | 126 +++++++++++++++++++++--- 6 files changed, 588 insertions(+), 30 deletions(-) diff --git a/src/math/Cylindrical.js b/src/math/Cylindrical.js index d1288244c0a7ef..920296f7527a3c 100644 --- a/src/math/Cylindrical.js +++ b/src/math/Cylindrical.js @@ -1,19 +1,52 @@ /** - * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system + * This class can be used to represent points in 3D space as + * [Cylindrical coordinates]{@link https://en.wikipedia.org/wiki/Cylindrical_coordinate_system}. */ - class Cylindrical { + /** + * Constructs a new cylindrical. + * + * @param {number} [radius=1] - The distance from the origin to a point in the x-z plane. + * @param {number} [theta=0] - A counterclockwise angle in the x-z plane measured in radians from the positive z-axis. + * @param {number} [y=0] - The height above the x-z plane. + */ constructor( radius = 1, theta = 0, y = 0 ) { - this.radius = radius; // distance from the origin to a point in the x-z plane - this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis - this.y = y; // height above the x-z plane + /** + * The distance from the origin to a point in the x-z plane. + * + * @type {number} + * @default 1 + */ + this.radius = radius; - return this; + /** + * A counterclockwise angle in the x-z plane measured in radians from the positive z-axis. + * + * @type {number} + * @default 0 + */ + this.theta = theta; + + /** + * The height above the x-z plane. + * + * @type {number} + * @default 0 + */ + this.y = y; } + /** + * Sets the cylindrical components by copying the given values. + * + * @param {number} radius - The radius. + * @param {number} theta - The theta angle. + * @param {number} y - The height value. + * @return {Cylindrical} A reference to this cylindrical. + */ set( radius, theta, y ) { this.radius = radius; @@ -24,6 +57,12 @@ class Cylindrical { } + /** + * Copies the values of the given cylindrical to this instance. + * + * @param {Cylindrical} other - The cylindrical to copy. + * @return {Cylindrical} A reference to this cylindrical. + */ copy( other ) { this.radius = other.radius; @@ -34,12 +73,27 @@ class Cylindrical { } + /** + * Sets the cylindrical components from the given vector which is assumed to hold + * Cartesian coordinates. + * + * @param {Vector3} v - The vector to set. + * @return {Cylindrical} A reference to this cylindrical. + */ setFromVector3( v ) { return this.setFromCartesianCoords( v.x, v.y, v.z ); } + /** + * Sets the cylindrical components from the given Cartesian coordinates. + * + * @param {number} x - The x value. + * @param {number} y - The x value. + * @param {number} z - The x value. + * @return {Cylindrical} A reference to this cylindrical. + */ setFromCartesianCoords( x, y, z ) { this.radius = Math.sqrt( x * x + z * z ); @@ -50,6 +104,11 @@ class Cylindrical { } + /** + * Returns a new cylindrical with copied values from this instance. + * + * @return {Cylindrical} A clone of this instance. + */ clone() { return new this.constructor().copy( this ); diff --git a/src/math/Frustum.js b/src/math/Frustum.js index 3bb0e8f8d1d8ae..b33598ae3d7b04 100644 --- a/src/math/Frustum.js +++ b/src/math/Frustum.js @@ -6,14 +6,47 @@ import { Plane } from './Plane.js'; const _sphere = /*@__PURE__*/ new Sphere(); const _vector = /*@__PURE__*/ new Vector3(); +/** + * Frustums are used to determine what is inside the camera's field of view. + * They help speed up the rendering process - objects which lie outside a camera's + * frustum can safely be excluded from rendering. + * + * This class is mainly intended for use internally by a renderer. + */ class Frustum { + /** + * Constructs a new frustum. + * + * @param {Plane} [p0] - The first plane that encloses the frustum. + * @param {Plane} [p1] - The second plane that encloses the frustum. + * @param {Plane} [p2] - The third plane that encloses the frustum. + * @param {Plane} [p3] - The fourth plane that encloses the frustum. + * @param {Plane} [p4] - The fifth plane that encloses the frustum. + * @param {Plane} [p5] - The sixth plane that encloses the frustum. + */ constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) { + /** + * This array holds the planes that enclose the frustum. + * + * @type {Array} + */ this.planes = [ p0, p1, p2, p3, p4, p5 ]; } + /** + * Sets the frustum planens by copying the given planes. + * + * @param {Plane} [p0] - The first plane that encloses the frustum. + * @param {Plane} [p1] - The second plane that encloses the frustum. + * @param {Plane} [p2] - The third plane that encloses the frustum. + * @param {Plane} [p3] - The fourth plane that encloses the frustum. + * @param {Plane} [p4] - The fifth plane that encloses the frustum. + * @param {Plane} [p5] - The sixth plane that encloses the frustum. + * @return {Frustum} A reference to this frustum. + */ set( p0, p1, p2, p3, p4, p5 ) { const planes = this.planes; @@ -29,6 +62,12 @@ class Frustum { } + /** + * Copies the values of the given frustum to this instance. + * + * @param {Frustum} frustum - The frustum to copy. + * @return {Frustum} A reference to this frustum. + */ copy( frustum ) { const planes = this.planes; @@ -43,6 +82,13 @@ class Frustum { } + /** + * Sets the frustum planes from the given projection matrix. + * + * @param {Matrix4} m - The projection matrix. + * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} coordinateSystem - The coordinate system. + * @return {Frustum} A reference to this frustum. + */ setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) { const planes = this.planes; @@ -76,6 +122,14 @@ class Frustum { } + /** + * Returns `true` if the 3D object's bounding sphere is intersecting this frustum. + * + * Note that the 3D object must have a geometry so that the bounding sphere can be calculated. + * + * @param {Object3D} object - The 3D object to test. + * @return {boolean} Whether the 3D object's bounding sphere is intersecting this frustum or not. + */ intersectsObject( object ) { if ( object.boundingSphere !== undefined ) { @@ -98,6 +152,12 @@ class Frustum { } + /** + * Returns `true` if the given sprite is intersecting this frustum. + * + * @param {Sprite} sprite - The sprite to test. + * @return {boolean} Whether the sprite is intersecting this frustum or not. + */ intersectsSprite( sprite ) { _sphere.center.set( 0, 0, 0 ); @@ -108,6 +168,12 @@ class Frustum { } + /** + * Returns `true` if the given bounding sphere is intersecting this frustum. + * + * @param {Sphere} sphere - The bounding sphere to test. + * @return {boolean} Whether the bounding sphere is intersecting this frustum or not. + */ intersectsSphere( sphere ) { const planes = this.planes; @@ -130,6 +196,12 @@ class Frustum { } + /** + * Returns `true` if the given bounding box is intersecting this frustum. + * + * @param {Box3} box - The bounding box to test. + * @return {boolean} Whether the bounding box is intersecting this frustum or not. + */ intersectsBox( box ) { const planes = this.planes; @@ -156,6 +228,12 @@ class Frustum { } + /** + * Returns `true` if the given point lies within the frustum. + * + * @param {Vector3} point - The point to test. + * @return {boolean} Whether the point liest within this frustum or not. + */ containsPoint( point ) { const planes = this.planes; @@ -174,6 +252,11 @@ class Frustum { } + /** + * Returns a new frustum with copied values from this instance. + * + * @return {Frustum} A clone of this instance. + */ clone() { return new this.constructor().copy( this ); diff --git a/src/math/Line3.js b/src/math/Line3.js index aa33e9c1cdf8ee..20a0f4bea5e9eb 100644 --- a/src/math/Line3.js +++ b/src/math/Line3.js @@ -4,15 +4,42 @@ import { clamp } from './MathUtils.js'; const _startP = /*@__PURE__*/ new Vector3(); const _startEnd = /*@__PURE__*/ new Vector3(); +/** + * An analytical line segment in 3D space represented by a start and end point. + */ class Line3 { + /** + * Constructs a new line segment. + * + * @param {Vector3} [start=(0,0,0)] - Start of the line segment. + * @param {Vector3} [end=(0,0,0)] - End of the line segment. + */ constructor( start = new Vector3(), end = new Vector3() ) { + /** + * Start of the line segment. + * + * @type {Vector3} + */ this.start = start; + + /** + * End of the line segment. + * + * @type {Vector3} + */ this.end = end; } + /** + * Sets the start and end values by copying the given vectors. + * + * @param {Vector3} start - The start point. + * @param {Vector3} end - The end point. + * @return {Line3} A reference to this line segment. + */ set( start, end ) { this.start.copy( start ); @@ -22,6 +49,12 @@ class Line3 { } + /** + * Copies the values of the given line segment to this instance. + * + * @param {Line3} line - The line segment to copy. + * @return {Line3} A reference to this line segment. + */ copy( line ) { this.start.copy( line.start ); @@ -31,36 +64,72 @@ class Line3 { } + /** + * Returns the center of the line segment. + * + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The center point. + */ getCenter( target ) { return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); } + /** + * Returns the delta vector of the line segment's start and end point. + * + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The delta vector. + */ delta( target ) { return target.subVectors( this.end, this.start ); } + /** + * Returns the squared Euclidean distance between the line' start and end point. + * + * @return {Vector3} The squared Euclidean distance. + */ distanceSq() { return this.start.distanceToSquared( this.end ); } + /** + * Returns the Euclidean distance between the line' start and end point. + * + * @return {Vector3} The Euclidean distance. + */ distance() { return this.start.distanceTo( this.end ); } + /** + * Returns a vector at a certain position along the line segment. + * + * @param {Vector3} t - A value between `[0,1]` to represent a position along the line segment. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The delta vector. + */ at( t, target ) { return this.delta( target ).multiplyScalar( t ).add( this.start ); } + /** + * Returns a point parameter based on the closest point as projected on the line segment. + * + * @param {Vector3} point - The point for which to return a point parameter. + * @param {boolean} clampToLine - Whether to clamp the result to the range `[0,1]` or not. + * @return {number} The point parameter. + */ closestPointToPointParameter( point, clampToLine ) { _startP.subVectors( point, this.start ); @@ -81,6 +150,14 @@ class Line3 { } + /** + * Returns the closets point on the line for a given point. + * + * @param {Vector3} point - The point to compute the closest point on the line for. + * @param {boolean} clampToLine - Whether to clamp the result to the range `[0,1]` or not. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The closest point on the line. + */ closestPointToPoint( point, clampToLine, target ) { const t = this.closestPointToPointParameter( point, clampToLine ); @@ -89,6 +166,12 @@ class Line3 { } + /** + * Applies a 4x4 transformation matrix to this line segment. + * + * @param {Matrix4} matrix - The transformation matrix. + * @return {Line3} A reference to this line segment. + */ applyMatrix4( matrix ) { this.start.applyMatrix4( matrix ); @@ -98,12 +181,23 @@ class Line3 { } + /** + * Returns `true` if this line segment is equal with the given one. + * + * @param {Line3} line - The line segment to test for equality. + * @return {boolean} Whether this line segment is equal with the given one. + */ equals( line ) { return line.start.equals( this.start ) && line.end.equals( this.end ); } + /** + * Returns a new line segment with copied values from this instance. + * + * @return {Line3} A clone of this instance. + */ clone() { return new this.constructor().copy( this ); diff --git a/src/math/Plane.js b/src/math/Plane.js index d8f2fd43e36232..ab5688855daba3 100644 --- a/src/math/Plane.js +++ b/src/math/Plane.js @@ -5,19 +5,54 @@ const _vector1 = /*@__PURE__*/ new Vector3(); const _vector2 = /*@__PURE__*/ new Vector3(); const _normalMatrix = /*@__PURE__*/ new Matrix3(); +/** + * A two dimensional surface that extends infinitely in 3D space, represented + * in [Hessian normal form]{@link http://mathworld.wolfram.com/HessianNormalForm.html} + * by a unit length normal vector and a constant. + */ class Plane { + /** + * Constructs a new plane. + * + * @param {Vector3} [normal=(1,0,0)] - A unit length vector defining the normal of the plane. + * @param {number} [constant=0] - The signed distance from the origin to the plane. + */ constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ this.isPlane = true; - // normal is assumed to be normalized - + /** + * A unit length vector defining the normal of the plane. + * + * @type {Vector3} + */ this.normal = normal; + + /** + * The signed distance from the origin to the plane. + * + * @type {number} + * @default 0 + */ this.constant = constant; } + /** + * Sets the plane components by copying the given values. + * + * @param {Vector3} normal - The normal. + * @param {number} constant - The constant. + * @return {Plane} A reference to this plane. + */ set( normal, constant ) { this.normal.copy( normal ); @@ -27,6 +62,16 @@ class Plane { } + /** + * Sets the plane components by defining `x`, `y`, `z` as the + * plane normal and `w` as the constant. + * + * @param {number} x - The value for the normal's x component. + * @param {number} y - The value for the normal's y component. + * @param {number} z - The value for the normal's z component. + * @param {number} w - The constant value. + * @return {Plane} A reference to this plane. + */ setComponents( x, y, z, w ) { this.normal.set( x, y, z ); @@ -36,6 +81,14 @@ class Plane { } + /** + * Sets the plane from the given normal and coplanar point (that is a point + * that lies onto the plane). + * + * @param {Vector3} normal - The normal. + * @param {Vector3} point - A coplanar point. + * @return {Plane} A reference to this plane. + */ setFromNormalAndCoplanarPoint( normal, point ) { this.normal.copy( normal ); @@ -45,6 +98,16 @@ class Plane { } + /** + * Sets the plane from three coplanar points. The winding order is + * assumed to be counter-clockwise, and determines the direction of + * the plane normal. + * + * @param {Vector3} a - The first coplanar point. + * @param {Vector3} b - The second coplanar point. + * @param {Vector3} c - The third coplanar point. + * @return {Plane} A reference to this plane. + */ setFromCoplanarPoints( a, b, c ) { const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize(); @@ -57,6 +120,12 @@ class Plane { } + /** + * Copies the values of the given plane to this instance. + * + * @param {Plane} plane - The plane to copy. + * @return {Plane} A reference to this plane. + */ copy( plane ) { this.normal.copy( plane.normal ); @@ -66,6 +135,11 @@ class Plane { } + /** + * Normalizes the plane normal and adjusts the constant accordingly. + * + * @return {Plane} A reference to this plane. + */ normalize() { // Note: will lead to a divide by zero if the plane is invalid. @@ -78,6 +152,11 @@ class Plane { } + /** + * Negates both the plane normal and the constant. + * + * @return {Plane} A reference to this plane. + */ negate() { this.constant *= - 1; @@ -87,24 +166,52 @@ class Plane { } + /** + * Returns the signed distance from the given point to this plane. + * + * @param {Vector3} point - The point to compute the distance for. + * @return {number} The signed distance. + */ distanceToPoint( point ) { return this.normal.dot( point ) + this.constant; } + /** + * Returns the signed distance from the given sphere to this plane. + * + * @param {Sphere} sphere - The sphere to compute the distance for. + * @return {number} The signed distance. + */ distanceToSphere( sphere ) { return this.distanceToPoint( sphere.center ) - sphere.radius; } + /** + * Projects a the given point onto the plane. + * + * @param {Vector3} point - The point to project. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The projected point on the plane. + */ projectPoint( point, target ) { return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) ); } + /** + * Returns the intersection point of the passed line and the plane. Returns + * `null` if the line does not intersect. Returns the line's starting point if + * the line is coplanar with the plane. + * + * @param {Line3} line - The line to compute the intersection for. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {?Vector3} The intersection point. + */ intersectLine( line, target ) { const direction = line.delta( _vector1 ); @@ -137,6 +244,12 @@ class Plane { } + /** + * Returns `true` if the given line segment intersects with (passes through) the plane. + * + * @param {Line3} line - The line to test. + * @return {boolean} Whether the given line segment intersects with the plane or not. + */ intersectsLine( line ) { // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. @@ -148,24 +261,55 @@ class Plane { } + /** + * Returns `true` if the given bounding box intersects with the plane. + * + * @param {Box3} box - The bounding box to test. + * @return {boolean} Whether the given bounding box intersects with the plane or not. + */ intersectsBox( box ) { return box.intersectsPlane( this ); } + /** + * Returns `true` if the given bounding sphere intersects with the plane. + * + * @param {Sphere} sphere - The bounding sphere to test. + * @return {boolean} Whether the given bounding sphere intersects with the plane or not. + */ intersectsSphere( sphere ) { return sphere.intersectsPlane( this ); } + /** + * Returns a coplanar vector to the plane, by calculating the + * projection of the normal at the origin onto the plane. + * + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {boolean} The coplanar point. + */ coplanarPoint( target ) { return target.copy( this.normal ).multiplyScalar( - this.constant ); } + /** + * Apply a 4x4 matrix to the plane. The matrix must be an affine, homogeneous transform. + * + * The optional normal matrix can be pre-computed like so: + * ```js + * const optionalNormalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); + * ``` + * + * @param {Matrix4} matrix - The transformation matrix. + * @param {Matrix4} [optionalNormalMatrix] - A pre-computed normal matrix. + * @return {Plane} A reference to this plane. + */ applyMatrix4( matrix, optionalNormalMatrix ) { const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix ); @@ -180,6 +324,13 @@ class Plane { } + /** + * Translates the plane by the distance defined by the given offset vector. + * Note that this only affects the plane constant and will not affect the normal vector. + * + * @param {Vector3} offset - The offset vector. + * @return {Plane} A reference to this plane. + */ translate( offset ) { this.constant -= offset.dot( this.normal ); @@ -188,12 +339,23 @@ class Plane { } + /** + * Returns `true` if this plane is equal with the given one. + * + * @param {Plane} plane - The plane to test for equality. + * @return {boolean} Whether this plane is equal with the given one. + */ equals( plane ) { return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); } + /** + * Returns a new plane with copied values from this instance. + * + * @return {Plane} A clone of this instance. + */ clone() { return new this.constructor().copy( this ); diff --git a/src/math/Spherical.js b/src/math/Spherical.js index c4050651a25379..6a4bd6b6c1cb02 100644 --- a/src/math/Spherical.js +++ b/src/math/Spherical.js @@ -1,23 +1,54 @@ import { clamp } from './MathUtils.js'; /** - * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system - * - * phi (the polar angle) is measured from the positive y-axis. The positive y-axis is up. - * theta (the azimuthal angle) is measured from the positive z-axis. + * This class can be used to represent points in 3D space as + * [Spherical coordinates]{@link https://en.wikipedia.org/wiki/Spherical_coordinate_system}. */ class Spherical { + /** + * Constructs a new spherical. + * + * @param {number} [radius=1] - The radius, or the Euclidean distance (straight-line distance) from the point to the origin. + * @param {number} [phi=0] - The polar angle in radians from the y (up) axis. + * @param {number} [theta=0] - The equator/azimuthal angle in radians around the y (up) axis. + */ constructor( radius = 1, phi = 0, theta = 0 ) { + /** + * The radius, or the Euclidean distance (straight-line distance) from the point to the origin. + * + * @type {number} + * @default 1 + */ this.radius = radius; - this.phi = phi; // polar angle - this.theta = theta; // azimuthal angle - return this; + /** + * The polar angle in radians from the y (up) axis. + * + * @type {number} + * @default 0 + */ + this.phi = phi; + + /** + * The equator/azimuthal angle in radians around the y (up) axis. + * + * @type {number} + * @default 0 + */ + this.theta = theta; } + /** + * Sets the spherical components by copying the given values. + * + * @param {number} radius - The radius. + * @param {number} phi - The polar angle. + * @param {number} theta - The azimuthal angle. + * @return {Spherical} A reference to this spherical. + */ set( radius, phi, theta ) { this.radius = radius; @@ -28,6 +59,12 @@ class Spherical { } + /** + * Copies the values of the given spherical to this instance. + * + * @param {Spherical} other - The spherical to copy. + * @return {Spherical} A reference to this spherical. + */ copy( other ) { this.radius = other.radius; @@ -38,7 +75,12 @@ class Spherical { } - // restrict phi to be between EPS and PI-EPS + /** + * Restricts the polar angle [page:.phi phi] to be between `0.000001` and pi - + * `0.000001`. + * + * @return {Spherical} A reference to this spherical. + */ makeSafe() { const EPS = 0.000001; @@ -48,12 +90,27 @@ class Spherical { } + /** + * Sets the spherical components from the given vector which is assumed to hold + * Cartesian coordinates. + * + * @param {Vector3} v - The vector to set. + * @return {Spherical} A reference to this spherical. + */ setFromVector3( v ) { return this.setFromCartesianCoords( v.x, v.y, v.z ); } + /** + * Sets the spherical components from the given Cartesian coordinates. + * + * @param {number} x - The x value. + * @param {number} y - The x value. + * @param {number} z - The x value. + * @return {Spherical} A reference to this spherical. + */ setFromCartesianCoords( x, y, z ) { this.radius = Math.sqrt( x * x + y * y + z * z ); @@ -74,6 +131,11 @@ class Spherical { } + /** + * Returns a new spherical with copied values from this instance. + * + * @return {Spherical} A clone of this instance. + */ clone() { return new this.constructor().copy( this ); diff --git a/src/math/SphericalHarmonics3.js b/src/math/SphericalHarmonics3.js index 5ec3610534b071..87da0d5ac76b26 100644 --- a/src/math/SphericalHarmonics3.js +++ b/src/math/SphericalHarmonics3.js @@ -1,21 +1,33 @@ import { Vector3 } from './Vector3.js'; /** - * Primary reference: - * https://graphics.stanford.edu/papers/envmap/envmap.pdf + * Represents a third-order spherical harmonics (SH). Light probes use this class + * to encode lighting information. * - * Secondary reference: - * https://www.ppsloan.org/publications/StupidSH36.pdf + * - Primary reference: {@link https://graphics.stanford.edu/papers/envmap/envmap.pdf} + * - Secondary reference: {@link https://www.ppsloan.org/publications/StupidSH36.pdf} */ - -// 3-band SH defined by 9 coefficients - class SphericalHarmonics3 { + /** + * Constructs a new spherical harmonics. + */ constructor() { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ this.isSphericalHarmonics3 = true; + /** + * An array holding the (9) SH coefficients. + * + * @type {Array} + */ this.coefficients = []; for ( let i = 0; i < 9; i ++ ) { @@ -26,6 +38,13 @@ class SphericalHarmonics3 { } + /** + * Sets the given SH coefficients to this instance by copying + * the values. + * + * @param {Array} coefficients - The SH coefficients. + * @return {SphericalHarmonics3} A reference to this spherical harmonics. + */ set( coefficients ) { for ( let i = 0; i < 9; i ++ ) { @@ -38,6 +57,11 @@ class SphericalHarmonics3 { } + /** + * Sets all SH coefficients to `0`. + * + * @return {SphericalHarmonics3} A reference to this spherical harmonics. + */ zero() { for ( let i = 0; i < 9; i ++ ) { @@ -50,8 +74,13 @@ class SphericalHarmonics3 { } - // get the radiance in the direction of the normal - // target is a Vector3 + /** + * Returns the radiance in the direction of the given normal. + * + * @param {Vector3} normal - The normal vector (assumed to be unit length) + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The radiance. + */ getAt( normal, target ) { // normal is assumed to be unit length @@ -79,9 +108,14 @@ class SphericalHarmonics3 { } - // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal - // target is a Vector3 - // https://graphics.stanford.edu/papers/envmap/envmap.pdf + /** + * Returns the irradiance (radiance convolved with cosine lobe) in the + * direction of the given normal. + * + * @param {Vector3} normal - The normal vector (assumed to be unit length) + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The irradiance. + */ getIrradianceAt( normal, target ) { // normal is assumed to be unit length @@ -109,6 +143,12 @@ class SphericalHarmonics3 { } + /** + * Adds the given SH to this instance. + * + * @param {SphericalHarmonics3} sh - The SH to add. + * @return {SphericalHarmonics3} A reference to this spherical harmonics. + */ add( sh ) { for ( let i = 0; i < 9; i ++ ) { @@ -121,6 +161,14 @@ class SphericalHarmonics3 { } + /** + * A convenience method for performing {@link SphericalHarmonics3#add} and + * {@link SphericalHarmonics3#scale} at once. + * + * @param {SphericalHarmonics3} sh - The SH to add. + * @param {number} s - The scale factor. + * @return {SphericalHarmonics3} A reference to this spherical harmonics. + */ addScaledSH( sh, s ) { for ( let i = 0; i < 9; i ++ ) { @@ -133,6 +181,12 @@ class SphericalHarmonics3 { } + /** + * Scales this SH by the given scale factor. + * + * @param {number} s - The scale factor. + * @return {SphericalHarmonics3} A reference to this spherical harmonics. + */ scale( s ) { for ( let i = 0; i < 9; i ++ ) { @@ -145,6 +199,14 @@ class SphericalHarmonics3 { } + /** + * Linear interpolates between the given SH and this instance by the given + * alpha factor. + * + * @param {SphericalHarmonics3} sh - The SH to interpolate with. + * @param {number} alpha - The alpha factor. + * @return {SphericalHarmonics3} A reference to this spherical harmonics. + */ lerp( sh, alpha ) { for ( let i = 0; i < 9; i ++ ) { @@ -157,6 +219,12 @@ class SphericalHarmonics3 { } + /** + * Returns `true` if this spherical harmonics is equal with the given one. + * + * @param {SphericalHarmonics3} sh - The spherical harmonics to test for equality. + * @return {boolean} Whether this spherical harmonics is equal with the given one. + */ equals( sh ) { for ( let i = 0; i < 9; i ++ ) { @@ -173,18 +241,36 @@ class SphericalHarmonics3 { } + /** + * Copies the values of the given spherical harmonics to this instance. + * + * @param {SphericalHarmonics3} sh - The spherical harmonics to copy. + * @return {SphericalHarmonics3} A reference to this spherical harmonics. + */ copy( sh ) { return this.set( sh.coefficients ); } + /** + * Returns a new spherical harmonics with copied values from this instance. + * + * @return {SphericalHarmonics3} A clone of this instance. + */ clone() { return new this.constructor().copy( this ); } + /** + * Sets the SH coefficients of this instance from the given array. + * + * @param {Array} array - An array holding the SH coefficients. + * @param {number} [offset=0] - The array offset where to start copying. + * @return {SphericalHarmonics3} A clone of this instance. + */ fromArray( array, offset = 0 ) { const coefficients = this.coefficients; @@ -199,6 +285,14 @@ class SphericalHarmonics3 { } + /** + * Returns an array with the SH coefficients, or copies them into the provided + * array. The coefficients are represented as numbers. + * + * @param {Array} [array=[]] - The target array. + * @param {number} [offset=0] - The array offset where to start copying. + * @return {Array} An array with flat SH coefficients. + */ toArray( array = [], offset = 0 ) { const coefficients = this.coefficients; @@ -213,8 +307,12 @@ class SphericalHarmonics3 { } - // evaluate the basis functions - // shBasis is an Array[ 9 ] + /** + * Computes the SH basis for the given normal vector. + * + * @param {Vector3} normal - The normal. + * @param {Array} shBasis - The target array holding the SH basis. + */ static getBasisAt( normal, shBasis ) { // normal is assumed to be unit length From fb8d8084fea8708746abc5a5dec830fd3f6d85e5 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sat, 22 Feb 2025 17:40:56 +0100 Subject: [PATCH 3/3] Docs: More JSDoc. --- src/math/Color.js | 343 ++++++++++++++++++ src/math/Euler.js | 141 ++++++- src/math/Interpolant.js | 95 ++++- src/math/MathUtils.js | 201 +++++++++- src/math/Quaternion.js | 268 +++++++++++++- src/math/Ray.js | 160 ++++++++ src/math/Sphere.js | 147 ++++++++ src/math/Triangle.js | 208 ++++++++++- src/math/interpolants/CubicInterpolant.js | 11 +- src/math/interpolants/DiscreteInterpolant.js | 12 +- src/math/interpolants/LinearInterpolant.js | 13 + .../QuaternionLinearInterpolant.js | 11 +- 12 files changed, 1567 insertions(+), 43 deletions(-) diff --git a/src/math/Color.js b/src/math/Color.js index 5f0bad7d438884..0b0af78c0ca1d5 100644 --- a/src/math/Color.js +++ b/src/math/Color.js @@ -41,20 +41,110 @@ function hue2rgb( p, q, t ) { } +/** + * A Color instance is represented by RGB components in the linear working + * color space, which defaults to `LinearSRGBColorSpace`. Inputs + * conventionally using `SRGBColorSpace` (such as hexadecimals and CSS + * strings) are converted to the working color space automatically. + * + * ```js + * // converted automatically from SRGBColorSpace to LinearSRGBColorSpace + * const color = new THREE.Color().setHex( 0x112233 ); + * ``` + * Source color spaces may be specified explicitly, to ensure correct conversions. + * ```js + * // assumed already LinearSRGBColorSpace; no conversion + * const color = new THREE.Color().setRGB( 0.5, 0.5, 0.5 ); + * + * // converted explicitly from SRGBColorSpace to LinearSRGBColorSpace + * const color = new THREE.Color().setRGB( 0.5, 0.5, 0.5, SRGBColorSpace ); + * ``` + * If THREE.ColorManagement is disabled, no conversions occur. For details, + * see Color management. Iterating through a Color instance will yield + * its components (r, g, b) in the corresponding order. A Color can be initialised + * in any of the following ways: + * ```js + * //empty constructor - will default white + * const color1 = new THREE.Color(); + * + * //Hexadecimal color (recommended) + * const color2 = new THREE.Color( 0xff0000 ); + * + * //RGB string + * const color3 = new THREE.Color("rgb(255, 0, 0)"); + * const color4 = new THREE.Color("rgb(100%, 0%, 0%)"); + * + * //X11 color name - all 140 color names are supported. + * //Note the lack of CamelCase in the name + * const color5 = new THREE.Color( 'skyblue' ); + * //HSL string + * const color6 = new THREE.Color("hsl(0, 100%, 50%)"); + * + * //Separate RGB values between 0 and 1 + * const color7 = new THREE.Color( 1, 0, 0 ); + * ``` + */ class Color { + /** + * Constructs a new color. + * + * Note that standard method of specifying color in three.js is with a hexadecimal triplet, + * and that method is used throughout the rest of the documentation. + * + * @param {(number|string|Color)} [r] - The red component of the color. If `g` and `b` are + * not provided, it can be hexadecimal triplet, a CSS-style string or another `Color` instance. + * @param {number} [g] - The green component. + * @param {number} [b] - The blue component. + */ constructor( r, g, b ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ this.isColor = true; + /** + * The red component. + * + * @type {number} + * @default 1 + */ this.r = 1; + + /** + * The green component. + * + * @type {number} + * @default 1 + */ this.g = 1; + + /** + * The blue component. + * + * @type {number} + * @default 1 + */ this.b = 1; return this.set( r, g, b ); } + /** + * Sets the colors's components from the given values. + * + * @param {(number|string|Color)} [r] - The red component of the color. If `g` and `b` are + * not provided, it can be hexadecimal triplet, a CSS-style string or another `Color` instance. + * @param {number} [g] - The green component. + * @param {number} [b] - The blue component. + * @return {Color} A reference to this color. + */ set( r, g, b ) { if ( g === undefined && b === undefined ) { @@ -87,6 +177,12 @@ class Color { } + /** + * Sets the colors's components to the given scalar value. + * + * @param {number} scalar - The scalar value. + * @return {Color} A reference to this color. + */ setScalar( scalar ) { this.r = scalar; @@ -97,6 +193,13 @@ class Color { } + /** + * Sets this color from a hexadecimal value. + * + * @param {number} hex - The hexadecimal value. + * @param {string} [colorSpace=SRGBColorSpace] - The color space. + * @return {Color} A reference to this color. + */ setHex( hex, colorSpace = SRGBColorSpace ) { hex = Math.floor( hex ); @@ -111,6 +214,15 @@ class Color { } + /** + * Sets this color from RGB values. + * + * @param {number} r - Red channel value between `0.0` and `1.0`. + * @param {number} g - Green channel value between `0.0` and `1.0`. + * @param {number} b - Blue channel value between `0.0` and `1.0`. + * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. + * @return {Color} A reference to this color. + */ setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { this.r = r; @@ -123,6 +235,15 @@ class Color { } + /** + * Sets this color from RGB values. + * + * @param {number} h - Hue value between `0.0` and `1.0`. + * @param {number} s - Saturation value between `0.0` and `1.0`. + * @param {number} l - Lightness value between `0.0` and `1.0`. + * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. + * @return {Color} A reference to this color. + */ setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { // h,s,l ranges are in 0.0 - 1.0 @@ -151,6 +272,16 @@ class Color { } + /** + * Sets this color from a CSS-style string. For example, `rgb(250, 0,0)`, + * `rgb(100%, 0%, 0%)`, `hsl(0, 100%, 50%)`, `#ff0000`, `#f00`, or `red` ( or + * any [X11 color name]{@link https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart} - + * all 140 color names are supported). + * + * @param {string} style - Color as a CSS-style string. + * @param {string} [colorSpace=SRGBColorSpace] - The color space. + * @return {Color} A reference to this color. + */ setStyle( style, colorSpace = SRGBColorSpace ) { function handleAlpha( string ) { @@ -277,6 +408,19 @@ class Color { } + /** + * Sets this color from a color name. Faster than {@link Color#setStyle} if + * you don't need the other CSS-style formats. + * + * For convenience, the list of names is exposed in `Color.NAMES` as a hash. + * ```js + * Color.NAMES.aliceblue // returns 0xF0F8FF + * ``` + * + * @param {string} style - The color name. + * @param {string} [colorSpace=SRGBColorSpace] - The color space. + * @return {Color} A reference to this color. + */ setColorName( style, colorSpace = SRGBColorSpace ) { // color keywords @@ -298,12 +442,23 @@ class Color { } + /** + * Returns a new color with copied values from this instance. + * + * @return {Color} A clone of this instance. + */ clone() { return new this.constructor( this.r, this.g, this.b ); } + /** + * Copies the values of the given color to this instance. + * + * @param {Color} color - The color to copy. + * @return {Color} A reference to this color. + */ copy( color ) { this.r = color.r; @@ -314,6 +469,13 @@ class Color { } + /** + * Copies the given color into this color, and then converts this color from + * `SRGBColorSpace` to `LinearSRGBColorSpace`. + * + * @param {Color} color - The color to copy/convert. + * @return {Color} A reference to this color. + */ copySRGBToLinear( color ) { this.r = SRGBToLinear( color.r ); @@ -324,6 +486,13 @@ class Color { } + /** + * Copies the given color into this color, and then converts this color from + * `LinearSRGBColorSpace` to `SRGBColorSpace`. + * + * @param {Color} color - The color to copy/convert. + * @return {Color} A reference to this color. + */ copyLinearToSRGB( color ) { this.r = LinearToSRGB( color.r ); @@ -334,6 +503,11 @@ class Color { } + /** + * Converts this color from `SRGBColorSpace` to `LinearSRGBColorSpace`. + * + * @return {Color} A reference to this color. + */ convertSRGBToLinear() { this.copySRGBToLinear( this ); @@ -342,6 +516,11 @@ class Color { } + /** + * Converts this color from `LinearSRGBColorSpace` to `SRGBColorSpace`. + * + * @return {Color} A reference to this color. + */ convertLinearToSRGB() { this.copyLinearToSRGB( this ); @@ -350,6 +529,12 @@ class Color { } + /** + * Returns the hexadecimal value of this color. + * + * @param {string} [colorSpace=SRGBColorSpace] - The color space. + * @return {number} The hexadecimal value. + */ getHex( colorSpace = SRGBColorSpace ) { ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); @@ -358,12 +543,26 @@ class Color { } + /** + * Returns the hexadecimal value of this color as a string (for example, 'FFFFFF'). + * + * @param {string} [colorSpace=SRGBColorSpace] - The color space. + * @return {string} The hexadecimal value as a string. + */ getHexString( colorSpace = SRGBColorSpace ) { return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); } + /** + * Converts the colors RGB values into the HSL format and stores them into the + * given target object. + * + * @param {{h:0,s:0,l:0}} target - The target object that is used to store the method's result. + * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. + * @return {{h:0,s:0,l:0}} The HSL representation of this color. + */ getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { // h,s,l ranges are in 0.0 - 1.0 @@ -409,6 +608,13 @@ class Color { } + /** + * Returns the RGB values of this color and stores them into the given target object. + * + * @param {Color} target - The target color that is used to store the method's result. + * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. + * @return {Color} The RGB representation of this color. + */ getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); @@ -421,6 +627,12 @@ class Color { } + /** + * Returns the value of this color as a CSS style string. Example: `rgb(255,0,0)`. + * + * @param {string} [colorSpace=SRGBColorSpace] - The color space. + * @return {string} The CSS representation of this color. + */ getStyle( colorSpace = SRGBColorSpace ) { ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); @@ -438,6 +650,16 @@ class Color { } + /** + * Adds the given HSL values to this color's values. + * Internally, this converts the color's RGB values to HSL, adds HSL + * and then converts the color back to RGB. + * + * @param {number} h - Hue value between `0.0` and `1.0`. + * @param {number} s - Saturation value between `0.0` and `1.0`. + * @param {number} l - Lightness value between `0.0` and `1.0`. + * @return {Color} A reference to this color. + */ offsetHSL( h, s, l ) { this.getHSL( _hslA ); @@ -446,6 +668,12 @@ class Color { } + /** + * Adds the RGB values of the given color to the RGB values of this color. + * + * @param {Color} color - The color to add. + * @return {Color} A reference to this color. + */ add( color ) { this.r += color.r; @@ -456,6 +684,13 @@ class Color { } + /** + * Adds the RGB values of the given colors and stores the result in this instance. + * + * @param {Color} color1 - The first color. + * @param {Color} color2 - The second color. + * @return {Color} A reference to this color. + */ addColors( color1, color2 ) { this.r = color1.r + color2.r; @@ -466,6 +701,12 @@ class Color { } + /** + * Adds the given scalar value to the RGB values of this color. + * + * @param {number} s - The scalar to add. + * @return {Color} A reference to this color. + */ addScalar( s ) { this.r += s; @@ -476,6 +717,12 @@ class Color { } + /** + * Subtracts the RGB values of the given color from the RGB values of this color. + * + * @param {Color} color - The color to subtract. + * @return {Color} A reference to this color. + */ sub( color ) { this.r = Math.max( 0, this.r - color.r ); @@ -486,6 +733,12 @@ class Color { } + /** + * Multiplies the RGB values of the given color with the RGB values of this color. + * + * @param {Color} color - The color to multiply. + * @return {Color} A reference to this color. + */ multiply( color ) { this.r *= color.r; @@ -496,6 +749,12 @@ class Color { } + /** + * Multiplies the given scalar value with the RGB values of this color. + * + * @param {number} s - The scalar to multiply. + * @return {Color} A reference to this color. + */ multiplyScalar( s ) { this.r *= s; @@ -506,6 +765,15 @@ class Color { } + /** + * Linearly interpolates this color's RGB values toward the RGB values of the + * given color. The alpha argument can be thought of as the ratio between + * the two colors, where `0.0` is this color and `1.0` is the first argument. + * + * @param {Color} color - The color to converge on. + * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. + * @return {Color} A reference to this color. + */ lerp( color, alpha ) { this.r += ( color.r - this.r ) * alpha; @@ -516,6 +784,16 @@ class Color { } + /** + * Linearly interpolates between the given colors and stores the result in this instance. + * The alpha argument can be thought of as the ratio between the two colors, where `0.0` + * is the first and `1.0` is the second color. + * + * @param {Color} color1 - The first color. + * @param {Color} color2 - The second color. + * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. + * @return {Color} A reference to this color. + */ lerpColors( color1, color2, alpha ) { this.r = color1.r + ( color2.r - color1.r ) * alpha; @@ -526,6 +804,17 @@ class Color { } + /** + * Linearly interpolates this color's HSL values toward the HSL values of the + * given color. It differs from {@link Color#lerp} by not interpolating straight + * from one color to the other, but instead going through all the hues in between + * those two colors. The alpha argument can be thought of as the ratio between + * the two colors, where 0.0 is this color and 1.0 is the first argument. + * + * @param {Color} color - The color to converge on. + * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. + * @return {Color} A reference to this color. + */ lerpHSL( color, alpha ) { this.getHSL( _hslA ); @@ -541,6 +830,12 @@ class Color { } + /** + * Sets the color's RGB components from the given 3D vector. + * + * @param {Vector3} v - The vector to set. + * @return {Color} A reference to this color. + */ setFromVector3( v ) { this.r = v.x; @@ -551,6 +846,12 @@ class Color { } + /** + * Transforms this color with the given 3x3 matrix. + * + * @param {Matrix3} m - The matrix. + * @return {Color} A reference to this color. + */ applyMatrix3( m ) { const r = this.r, g = this.g, b = this.b; @@ -564,12 +865,25 @@ class Color { } + /** + * Returns `true` if this color is equal with the given one. + * + * @param {Color} c - The color to test for equality. + * @return {boolean} Whether this bounding color is equal with the given one. + */ equals( c ) { return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); } + /** + * Sets this color's RGB components from the given array. + * + * @param {Array} array - An array holding the RGB values. + * @param {number} [offset=0] - The offset into the array. + * @return {Color} A reference to this color. + */ fromArray( array, offset = 0 ) { this.r = array[ offset ]; @@ -580,6 +894,14 @@ class Color { } + /** + * Writes the RGB components of this color to the given array. If no array is provided, + * the method returns a new instance. + * + * @param {Array} [array=[]] - The target array holding the color components. + * @param {number} [offset=0] - Index of the first element in the array. + * @return {Array} The color components. + */ toArray( array = [], offset = 0 ) { array[ offset ] = this.r; @@ -590,6 +912,13 @@ class Color { } + /** + * Sets the components of this color from the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute holding color data. + * @param {number} index - The index into the attribute. + * @return {Color} A reference to this color. + */ fromBufferAttribute( attribute, index ) { this.r = attribute.getX( index ); @@ -600,6 +929,12 @@ class Color { } + /** + * This methods defines the serialization result of this class. Returns the color + * as a hexadecimal value. + * + * @return {number} The hexadecimal value. + */ toJSON() { return this.getHex(); @@ -618,6 +953,14 @@ class Color { const _color = /*@__PURE__*/ new Color(); +/** + * A dictionary with X11 color names. + * + * Note that multiple words such as Dark Orange become the string 'darkorange'. + * + * @static + * @type {Object} + */ Color.NAMES = _colorKeywords; export { Color }; diff --git a/src/math/Euler.js b/src/math/Euler.js index 33150c6104a4c2..5f0e155bccf5f5 100644 --- a/src/math/Euler.js +++ b/src/math/Euler.js @@ -5,10 +5,41 @@ import { clamp } from './MathUtils.js'; const _matrix = /*@__PURE__*/ new Matrix4(); const _quaternion = /*@__PURE__*/ new Quaternion(); +/** + * A class representing Euler angles. + * + * Euler angles describe a rotational transformation by rotating an object on + * its various axes in specified amounts per axis, and a specified axis + * order. + * + * Iterating through an instance will yield its components (x, y, z, + * order) in the corresponding order. + * + * ```js + * const a = new THREE.Euler( 0, 1, 1.57, 'XYZ' ); + * const b = new THREE.Vector3( 1, 0, 1 ); + * b.applyEuler(a); + * ``` + */ class Euler { + /** + * Constructs a new euler instance. + * + * @param {number} [x=0] - The angle of the x axis in radians. + * @param {number} [y=0] - The angle of the y axis in radians. + * @param {number} [z=0] - The angle of the z axis in radians. + * @param {string} [order=Euler.DEFAULT_ORDER] - A string representing the order that the rotations are applied. + */ constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ this.isEuler = true; this._x = x; @@ -18,6 +49,12 @@ class Euler { } + /** + * The angle of the x axis in radians. + * + * @type {number} + * @default 0 + */ get x() { return this._x; @@ -31,6 +68,12 @@ class Euler { } + /** + * The angle of the y axis in radians. + * + * @type {number} + * @default 0 + */ get y() { return this._y; @@ -44,6 +87,12 @@ class Euler { } + /** + * The angle of the z axis in radians. + * + * @type {number} + * @default 0 + */ get z() { return this._z; @@ -57,6 +106,12 @@ class Euler { } + /** + * A string representing the order that the rotations are applied. + * + * @type {string} + * @default 'XYZ' + */ get order() { return this._order; @@ -70,6 +125,15 @@ class Euler { } + /** + * Sets the Euler components. + * + * @param {number} x - The angle of the x axis in radians. + * @param {number} y - The angle of the y axis in radians. + * @param {number} z - The angle of the z axis in radians. + * @param {string} [order] - A string representing the order that the rotations are applied. + * @return {Euler} A reference to this Euler instance. + */ set( x, y, z, order = this._order ) { this._x = x; @@ -83,12 +147,23 @@ class Euler { } + /** + * Returns a new Euler instance with copied values from this instance. + * + * @return {Euler} A clone of this instance. + */ clone() { return new this.constructor( this._x, this._y, this._z, this._order ); } + /** + * Copies the values of the given Euler instance to this instance. + * + * @param {Euler} euler - The Euler instance to copy. + * @return {Euler} A reference to this Euler instance. + */ copy( euler ) { this._x = euler._x; @@ -102,10 +177,16 @@ class Euler { } + /** + * Sets the angles of this Euler instance from a pure rotation matrix. + * + * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled). + * @param {string} [order] - A string representing the order that the rotations are applied. + * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. + * @return {Euler} A reference to this Euler instance. + */ setFromRotationMatrix( m, order = this._order, update = true ) { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - const te = m.elements; const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; @@ -235,6 +316,14 @@ class Euler { } + /** + * Sets the angles of this Euler instance from a normalized quaternion. + * + * @param {Quaternion} q - A normalized Quaternion. + * @param {string} [order] - A string representing the order that the rotations are applied. + * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. + * @return {Euler} A reference to this Euler instance. + */ setFromQuaternion( q, order, update ) { _matrix.makeRotationFromQuaternion( q ); @@ -243,28 +332,57 @@ class Euler { } + /** + * Sets the angles of this Euler instance from the given vector. + * + * @param {Vector3} v - The vector. + * @param {string} [order] - A string representing the order that the rotations are applied. + * @return {Euler} A reference to this Euler instance. + */ setFromVector3( v, order = this._order ) { return this.set( v.x, v.y, v.z, order ); } + /** + * Resets the euler angle with a new order by creating a quaternion from this + * euler angle and then setting this euler angle with the quaternion and the + * new order. + * + * Warning: This discards revolution information. + * + * @param {string} [newOrder] - A string representing the new order that the rotations are applied. + * @return {Euler} A reference to this Euler instance. + */ reorder( newOrder ) { - // WARNING: this discards revolution information -bhouston - _quaternion.setFromEuler( this ); return this.setFromQuaternion( _quaternion, newOrder ); } + /** + * Returns `true` if this Euler instance is equal with the given one. + * + * @param {Euler} euler - The Euler instance to test for equality. + * @return {boolean} Whether this Euler instance is equal with the given one. + */ equals( euler ) { return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); } + /** + * Sets this Euler instance's components to values from the given array. The first three + * entries of the array are assign to the x,y and z components. An optinal fourth entry + * defines the Euler order. + * + * @param {Array} array - An array holding the Euler component values. + * @return {Euler} A reference to this Euler instance. + */ fromArray( array ) { this._x = array[ 0 ]; @@ -278,6 +396,14 @@ class Euler { } + /** + * Writes the components of this Euler instance to the given array. If no array is provided, + * the method returns a new instance. + * + * @param {Array} [array=[]] - The target array holding the Euler components. + * @param {number} [offset=0] - Index of the first element in the array. + * @return {Array} The Euler components. + */ toArray( array = [], offset = 0 ) { array[ offset ] = this._x; @@ -310,6 +436,13 @@ class Euler { } +/** + * The default Euler angle order. + * + * @static + * @type {string} + * @default 'XYZ' + */ Euler.DEFAULT_ORDER = 'XYZ'; export { Euler }; diff --git a/src/math/Interpolant.js b/src/math/Interpolant.js index 826b40cfb9db4d..f156d3b3a821cf 100644 --- a/src/math/Interpolant.js +++ b/src/math/Interpolant.js @@ -13,29 +13,82 @@ * Time complexity is O(1) for linear access crossing at most two points * and O(log N) for random access, where N is the number of positions. * - * References: - * - * http://www.oodesign.com/template-method-pattern.html + * References: {@link http://www.oodesign.com/template-method-pattern.html} * + * @abstract */ - class Interpolant { + /** + * Constructs a new interpolant. + * + * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. + * @param {TypedArray} sampleValues - The sample values. + * @param {number} sampleSize - The sample size + * @param {TypedArray} [resultBuffer] - The result buffer. + */ constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + /** + * The parameter positions. + * + * @type {TypedArray} + */ this.parameterPositions = parameterPositions; + + /** + * A cache index. + * + * @private + * @type {number} + * @default 0 + */ this._cachedIndex = 0; - this.resultBuffer = resultBuffer !== undefined ? - resultBuffer : new sampleValues.constructor( sampleSize ); + /** + * The result buffer. + * + * @type {TypedArray} + */ + this.resultBuffer = resultBuffer !== undefined ? resultBuffer : new sampleValues.constructor( sampleSize ); + + /** + * The sample values. + * + * @type {TypedArray} + */ this.sampleValues = sampleValues; + + /** + * The value size. + * + * @type {TypedArray} + */ this.valueSize = sampleSize; + /** + * The interpolation settings. + * + * @type {?Object} + * @default null + */ this.settings = null; + + /** + * The default settings object. + * + * @type {Object} + */ this.DefaultSettings_ = {}; } + /** + * Evaluate the interpolant at position `t`. + * + * @param {number} t - The interpolation factor. + * @return {TypedArray} The result buffer. + */ evaluate( t ) { const pp = this.parameterPositions; @@ -196,12 +249,23 @@ class Interpolant { } + /** + * Returns the interpolation settings. + * + * @return {Object} The interpolation settings. + */ getSettings_() { return this.settings || this.DefaultSettings_; } + /** + * Copies a sample value to the result buffer. + * + * @param {number} index - An index into the sample value buffer. + * @return {TypedArray} The result buffer. + */ copySampleValue_( index ) { // copies a sample value to the result buffer @@ -221,8 +285,16 @@ class Interpolant { } - // Template methods for derived classes: - + /** + * Copies a sample value to the result buffer. + * + * @abstract + * @param {number} i1 - An index into the sample value buffer. + * @param {number} t0 - The previous interpolation factor. + * @param {number} t - The current interpolation factor. + * @param {number} t1 - The next interpolation factor. + * @return {TypedArray} The result buffer. + */ interpolate_( /* i1, t0, t, t1 */ ) { throw new Error( 'call to abstract method' ); @@ -230,6 +302,13 @@ class Interpolant { } + /** + * Optional method that is executed when the interval has changed. + * + * @param {number} i1 - An index into the sample value buffer. + * @param {number} t0 - The previous interpolation factor. + * @param {number} t - The current interpolation factor. + */ intervalChanged_( /* i1, t0, t1 */ ) { // empty diff --git a/src/math/MathUtils.js b/src/math/MathUtils.js index e4d4448b8e7ee8..7a78120e5a7a8f 100644 --- a/src/math/MathUtils.js +++ b/src/math/MathUtils.js @@ -6,9 +6,16 @@ let _seed = 1234567; const DEG2RAD = Math.PI / 180; const RAD2DEG = 180 / Math.PI; -// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 +/** + * Generate a [UUID]{@link https://en.wikipedia.org/wiki/Universally_unique_identifier} + * (universally unique identifier). + * + * @return {string} The UUID. + */ function generateUUID() { + // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 + const d0 = Math.random() * 0xffffffff | 0; const d1 = Math.random() * 0xffffffff | 0; const d2 = Math.random() * 0xffffffff | 0; @@ -23,30 +30,66 @@ function generateUUID() { } +/** + * Clamps the given value between min and max. + * + * @param {number} value - The value to clamp. + * @param {number} min - The min value. + * @param {number} max - The max value. + * @return {number} The clamped value. + */ function clamp( value, min, max ) { return Math.max( min, Math.min( max, value ) ); } -// compute euclidean modulo of m % n -// https://en.wikipedia.org/wiki/Modulo_operation +/** + * Computes the Euclidean modulo of the given parameters that + * is `( ( n % m ) + m ) % m`. + * + * @param {number} n - The first parameter. + * @param {number} m - The second parameter. + * @return {number} The Euclidean modulo. + */ function euclideanModulo( n, m ) { + // https://en.wikipedia.org/wiki/Modulo_operation + return ( ( n % m ) + m ) % m; } -// Linear mapping from range to range +/** + * Performs a linear mapping from range `` to range `` + * for the given value. + * + * @param {number} x - The value to be mapped. + * @param {number} a1 - Minimum value for range A. + * @param {number} a2 - Maximum value for range A. + * @param {number} b1 - Minimum value for range B. + * @param {number} b2 - Maximum value for range B. + * @return {number} The mapped value. + */ function mapLinear( x, a1, a2, b1, b2 ) { return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); } -// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ +/** + * Returns the percentage in the closed interval `[0, 1]` of the given value + * between the start and end point. + * + * @param {number} x - The start point + * @param {number} y - The end point. + * @param {number} value - A value between start and end. + * @return {number} The interpolation factor. + */ function inverseLerp( x, y, value ) { + // https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ + if ( x !== y ) { return ( value - x ) / ( y - x ); @@ -59,28 +102,66 @@ function inverseLerp( x, y, value ) { } -// https://en.wikipedia.org/wiki/Linear_interpolation +/** + * Returns a value linearly interpolated from two known points based on the given interval - + * `t = 0` will return `x` and `t = 1` will return `y`. + * + * @param {number} x - The start point + * @param {number} y - The end point. + * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. + * @return {number} The interpolated value. + */ function lerp( x, y, t ) { return ( 1 - t ) * x + t * y; } -// http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ +/** + * Smoothly interpolate a number from `x` to `y` in a spring-like manner using a delta + * time to maintain frame rate independent movement. For details, see + * [Frame rate independent damping using lerp]{@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}. + * + * @param {number} x - The current point. + * @param {number} y - The target point. + * @param {number} lambda - A higher lambda value will make the movement more sudden, + * and a lower value will make the movement more gradual. + * @param {number} dt - Delta time in seconds. + * @return {number} The interpolated value. + */ function damp( x, y, lambda, dt ) { return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); } -// https://www.desmos.com/calculator/vcsjnyz7x4 +/** + * Returns a value that alternates between `0` and the given `length` parameter. + * + * @param {number} x - The value to pingpong. + * @param {number} [length=1] - The positive value the function will pingpong to. + * @return {number} The alternated value. + */ function pingpong( x, length = 1 ) { + // https://www.desmos.com/calculator/vcsjnyz7x4 + return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); } -// http://en.wikipedia.org/wiki/Smoothstep +/** + * Returns a value in the range `[0,1]` that represents the percentage that `x` has + * moved between `min` and `max`, but smoothed or slowed down the closer `x` is to + * the `min` and `max`. + * + * See [Smoothstep]{@link http://en.wikipedia.org/wiki/Smoothstep} for more details. + * + * @param {number} x - The value to evaluate based on its position between min and max. + * @param {number} min - The min value. Any x value below min will be `0`. + * @param {number} max - The max value. Any x value above max will be `1`. + * @return {number} The alternated value. + */ function smoothstep( x, min, max ) { if ( x <= min ) return 0; @@ -92,6 +173,15 @@ function smoothstep( x, min, max ) { } +/** + * A [variation on smoothstep]{@link https://en.wikipedia.org/wiki/Smoothstep#Variations} + * that has zero 1st and 2nd order derivatives at x=0 and x=1. + * + * @param {number} x - The value to evaluate based on its position between min and max. + * @param {number} min - The min value. Any x value below min will be `0`. + * @param {number} max - The max value. Any x value above max will be `1`. + * @return {number} The alternated value. + */ function smootherstep( x, min, max ) { if ( x <= min ) return 0; @@ -103,28 +193,50 @@ function smootherstep( x, min, max ) { } -// Random integer from interval +/** + * Returns a random integer from `` interval. + * + * @param {number} low - The lower value boundary. + * @param {number} high - The upper value boundary + * @return {number} A random integer. + */ function randInt( low, high ) { return low + Math.floor( Math.random() * ( high - low + 1 ) ); } -// Random float from interval +/** + * Returns a random float from `` interval. + * + * @param {number} low - The lower value boundary. + * @param {number} high - The upper value boundary + * @return {number} A random float. + */ function randFloat( low, high ) { return low + Math.random() * ( high - low ); } -// Random float from <-range/2, range/2> interval +/** + * Returns a random integer from `<-range/2, range/2>` interval. + * + * @param {number} range - Defines the value range. + * @return {number} A random float. + */ function randFloatSpread( range ) { return range * ( 0.5 - Math.random() ); } -// Deterministic pseudo-random float in the interval [ 0, 1 ] +/** + * Returns a deterministic pseudo-random float in the interval `[0, 1]`. + * + * @param {number} [s] - The integer seed. + * @return {number} A random float. + */ function seededRandom( s ) { if ( s !== undefined ) _seed = s; @@ -141,44 +253,81 @@ function seededRandom( s ) { } +/** + * Converts degrees to radians. + * + * @param {number} degrees - A value in degrees. + * @return {number} The converted value in radians. + */ function degToRad( degrees ) { return degrees * DEG2RAD; } +/** + * Converts radians to degrees. + * + * @param {number} radians - A value in radians. + * @return {number} The converted value in degrees. + */ function radToDeg( radians ) { return radians * RAD2DEG; } +/** + * Returns `true` if the given number is a power of two. + * + * @param {number} value - The value to check. + * @return {boolean} Whether the given number is a power of two or not. + */ function isPowerOfTwo( value ) { return ( value & ( value - 1 ) ) === 0 && value !== 0; } +/** + * Returns the smallest power of two that is greater than or equal to the given number. + * + * @param {number} value - The value to find a POT for. + * @return {number} The smallest power of two that is greater than or equal to the given number. + */ function ceilPowerOfTwo( value ) { return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); } +/** + * Returns the largest power of two that is less than or equal to the given number. + * + * @param {number} value - The value to find a POT for. + * @return {number} The largest power of two that is less than or equal to the given number. + */ function floorPowerOfTwo( value ) { return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); } +/** + * Sets the given quaternion from the [Intrinsic Proper Euler Angles]{@link https://en.wikipedia.org/wiki/Euler_angles} + * defined by the given angles and order. + * + * Rotations are applied to the axes in the order specified by order: + * rotation by angle `a` is applied first, then by angle `b`, then by angle `c`. + * + * @param {Quaternion} q - The quaternion to set. + * @param {number} a - The rotation applied to the first axis, in radians. + * @param {number} b - The rotation applied to the second axis, in radians. + * @param {number} c - The rotation applied to the third axis, in radians. + * @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - A string specifying the axes order. + */ function setQuaternionFromProperEuler( q, a, b, c, order ) { - // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles - - // rotations are applied to the axes in the order specified by 'order' - // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' - // angles are in radians - const cos = Math.cos; const sin = Math.sin; @@ -227,6 +376,13 @@ function setQuaternionFromProperEuler( q, a, b, c, order ) { } +/** + * Denormalizes the given value according to the given typed array. + * + * @param {number} value - The value to denormalize. + * @param {TypedArray} array - The typed array that defines the data type of the value. + * @return {number} The denormalize (float) value in the range `[0,1]`. + */ function denormalize( value, array ) { switch ( array.constructor ) { @@ -267,6 +423,13 @@ function denormalize( value, array ) { } +/** + * Normalizes the given value according to the given typed array. + * + * @param {number} value - The float value in the range `[0,1]` to normalize. + * @param {TypedArray} array - The typed array that defines the data type of the value. + * @return {number} The normalize value. + */ function normalize( value, array ) { switch ( array.constructor ) { diff --git a/src/math/Quaternion.js b/src/math/Quaternion.js index e6836434e13f5b..11a1424f56eb7c 100644 --- a/src/math/Quaternion.js +++ b/src/math/Quaternion.js @@ -1,9 +1,39 @@ import { clamp } from './MathUtils.js'; +/** + * Class for representing a Quaternion. Quaternions are used in three.js to represent rotations. + * + * Iterating through a vector instance will yield its components `(x, y, z, w)` in + * the corresponding order. + * + * Note that three.js expects Quaternions to be normalized. + * ```js + * const quaternion = new THREE.Quaternion(); + * quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), Math.PI / 2 ); + * + * const vector = new THREE.Vector3( 1, 0, 0 ); + * vector.applyQuaternion( quaternion ); + * ``` + */ class Quaternion { + /** + * Constructs a new quaternion. + * + * @param {number} [x=0] - The x value of this quaternion. + * @param {number} [y=0] - The y value of this quaternion. + * @param {number} [z=0] - The z value of this quaternion. + * @param {number} [w=1] - The w value of this quaternion. + */ constructor( x = 0, y = 0, z = 0, w = 1 ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ this.isQuaternion = true; this._x = x; @@ -13,6 +43,19 @@ class Quaternion { } + /** + * Interpolates between two quaternions via SLERP. This implementation assumes the + * quaternion data are managed in flat arrays. + * + * @param {Array} dst - The destination array. + * @param {number} dstOffset - An offset into the destination array. + * @param {Array} src0 - The source array of the first quaternion. + * @param {number} srcOffset0 - An offset into the first source array. + * @param {Array} src1 - The source array of the second quaternion. + * @param {number} srcOffset1 - An offset into the second source array. + * @param {number} t - The interpolation factor in the range `[0,1]`. + * @see {@link Quaternion#slerp} + */ static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { // fuzz-free, array-based Quaternion SLERP operation @@ -93,6 +136,19 @@ class Quaternion { } + /** + * Multiplies two quaternions. This implementation assumes the quaternion data are managed + * in flat arrays. + * + * @param {Array} dst - The destination array. + * @param {number} dstOffset - An offset into the destination array. + * @param {Array} src0 - The source array of the first quaternion. + * @param {number} srcOffset0 - An offset into the first source array. + * @param {Array} src1 - The source array of the second quaternion. + * @param {number} srcOffset1 - An offset into the second source array. + * @return {Array} The destination array. + * @see {@link Quaternion#multiplyQuaternions}. + */ static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { const x0 = src0[ srcOffset0 ]; @@ -114,6 +170,12 @@ class Quaternion { } + /** + * The x value of this quaternion. + * + * @type {number} + * @default 0 + */ get x() { return this._x; @@ -127,6 +189,12 @@ class Quaternion { } + /** + * The y value of this quaternion. + * + * @type {number} + * @default 0 + */ get y() { return this._y; @@ -140,6 +208,12 @@ class Quaternion { } + /** + * The z value of this quaternion. + * + * @type {number} + * @default 0 + */ get z() { return this._z; @@ -153,6 +227,12 @@ class Quaternion { } + /** + * The w value of this quaternion. + * + * @type {number} + * @default 1 + */ get w() { return this._w; @@ -166,6 +246,15 @@ class Quaternion { } + /** + * Sets the quaternion components. + * + * @param {number} x - The x value of this quaternion. + * @param {number} y - The y value of this quaternion. + * @param {number} z - The z value of this quaternion. + * @param {number} w - The w value of this quaternion. + * @return {Quaternion} A reference to this quaternion. + */ set( x, y, z, w ) { this._x = x; @@ -179,12 +268,23 @@ class Quaternion { } + /** + * Returns a new quaternion with copied values from this instance. + * + * @return {Quaternion} A clone of this instance. + */ clone() { return new this.constructor( this._x, this._y, this._z, this._w ); } + /** + * Copies the values of the given quaternion to this instance. + * + * @param {Quaternion} quaternion - The quaternion to copy. + * @return {Quaternion} A reference to this quaternion. + */ copy( quaternion ) { this._x = quaternion.x; @@ -198,6 +298,14 @@ class Quaternion { } + /** + * Sets this quaternion from the rotation specified by the given + * Euler angles. + * + * @param {Euler} euler - The Euler angles. + * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. + * @return {Quaternion} A reference to this quaternion. + */ setFromEuler( euler, update = true ) { const x = euler._x, y = euler._y, z = euler._z, order = euler._order; @@ -272,12 +380,17 @@ class Quaternion { } + /** + * Sets this quaternion from the given axis and angle. + * + * @param {Vector3} axis - The normalized axis. + * @param {number} angle - The angle in radians. + * @return {Quaternion} A reference to this quaternion. + */ setFromAxisAngle( axis, angle ) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - // assumes axis is normalized - const halfAngle = angle / 2, s = Math.sin( halfAngle ); this._x = axis.x * s; @@ -291,6 +404,12 @@ class Quaternion { } + /** + * Sets this quaternion from the given rotation matrix. + * + * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled). + * @return {Quaternion} A reference to this quaternion. + */ setFromRotationMatrix( m ) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm @@ -349,6 +468,14 @@ class Quaternion { } + /** + * Sets this quaternion to the rotation required to rotate the direction vector + * `vFrom` to the direction vector `vTo`. + * + * @param {Vector3} vFrom - The first (normalized) direction vector. + * @param {Vector3} vTo - The second (normalized) direction vector. + * @return {Quaternion} A reference to this quaternion. + */ setFromUnitVectors( vFrom, vTo ) { // assumes direction vectors vFrom and vTo are normalized @@ -392,12 +519,26 @@ class Quaternion { } + /** + * Returns the angle between this quaternion and the given one in radians. + * + * @param {Quaternion} q - The quaternion to compute the angle with. + * @return {number} The angle in radians. + */ angleTo( q ) { return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); } + /** + * Rotates this quaternion by a given angular step to the given quaterion. + * The method ensures that the final quaternion will not overshoot `q`. + * + * @param {Quaternion} q - The target quaternion. + * @param {number} step - The angular step in radians. + * @return {Quaternion} A reference to this quaternion. + */ rotateTowards( q, step ) { const angle = this.angleTo( q ); @@ -412,20 +553,37 @@ class Quaternion { } + /** + * Sets this quaternion to the identity quaternion; that is, to the + * quaternion that represents "no rotation". + * + * @return {Quaternion} A reference to this quaternion. + */ identity() { return this.set( 0, 0, 0, 1 ); } + /** + * Inverts this quaternion via {@link Quaternion#conjugate}. The + * quaternion is assumed to have unit length. + * + * @return {Quaternion} A reference to this quaternion. + */ invert() { - // quaternion is assumed to have unit length - return this.conjugate(); } + /** + * Returns the rotational conjugate of this quaternion. The conjugate of a + * quaternion represents the same rotation in the opposite direction about + * the rotational axis. + * + * @return {Quaternion} A reference to this quaternion. + */ conjugate() { this._x *= - 1; @@ -438,24 +596,50 @@ class Quaternion { } + /** + * Calculates the dot product of this quaternion and the given one. + * + * @param {Quaternion} v - The quaternion to compute the dot product with. + * @return {number} The result of the dot product. + */ dot( v ) { return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; } + /** + * Computes the squared Euclidean length (straight-line length) of this quaternion, + * considered as a 4 dimensional vector. This can be useful if you are comparing the + * lengths of two quaternions, as this is a slightly more efficient calculation than + * {@link Quaternion#length}. + * + * @return {number} The squared Euclidean length. + */ lengthSq() { return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; } + /** + * Computes the Euclidean length (straight-line length) of this quaternion, + * considered as a 4 dimensional vector. + * + * @return {number} The Euclidean length. + */ length() { return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); } + /** + * Normalizes this quaternion - that is, calculated the quaternion that performs + * the same rotation as this one, but has a length equal to `1`. + * + * @return {Quaternion} A reference to this quaternion. + */ normalize() { let l = this.length(); @@ -484,18 +668,37 @@ class Quaternion { } + /** + * Multiplies this quaternion by the given one. + * + * @param {Quaternion} q - The quaternion. + * @return {Quaternion} A reference to this quaternion. + */ multiply( q ) { return this.multiplyQuaternions( this, q ); } + /** + * Pre-multiplies this quaternion by the given one. + * + * @param {Quaternion} q - The quaternion. + * @return {Quaternion} A reference to this quaternion. + */ premultiply( q ) { return this.multiplyQuaternions( q, this ); } + /** + * Multiplies the given quaternions and stores the result in this instance. + * + * @param {Quaternion} a - The first quaternion. + * @param {Quaternion} b - The second quaternion. + * @return {Quaternion} A reference to this quaternion. + */ multiplyQuaternions( a, b ) { // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm @@ -514,6 +717,13 @@ class Quaternion { } + /** + * Performs a spherical linear interpolation between quaternions. + * + * @param {Quaternion} qb - The target quaternion. + * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. + * @return {Quaternion} A reference to this quaternion. + */ slerp( qb, t ) { if ( t === 0 ) return this; @@ -583,16 +793,28 @@ class Quaternion { } + /** + * Performs a spherical linear interpolation between the given quaternions + * and stores the result in this quaternion. + * + * @param {Quaternion} qa - The source quaternion. + * @param {Quaternion} qb - The target quaternion. + * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. + * @return {Quaternion} A reference to this quaternion. + */ slerpQuaternions( qa, qb, t ) { return this.copy( qa ).slerp( qb, t ); } + /** + * Sets this quaternion to a uniformly random, normalized quaternion. + * + * @return {Quaternion} A reference to this quaternion. + */ random() { - // sets this quaternion to a uniform random unit quaternnion - // Ken Shoemake // Uniform random rotations // D. Kirk, editor, Graphics Gems III, pages 124-132. Academic Press, New York, 1992. @@ -613,12 +835,25 @@ class Quaternion { } + /** + * Returns `true` if this quaternion is equal with the given one. + * + * @param {Quaternion} quaternion - The quaternion to test for equality. + * @return {boolean} Whether this quaternion is equal with the given one. + */ equals( quaternion ) { return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); } + /** + * Sets this quaternion's components from the given array. + * + * @param {Array} array - An array holding the quaternion component values. + * @param {number} [offset=0] - The offset into the array. + * @return {Quaternion} A reference to this quaternion. + */ fromArray( array, offset = 0 ) { this._x = array[ offset ]; @@ -632,6 +867,14 @@ class Quaternion { } + /** + * Writes the components of this quaternion to the given array. If no array is provided, + * the method returns a new instance. + * + * @param {Array} [array=[]] - The target array holding the quaternion components. + * @param {number} [offset=0] - Index of the first element in the array. + * @return {Array} The quaternion components. + */ toArray( array = [], offset = 0 ) { array[ offset ] = this._x; @@ -643,6 +886,13 @@ class Quaternion { } + /** + * Sets the components of this quaternion from the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute holding quaternion data. + * @param {number} index - The index into the attribute. + * @return {Quaternion} A reference to this quaternion. + */ fromBufferAttribute( attribute, index ) { this._x = attribute.getX( index ); @@ -656,6 +906,12 @@ class Quaternion { } + /** + * This methods defines the serialization result of this class. Returns the + * numerical elements of this quaternion in an array of format `[x, y, z, w]`. + * + * @return {Array} The serialized quaternion. + */ toJSON() { return this.toArray(); diff --git a/src/math/Ray.js b/src/math/Ray.js index ed3d12059aebb4..14bc3cd04fff8a 100644 --- a/src/math/Ray.js +++ b/src/math/Ray.js @@ -9,15 +9,45 @@ const _edge1 = /*@__PURE__*/ new Vector3(); const _edge2 = /*@__PURE__*/ new Vector3(); const _normal = /*@__PURE__*/ new Vector3(); +/** + * A ray that emits from an origin in a certain direction. The class is used by + * {@link Raycaster} to assist with raycasting. Raycasting is used for + * mouse picking (working out what objects in the 3D space the mouse is over) + * amongst other things. + */ class Ray { + /** + * Constructs a new ray. + * + * @param {Vector3} [origin=(0,0,0)] - The origin of the ray. + * @param {Vector3} [direction=(0,0,-1)] - The (normalized) direction of the ray. + */ constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { + /** + * The origin of the ray. + * + * @type {Vector3} + */ this.origin = origin; + + /** + * The (normalized) direction of the ray. + * + * @type {Vector3} + */ this.direction = direction; } + /** + * Sets the ray's components by copying the given values. + * + * @param {Vector3} origin - The origin. + * @param {Vector3} direction - The direction. + * @return {Ray} A reference to this ray. + */ set( origin, direction ) { this.origin.copy( origin ); @@ -27,6 +57,12 @@ class Ray { } + /** + * Copies the values of the given ray to this instance. + * + * @param {Ray} ray - The ray to copy. + * @return {Ray} A reference to this ray. + */ copy( ray ) { this.origin.copy( ray.origin ); @@ -36,12 +72,25 @@ class Ray { } + /** + * Returns a vector that is located at a given distance along this ray. + * + * @param {number} t - The distance along the ray to retrieve a position for. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} A position on the ray. + */ at( t, target ) { return target.copy( this.origin ).addScaledVector( this.direction, t ); } + /** + * Adjusts the direction of the ray to point at the given vector in world space. + * + * @param {Vector3} v - The target position. + * @return {Ray} A reference to this ray. + */ lookAt( v ) { this.direction.copy( v ).sub( this.origin ).normalize(); @@ -50,6 +99,12 @@ class Ray { } + /** + * Shift the origin of this ray along its direction by the given distance. + * + * @param {number} t - The distance along the ray to interpolate. + * @return {Ray} A reference to this ray. + */ recast( t ) { this.origin.copy( this.at( t, _vector ) ); @@ -58,6 +113,13 @@ class Ray { } + /** + * Returns the point along this ray that is closest to the given point. + * + * @param {Vector3} point - A point in 3D space to get the closet location on the ray for. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The closest point on this ray. + */ closestPointToPoint( point, target ) { target.subVectors( point, this.origin ); @@ -74,12 +136,24 @@ class Ray { } + /** + * Returns the distance of the closest approach between this ray and the given point. + * + * @param {Vector3} point - A point in 3D space to compute the distance to. + * @return {number} The distance. + */ distanceToPoint( point ) { return Math.sqrt( this.distanceSqToPoint( point ) ); } + /** + * Returns the squared distance of the closest approach between this ray and the given point. + * + * @param {Vector3} point - A point in 3D space to compute the distance to. + * @return {number} The squared distance. + */ distanceSqToPoint( point ) { const directionDistance = _vector.subVectors( point, this.origin ).dot( this.direction ); @@ -98,6 +172,15 @@ class Ray { } + /** + * Returns the squared distance between this ray and the given line segment. + * + * @param {Vector3} v0 - The start point of the line segment. + * @param {Vector3} v1 - The end point of the line segment. + * @param {Vector3} [optionalPointOnRay] - When provided, it receives the point on this ray that is closest to the segment. + * @param {Vector3} [optionalPointOnSegment] - When provided, it receives the point on the line segment that is closest to this ray. + * @return {number} The squared distance. + */ distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h @@ -217,6 +300,14 @@ class Ray { } + /** + * Intersects this ray with the given sphere, returning the intersection + * point or `null` if there is no intersection. + * + * @param {Sphere} sphere - The sphere to intersect. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {?Vector3} The intersection point. + */ intersectSphere( sphere, target ) { _vector.subVectors( sphere.center, this.origin ); @@ -247,12 +338,25 @@ class Ray { } + /** + * Returns `true` if this ray intersects with the given sphere. + * + * @param {Sphere} sphere - The sphere to intersect. + * @return {boolean} Whether this ray intersects with the given sphere or not. + */ intersectsSphere( sphere ) { return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); } + /** + * Computes the distance from the ray's origin to the given plane. Returns `null` if the ray + * does not intersect with the plane. + * + * @param {Plane} plane - The plane to compute the distance to. + * @return {?number} Whether this ray intersects with the given sphere or not. + */ distanceToPlane( plane ) { const denominator = plane.normal.dot( this.direction ); @@ -280,6 +384,14 @@ class Ray { } + /** + * Intersects this ray with the given plane, returning the intersection + * point or `null` if there is no intersection. + * + * @param {Plane} plane - The plane to intersect. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {?Vector3} The intersection point. + */ intersectPlane( plane, target ) { const t = this.distanceToPlane( plane ); @@ -294,6 +406,12 @@ class Ray { } + /** + * Returns `true` if this ray intersects with the given plane. + * + * @param {Plane} plane - The plane to intersect. + * @return {boolean} Whether this ray intersects with the given plane or not. + */ intersectsPlane( plane ) { // check if the ray lies on the plane first @@ -320,6 +438,14 @@ class Ray { } + /** + * Intersects this ray with the given bounding box, returning the intersection + * point or `null` if there is no intersection. + * + * @param {Box3} box - The box to intersect. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {?Vector3} The intersection point. + */ intersectBox( box, target ) { let tmin, tmax, tymin, tymax, tzmin, tzmax; @@ -386,12 +512,29 @@ class Ray { } + /** + * Returns `true` if this ray intersects with the given box. + * + * @param {Box3} box - The box to intersect. + * @return {boolean} Whether this ray intersects with the given box or not. + */ intersectsBox( box ) { return this.intersectBox( box, _vector ) !== null; } + /** + * Intersects this ray with the given triangle, returning the intersection + * point or `null` if there is no intersection. + * + * @param {Vector3} a - The first vertex of the triangle. + * @param {Vector3} b - The second vertex of the triangle. + * @param {Vector3} c - The third vertex of the triangle. + * @param {boolean} backfaceCulling - Whether to use backface culling or not. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {?Vector3} The intersection point. + */ intersectTriangle( a, b, c, backfaceCulling, target ) { // Compute the offset origin, edges, and normal. @@ -467,6 +610,12 @@ class Ray { } + /** + * Transforms this ray with the given 4x4 transformation matrix. + * + * @param {Matrix4} matrix4 - The transformation matrix. + * @return {Ray} A reference to this ray. + */ applyMatrix4( matrix4 ) { this.origin.applyMatrix4( matrix4 ); @@ -476,12 +625,23 @@ class Ray { } + /** + * Returns `true` if this ray is equal with the given one. + * + * @param {Ray} ray - The ray to test for equality. + * @return {boolean} Whether this ray is equal with the given one. + */ equals( ray ) { return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); } + /** + * Returns a new ray with copied values from this instance. + * + * @return {Ray} A clone of this instance. + */ clone() { return new this.constructor().copy( this ); diff --git a/src/math/Sphere.js b/src/math/Sphere.js index 76e3d130357c8d..31aee36d691a1d 100644 --- a/src/math/Sphere.js +++ b/src/math/Sphere.js @@ -5,17 +5,52 @@ const _box = /*@__PURE__*/ new Box3(); const _v1 = /*@__PURE__*/ new Vector3(); const _v2 = /*@__PURE__*/ new Vector3(); +/** + * An analytical 3D sphere defined by a center and radius. This class is mainly + * used as a Bounding Sphere for 3D objects. + */ class Sphere { + /** + * Constructs a new sphere. + * + * @param {Vector3} [center=(0,0,0)] - The center of the sphere + * @param {number} [radius=-1] - The radius of the sphere. + */ constructor( center = new Vector3(), radius = - 1 ) { + /** + * This flag can be used for type testing. + * + * @type {boolean} + * @readonly + * @default true + */ this.isSphere = true; + /** + * The center of the sphere + * + * @type {Vector3} + */ this.center = center; + + /** + * The radius of the sphere. + * + * @type {number} + */ this.radius = radius; } + /** + * Sets the sphere's components by copying the given values. + * + * @param {Vector3} center - The center. + * @param {number} radius - The radius. + * @return {Sphere} A reference to this sphere. + */ set( center, radius ) { this.center.copy( center ); @@ -25,6 +60,16 @@ class Sphere { } + /** + * Computes the minimum bounding sphere for list of points. + * If the optional center point is given, it is used as the sphere's + * center. Otherwise, the center of the axis-aligned bounding box + * encompassing the points is calculated. + * + * @param {Array} points - A list of points in 3D space. + * @param {Vector3} [optionalCenter] - The center of the sphere. + * @return {Sphere} A reference to this sphere. + */ setFromPoints( points, optionalCenter ) { const center = this.center; @@ -53,6 +98,12 @@ class Sphere { } + /** + * Copies the values of the given sphere to this instance. + * + * @param {Sphere} sphere - The sphere to copy. + * @return {Sphere} A reference to this sphere. + */ copy( sphere ) { this.center.copy( sphere.center ); @@ -62,12 +113,25 @@ class Sphere { } + /** + * Returns `true` if the sphere is empty (the radius set to a negative number). + * + * Spheres with a radius of `0` contain only their center point and are not + * considered to be empty. + * + * @return {boolean} Whether this sphere is empty or not. + */ isEmpty() { return ( this.radius < 0 ); } + /** + * Makes this sphere empty which means in encloses a zero space in 3D. + * + * @return {Sphere} A reference to this sphere. + */ makeEmpty() { this.center.set( 0, 0, 0 ); @@ -77,18 +141,39 @@ class Sphere { } + /** + * Returns `true` if this sphere contains the given point inclusive of + * the surface of the sphere. + * + * @param {Vector3} point - The point to check. + * @return {boolean} Whether this sphere contains the given point or not. + */ containsPoint( point ) { return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); } + /** + * Returns the closest distance from the boundary of the sphere to the + * given point. If the sphere contains the point, the distance will + * be negative. + * + * @param {Vector3} point - The point to compute the distance to. + * @return {number} The distance to the point. + */ distanceToPoint( point ) { return ( point.distanceTo( this.center ) - this.radius ); } + /** + * Returns `true` if this sphere intersects with the given one. + * + * @param {Sphere} sphere - The sphere to test. + * @return {boolean} Whether this sphere intersects with the given one or not. + */ intersectsSphere( sphere ) { const radiusSum = this.radius + sphere.radius; @@ -97,18 +182,39 @@ class Sphere { } + /** + * Returns `true` if this sphere intersects with the given box. + * + * @param {Box3} box - The box to test. + * @return {boolean} Whether this sphere intersects with the given box or not. + */ intersectsBox( box ) { return box.intersectsSphere( this ); } + /** + * Returns `true` if this sphere intersects with the given plane. + * + * @param {Plane} plane - The plane to test. + * @return {boolean} Whether this sphere intersects with the given plane or not. + */ intersectsPlane( plane ) { return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; } + /** + * Clamps a point within the sphere. If the point is outside the sphere, it + * will clamp it to the closest point on the edge of the sphere. Points + * already inside the sphere will not be affected. + * + * @param {Vector3} point - The plane to clamp. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The clamped point. + */ clampPoint( point, target ) { const deltaLengthSq = this.center.distanceToSquared( point ); @@ -126,6 +232,12 @@ class Sphere { } + /** + * Returns a bounding box that encloses this sphere. + * + * @param {Box3} target - The target box that is used to store the method's result. + * @return {Box3} The bounding box that encloses this sphere. + */ getBoundingBox( target ) { if ( this.isEmpty() ) { @@ -143,6 +255,12 @@ class Sphere { } + /** + * Transforms this sphere with the given 4x4 transformation matrix. + * + * @param {Matrix4} matrix - The transformation matrix. + * @return {Sphere} A reference to this sphere. + */ applyMatrix4( matrix ) { this.center.applyMatrix4( matrix ); @@ -152,6 +270,12 @@ class Sphere { } + /** + * Translates the sphere's center by the given offset. + * + * @param {Vector3} offset - The offset. + * @return {Sphere} A reference to this sphere. + */ translate( offset ) { this.center.add( offset ); @@ -160,6 +284,12 @@ class Sphere { } + /** + * Expands the boundaries of this sphere to include the given point. + * + * @param {Vector3} point - The point to include. + * @return {Sphere} A reference to this sphere. + */ expandByPoint( point ) { if ( this.isEmpty() ) { @@ -194,6 +324,12 @@ class Sphere { } + /** + * Expands this sphere to enclose both the original sphere and the given sphere. + * + * @param {Sphere} sphere - The sphere to include. + * @return {Sphere} A reference to this sphere. + */ union( sphere ) { if ( sphere.isEmpty() ) { @@ -228,12 +364,23 @@ class Sphere { } + /** + * Returns `true` if this sphere is equal with the given one. + * + * @param {Sphere} sphere - The sphere to test for equality. + * @return {boolean} Whether this bounding sphere is equal with the given one. + */ equals( sphere ) { return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); } + /** + * Returns a new sphere with copied values from this instance. + * + * @return {Sphere} A clone of this instance. + */ clone() { return new this.constructor().copy( this ); diff --git a/src/math/Triangle.js b/src/math/Triangle.js index 2b0bbcd136a87a..b9af2747463ae2 100644 --- a/src/math/Triangle.js +++ b/src/math/Triangle.js @@ -17,16 +17,52 @@ const _v40 = /*@__PURE__*/ new Vector4(); const _v41 = /*@__PURE__*/ new Vector4(); const _v42 = /*@__PURE__*/ new Vector4(); +/** + * A geometric triangle as defined by three vectors representing its three corners. + */ class Triangle { + /** + * Constructs a new triangle. + * + * @param {Vector3} [a=(0,0,0)] - The first corner of the triangle. + * @param {Vector3} [b=(0,0,0)] - The second corner of the triangle. + * @param {Vector3} [c=(0,0,0)] - The third corner of the triangle. + */ constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { + /** + * The first corner of the triangle. + * + * @type {Vector3} + */ this.a = a; + + /** + * The second corner of the triangle. + * + * @type {Vector3} + */ this.b = b; + + /** + * The third corner of the triangle. + * + * @type {Vector3} + */ this.c = c; } + /** + * Computes the normal vector of a triangle. + * + * @param {Vector3} a - The first corner of the triangle. + * @param {Vector3} b - The second corner of the triangle. + * @param {Vector3} c - The third corner of the triangle. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The triangle's normal. + */ static getNormal( a, b, c, target ) { target.subVectors( c, b ); @@ -44,10 +80,21 @@ class Triangle { } - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html + /** + * Copmutes a barycentric coordinates from the given vector. + * Returns `null` if the triangle is degenerate. + * + * @param {Vector3} point - A point in 3D space. + * @param {Vector3} a - The first corner of the triangle. + * @param {Vector3} b - The second corner of the triangle. + * @param {Vector3} c - The third corner of the triangle. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {?Vector3} The barycentric coordinates for the given point + */ static getBarycoord( point, a, b, c, target ) { + // based on: http://www.blackpawn.com/texts/pointinpoly/default.html + _v0.subVectors( c, a ); _v1.subVectors( b, a ); _v2.subVectors( point, a ); @@ -77,6 +124,17 @@ class Triangle { } + /** + * Returns `true` if the given point, when projected onto the plane of the + * triangle, lies within the triangle. + * + * @param {Vector3} point - The point in 3D space to test. + * @param {Vector3} a - The first corner of the triangle. + * @param {Vector3} b - The second corner of the triangle. + * @param {Vector3} c - The third corner of the triangle. + * @return {boolean} Whether the given point, when projected onto the plane of the + * triangle, lies within the triangle or not. + */ static containsPoint( point, a, b, c ) { // if the triangle is degenerate then we can't contain a point @@ -90,6 +148,20 @@ class Triangle { } + /** + * Computes the value barycentrically interpolated for the given point on the + * triangle. Returns `null` if the triangle is degenerate. + * + * @param {Vector3} point - Position of interpolated point. + * @param {Vector3} p1 - The first corner of the triangle. + * @param {Vector3} p2 - The second corner of the triangle. + * @param {Vector3} p3 - The third corner of the triangle. + * @param {Vector3} v1 - Value to interpolate of first vertex. + * @param {Vector3} v2 - Value to interpolate of second vertex. + * @param {Vector3} v3 - Value to interpolate of third vertex. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {?Vector3} The interpolated value. + */ static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) { if ( this.getBarycoord( point, p1, p2, p3, _v3 ) === null ) { @@ -111,6 +183,17 @@ class Triangle { } + /** + * Computes the value barycentrically interpolated for the given attribute and indices. + * + * @param {BufferAttribute} attr - The attribute to interpolate. + * @param {number} i1 - Index of first vertex. + * @param {number} i2 - Index of second vertex. + * @param {number} i3 - Index of third vertex. + * @param {Vector3} barycoord - The barycoordinate value to use to interpolate. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The interpolated attribute value. + */ static getInterpolatedAttribute( attr, i1, i2, i3, barycoord, target ) { _v40.setScalar( 0 ); @@ -130,6 +213,15 @@ class Triangle { } + /** + * Returns `true` if the triangle is oriented towards the given direction. + * + * @param {Vector3} a - The first corner of the triangle. + * @param {Vector3} b - The second corner of the triangle. + * @param {Vector3} c - The third corner of the triangle. + * @param {Vector3} direction - The (normalized) direction vector. + * @return {boolean} Whether the triangle is oriented towards the given direction or not. + */ static isFrontFacing( a, b, c, direction ) { _v0.subVectors( c, b ); @@ -140,6 +232,14 @@ class Triangle { } + /** + * Sets the triangle's vertices by copying the given values. + * + * @param {Vector3} a - The first corner of the triangle. + * @param {Vector3} b - The second corner of the triangle. + * @param {Vector3} c - The third corner of the triangle. + * @return {Triangle} A reference to this triangle. + */ set( a, b, c ) { this.a.copy( a ); @@ -150,6 +250,15 @@ class Triangle { } + /** + * Sets the triangle's vertices by copying the given array values. + * + * @param {Array} points - An array with 3D points. + * @param {number} i0 - The array index representing the first corner of the triangle. + * @param {number} i1 - The array index representing the second corner of the triangle. + * @param {number} i2 - The array index representing the third corner of the triangle. + * @return {Triangle} A reference to this triangle. + */ setFromPointsAndIndices( points, i0, i1, i2 ) { this.a.copy( points[ i0 ] ); @@ -160,6 +269,15 @@ class Triangle { } + /** + * Sets the triangle's vertices by copying the given attribute values. + * + * @param {BufferAttribute} attribute - A buffer attribute with 3D points data. + * @param {number} i0 - The attribute index representing the first corner of the triangle. + * @param {number} i1 - The attribute index representing the second corner of the triangle. + * @param {number} i2 - The attribute index representing the third corner of the triangle. + * @return {Triangle} A reference to this triangle. + */ setFromAttributeAndIndices( attribute, i0, i1, i2 ) { this.a.fromBufferAttribute( attribute, i0 ); @@ -170,12 +288,23 @@ class Triangle { } + /** + * Returns a new triangle with copied values from this instance. + * + * @return {Triangle} A clone of this instance. + */ clone() { return new this.constructor().copy( this ); } + /** + * Copies the values of the given triangle to this instance. + * + * @param {Triangle} triangle - The triangle to copy. + * @return {Triangle} A reference to this triangle. + */ copy( triangle ) { this.a.copy( triangle.a ); @@ -186,6 +315,11 @@ class Triangle { } + /** + * Computes the area of the triangle. + * + * @return {number} The triangle's area. + */ getArea() { _v0.subVectors( this.c, this.b ); @@ -195,54 +329,118 @@ class Triangle { } + /** + * Computes the midpoint of the triangle. + * + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The triangle's midpoint. + */ getMidpoint( target ) { return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); } + /** + * Computes the normal of the triangle. + * + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The triangle's normal. + */ getNormal( target ) { return Triangle.getNormal( this.a, this.b, this.c, target ); } + /** + * Computes a plane the triangle lies within. + * + * @param {Plane} target - The target vector that is used to store the method's result. + * @return {Plane} The plane the triangle lies within. + */ getPlane( target ) { return target.setFromCoplanarPoints( this.a, this.b, this.c ); } + /** + * Copmutes a barycentric coordinates from the given vector. + * Returns `null` if the triangle is degenerate. + * + * @param {Vector3} point - A point in 3D space. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {?Vector3} The barycentric coordinates for the given point + */ getBarycoord( point, target ) { return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); } + /** + * Computes the value barycentrically interpolated for the given point on the + * triangle. Returns `null` if the triangle is degenerate. + * + * @param {Vector3} point - Position of interpolated point. + * @param {Vector3} v1 - Value to interpolate of first vertex. + * @param {Vector3} v2 - Value to interpolate of second vertex. + * @param {Vector3} v3 - Value to interpolate of third vertex. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {?Vector3} The interpolated value. + */ getInterpolation( point, v1, v2, v3, target ) { return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target ); } + /** + * Returns `true` if the given point, when projected onto the plane of the + * triangle, lies within the triangle. + * + * @param {Vector3} point - The point in 3D space to test. + * @return {boolean} Whether the given point, when projected onto the plane of the + * triangle, lies within the triangle or not. + */ containsPoint( point ) { return Triangle.containsPoint( point, this.a, this.b, this.c ); } + /** + * Returns `true` if the triangle is oriented towards the given direction. + * + * @param {Vector3} direction - The (normalized) direction vector. + * @return {boolean} Whether the triangle is oriented towards the given direction or not. + */ isFrontFacing( direction ) { return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); } + /** + * Returns `true` if this triangle intersects with the given box. + * + * @param {Box3} box - The box to intersect. + * @return {boolean} Whether this triangle intersects with the given box or not. + */ intersectsBox( box ) { return box.intersectsTriangle( this ); } + /** + * Returns the closest point on the triangle to the given point. + * + * @param {Vector3} p - The point to compute the closest point for. + * @param {Vector3} target - The target vector that is used to store the method's result. + * @return {Vector3} The closest point on the triangle. + */ closestPointToPoint( p, target ) { const a = this.a, b = this.b, c = this.c; @@ -324,6 +522,12 @@ class Triangle { } + /** + * Returns `true` if this triangle is equal with the given one. + * + * @param {Triangle} triangle - The triangle to test for equality. + * @return {boolean} Whether this triangle is equal with the given one. + */ equals( triangle ) { return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); diff --git a/src/math/interpolants/CubicInterpolant.js b/src/math/interpolants/CubicInterpolant.js index 14c9b58f0bdde6..24b3096de529e1 100644 --- a/src/math/interpolants/CubicInterpolant.js +++ b/src/math/interpolants/CubicInterpolant.js @@ -7,10 +7,19 @@ import { Interpolant } from '../Interpolant.js'; * It was derived from a Hermitian construction setting the first derivative * at each sample position to the linear slope between neighboring positions * over their parameter interval. + * + * @augments Interpolant */ - class CubicInterpolant extends Interpolant { + /** + * Constructs a new cubic interpolant. + * + * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. + * @param {TypedArray} sampleValues - The sample values. + * @param {number} sampleSize - The sample size + * @param {TypedArray} [resultBuffer] - The result buffer. + */ constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { super( parameterPositions, sampleValues, sampleSize, resultBuffer ); diff --git a/src/math/interpolants/DiscreteInterpolant.js b/src/math/interpolants/DiscreteInterpolant.js index 99331213156d02..87e31d5ec1a8ba 100644 --- a/src/math/interpolants/DiscreteInterpolant.js +++ b/src/math/interpolants/DiscreteInterpolant.js @@ -1,13 +1,21 @@ import { Interpolant } from '../Interpolant.js'; /** - * * Interpolant that evaluates to the sample value at the position preceding * the parameter. + * + * @augments Interpolant */ - class DiscreteInterpolant extends Interpolant { + /** + * Constructs a new discrete interpolant. + * + * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. + * @param {TypedArray} sampleValues - The sample values. + * @param {number} sampleSize - The sample size + * @param {TypedArray} [resultBuffer] - The result buffer. + */ constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { super( parameterPositions, sampleValues, sampleSize, resultBuffer ); diff --git a/src/math/interpolants/LinearInterpolant.js b/src/math/interpolants/LinearInterpolant.js index dae736e2fe4074..4729c13494ec17 100644 --- a/src/math/interpolants/LinearInterpolant.js +++ b/src/math/interpolants/LinearInterpolant.js @@ -1,7 +1,20 @@ import { Interpolant } from '../Interpolant.js'; +/** + * A basic linear interpolant. + * + * @augments Interpolant + */ class LinearInterpolant extends Interpolant { + /** + * Constructs a new linear interpolant. + * + * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. + * @param {TypedArray} sampleValues - The sample values. + * @param {number} sampleSize - The sample size + * @param {TypedArray} [resultBuffer] - The result buffer. + */ constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { super( parameterPositions, sampleValues, sampleSize, resultBuffer ); diff --git a/src/math/interpolants/QuaternionLinearInterpolant.js b/src/math/interpolants/QuaternionLinearInterpolant.js index 3b8bd4f221095f..d6c999b30351e5 100644 --- a/src/math/interpolants/QuaternionLinearInterpolant.js +++ b/src/math/interpolants/QuaternionLinearInterpolant.js @@ -3,10 +3,19 @@ import { Quaternion } from '../Quaternion.js'; /** * Spherical linear unit quaternion interpolant. + * + * @augments Interpolant */ - class QuaternionLinearInterpolant extends Interpolant { + /** + * Constructs a new SLERP interpolant. + * + * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. + * @param {TypedArray} sampleValues - The sample values. + * @param {number} sampleSize - The sample size + * @param {TypedArray} [resultBuffer] - The result buffer. + */ constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { super( parameterPositions, sampleValues, sampleSize, resultBuffer );