diff --git a/packages/dev/core/src/Cameras/camera.ts b/packages/dev/core/src/Cameras/camera.ts index 888b0d4eeab..792793823e2 100644 --- a/packages/dev/core/src/Cameras/camera.ts +++ b/packages/dev/core/src/Cameras/camera.ts @@ -2,7 +2,7 @@ import { serialize, SerializationHelper, serializeAsVector3 } from "../Misc/deco import { SmartArray } from "../Misc/smartArray"; import { Tools } from "../Misc/tools"; import { Observable } from "../Misc/observable"; -import type { Nullable } from "../types"; +import type { DeepImmutable, Nullable } from "../types"; import type { CameraInputsManager } from "./cameraInputsManager"; import type { Scene } from "../scene"; import { Matrix, Vector3, Quaternion } from "../Maths/math.vector"; @@ -1361,7 +1361,7 @@ export class Camera extends Node { * @param localAxis Defines the reference axis to provide a relative direction. * @returns the direction */ - public getDirection(localAxis: Vector3): Vector3 { + public getDirection(localAxis: DeepImmutable): Vector3 { const result = Vector3.Zero(); this.getDirectionToRef(localAxis, result); @@ -1383,7 +1383,7 @@ export class Camera extends Node { * @param localAxis Defines the reference axis to provide a relative direction. * @param result Defines the vector to store the result in */ - public getDirectionToRef(localAxis: Vector3, result: Vector3): void { + public getDirectionToRef(localAxis: DeepImmutable, result: Vector3): void { Vector3.TransformNormalToRef(localAxis, this.getWorldMatrix(), result); } diff --git a/packages/dev/core/src/Debug/directionalLightFrustumViewer.ts b/packages/dev/core/src/Debug/directionalLightFrustumViewer.ts index 23465816f21..8dccaef5915 100644 --- a/packages/dev/core/src/Debug/directionalLightFrustumViewer.ts +++ b/packages/dev/core/src/Debug/directionalLightFrustumViewer.ts @@ -247,32 +247,32 @@ export class DirectionalLightFrustumViewer { this._rootNode = new TransformNode("directionalLightHelperRoot_" + this._light.name, this._scene); this._rootNode.parent = this._light.parent; - this._nearLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly]; + this._nearLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly] as Vector3[]; const nearLines = CreateLines("nearlines", { updatable: true, points: this._nearLinesPoints }, this._scene); nearLines.parent = this._rootNode; nearLines.alwaysSelectAsActiveMesh = true; - this._farLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly]; + this._farLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly, Vector3.ZeroReadOnly] as Vector3[]; const farLines = CreateLines("farlines", { updatable: true, points: this._farLinesPoints }, this._scene); farLines.parent = this._rootNode; farLines.alwaysSelectAsActiveMesh = true; - this._trLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly]; + this._trLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly] as Vector3[]; const trLines = CreateLines("trlines", { updatable: true, points: this._trLinesPoints }, this._scene); trLines.parent = this._rootNode; trLines.alwaysSelectAsActiveMesh = true; - this._brLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly]; + this._brLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly] as Vector3[]; const brLines = CreateLines("brlines", { updatable: true, points: this._brLinesPoints }, this._scene); brLines.parent = this._rootNode; brLines.alwaysSelectAsActiveMesh = true; - this._tlLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly]; + this._tlLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly] as Vector3[]; const tlLines = CreateLines("tllines", { updatable: true, points: this._tlLinesPoints }, this._scene); tlLines.parent = this._rootNode; tlLines.alwaysSelectAsActiveMesh = true; - this._blLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly]; + this._blLinesPoints = [Vector3.ZeroReadOnly, Vector3.ZeroReadOnly] as Vector3[]; const blLines = CreateLines("bllines", { updatable: true, points: this._blLinesPoints }, this._scene); blLines.parent = this._rootNode; blLines.alwaysSelectAsActiveMesh = true; diff --git a/packages/dev/core/src/Maths/math.color.ts b/packages/dev/core/src/Maths/math.color.ts index a53077bc81c..4c1605604d7 100644 --- a/packages/dev/core/src/Maths/math.color.ts +++ b/packages/dev/core/src/Maths/math.color.ts @@ -1,8 +1,9 @@ -import type { DeepImmutable, FloatArray } from "../types"; +import type { Constructor, DeepImmutable, FloatArray } from "../types"; import { Scalar } from "./math.scalar"; -import { ToLinearSpace, ToGammaSpace } from "./math.constants"; +import { ToLinearSpace, ToGammaSpace, Epsilon } from "./math.constants"; import { ArrayTools } from "../Misc/arrayTools"; import { RegisterClass } from "../Misc/typeStore"; +import type { VectorLike } from "./math.vector"; function colorChannelToLinearSpace(color: number): number { return Math.pow(color, ToLinearSpace); @@ -29,7 +30,9 @@ function colorChannelToGammaSpaceExact(color: number): number { /** * Class used to hold a RGB color */ -export class Color3 { +export class Color3 implements VectorLike<[number, number, number]> { + public readonly dimension: [number] = [3]; + /** * Creates a new Color3 object from red, green, blue values, all between 0 and 1 * @param r defines the red component (between 0 and 1, default is 0) @@ -86,7 +89,7 @@ export class Color3 { * @param index defines an optional index in the target array to define where to start storing values * @returns the current Color3 object */ - public toArray(array: FloatArray, index: number = 0): Color3 { + public toArray(array: FloatArray, index: number = 0): this { array[index] = this.r; array[index + 1] = this.g; array[index + 2] = this.b; @@ -100,7 +103,7 @@ export class Color3 { * @param offset defines an offset in the source array * @returns the current Color3 object */ - public fromArray(array: DeepImmutable>, offset: number = 0): Color3 { + public fromArray(array: DeepImmutable>, offset: number = 0): this { Color3.FromArrayToRef(array, offset, this); return this; } @@ -118,7 +121,7 @@ export class Color3 { * Returns a new array populated with 3 numeric elements : red, green and blue values * @returns the new array */ - public asArray(): number[] { + public asArray(): [number, number, number] { return [this.r, this.g, this.b]; } @@ -135,32 +138,179 @@ export class Color3 { * @param otherColor defines the second operand * @returns the new Color3 object */ - public multiply(otherColor: DeepImmutable): Color3 { - return new Color3(this.r * otherColor.r, this.g * otherColor.g, this.b * otherColor.b); + public multiply(otherColor: DeepImmutable): this { + return new (this.constructor as Constructor)(this.r * otherColor.r, this.g * otherColor.g, this.b * otherColor.b); } /** * Multiply the rgb values of the Color3 and the given Color3 and stores the result in the object "result" * @param otherColor defines the second operand * @param result defines the Color3 object where to store the result - * @returns the current Color3 + * @returns the result Color3 */ - public multiplyToRef(otherColor: DeepImmutable, result: Color3): Color3 { + public multiplyToRef(otherColor: DeepImmutable, result: T): T { result.r = this.r * otherColor.r; result.g = this.g * otherColor.g; result.b = this.b * otherColor.b; + return result; + } + + /** + * Multiplies the current Color3 coordinates by the given ones + * @param otherColor defines the second operand + * @returns the current updated Color3 + */ + public multiplyInPlace(otherColor: DeepImmutable): this { + this.r *= otherColor.r; + this.g *= otherColor.g; + this.b *= otherColor.b; return this; } + /** + * Returns a new Color3 set with the result of the multiplication of the current Color3 coordinates by the given floats + * @param r defines the r coordinate of the operand + * @param g defines the g coordinate of the operand + * @param b defines the b coordinate of the operand + * @returns the new Color3 + */ + public multiplyByFloats(r: number, g: number, b: number): this { + return new (this.constructor as Constructor)(this.r * r, this.g * g, this.b * b); + } + + /** + * Returns a new Color3 set with the result of the division of the current Color3 coordinates by the given ones + * @param otherColor defines the second operand + * @returns the new Color3 + */ + public divide(otherColor: DeepImmutable): this { + return new (this.constructor as Constructor)(this.r / otherColor.r, this.g / otherColor.g, this.b / otherColor.b); + } + + /** + * Divides the current Color3 coordinates by the given ones and stores the result in the given color "result" + * @param otherColor defines the second operand + * @param result defines the Color3 object where to store the result + * @returns the result + */ + public divideToRef(otherColor: DeepImmutable, result: T): T { + return result.copyFromFloats(this.r / otherColor.r, this.g / otherColor.g, this.b / otherColor.b); + } + + /** + * Divides the current Color3 coordinates by the given ones. + * @param otherColor defines the second operand + * @returns the current updated Color3 + */ + public divideInPlace(otherColor: DeepImmutable): this { + this.r = this.r / otherColor.r; + this.g = this.g / otherColor.g; + this.b = this.b / otherColor.b; + return this; + } + + /** + * Updates the current Color3 with the minimal coordinate values between its and the given color ones + * @param other defines the second operand + * @returns the current updated Color3 + */ + public minimizeInPlace(other: DeepImmutable): this { + return this.minimizeInPlaceFromFloats(other.r, other.g, other.b); + } + + /** + * Updates the current Color3 with the maximal coordinate values between its and the given color ones. + * @param other defines the second operand + * @returns the current updated Color3 + */ + public maximizeInPlace(other: DeepImmutable): this { + return this.maximizeInPlaceFromFloats(other.r, other.g, other.b); + } + + /** + * Updates the current Color3 with the minimal coordinate values between its and the given coordinates + * @param r defines the r coordinate of the operand + * @param g defines the g coordinate of the operand + * @param b defines the b coordinate of the operand + * @returns the current updated Color3 + */ + public minimizeInPlaceFromFloats(r: number, g: number, b: number): this { + this.r = Math.min(r, this.r); + this.g = Math.min(g, this.g); + this.b = Math.min(b, this.b); + return this; + } + + /** + * Updates the current Color3 with the maximal coordinate values between its and the given coordinates. + * @param r defines the r coordinate of the operand + * @param g defines the g coordinate of the operand + * @param b defines the b coordinate of the operand + * @returns the current updated Color3 + */ + public maximizeInPlaceFromFloats(r: number, g: number, b: number): this { + this.r = Math.max(r, this.r); + this.g = Math.max(g, this.g); + this.b = Math.max(b, this.b); + return this; + } + + /** + * Gets the current Color3's floored values and stores them in result + * @param result the color to store the result in + * @returns the result color + */ + public floorToRef(result: T): T { + result.r = Math.floor(this.r); + result.g = Math.floor(this.g); + result.b = Math.floor(this.b); + return result; + } + + /** + * Gets a new Color3 from current Color3 floored values + * @returns a new Color3 + */ + public floor(): this { + return new (this.constructor as Constructor)(Math.floor(this.r), Math.floor(this.g), Math.floor(this.b)); + } + + /** + * Gets the current Color3's fractional values and stores them in result + * @param result the color to store the result in + * @returns the result color + */ + public fractToRef(result: T): T { + result.r = this.r - Math.floor(this.r); + result.g = this.g - Math.floor(this.g); + result.b = this.b - Math.floor(this.b); + return result; + } + + /** + * Gets a new Color3 from current Color3 fractional values + * @returns a new Color3 + */ + public fract(): this { + return new (this.constructor as Constructor)(this.r - Math.floor(this.r), this.g - Math.floor(this.g), this.b - Math.floor(this.b)); + } + /** * Determines equality between Color3 objects * @param otherColor defines the second operand * @returns true if the rgb values are equal to the given ones */ - public equals(otherColor: DeepImmutable): boolean { + public equals(otherColor: DeepImmutable): boolean { return otherColor && this.r === otherColor.r && this.g === otherColor.g && this.b === otherColor.b; } + /** + * Alias for equalsToFloats + */ + public equalsFloats(r: number, g: number, b: number): boolean { + return this.equalsToFloats(r, g, b); + } + /** * Determines equality between the current Color3 object and a set of r,b,g values * @param r defines the red component to check @@ -168,17 +318,60 @@ export class Color3 { * @param b defines the blue component to check * @returns true if the rgb values are equal to the given ones */ - public equalsFloats(r: number, g: number, b: number): boolean { + public equalsToFloats(r: number, g: number, b: number): boolean { return this.r === r && this.g === g && this.b === b; } + /** + * Returns true if the current Color3 and the given color coordinates are distant less than epsilon + * @param otherColor defines the second operand + * @param epsilon defines the minimal distance to define values as equals + * @returns true if both colors are distant less than epsilon + */ + public equalsWithEpsilon(otherColor: DeepImmutable, epsilon: number = Epsilon): boolean { + return ( + otherColor && + Scalar.WithinEpsilon(this.r, otherColor.r, epsilon) && + Scalar.WithinEpsilon(this.g, otherColor.g, epsilon) && + Scalar.WithinEpsilon(this.b, otherColor.b, epsilon) + ); + } + + /** + * Gets a new Color3 set with the current Color3 negated coordinates + * @returns a new Color3 + */ + public negate(): this { + return new (this.constructor as Constructor)(-this.r, -this.g, -this.b); + } + + /** + * Negate this color in place + * @returns this + */ + public negateInPlace(): this { + this.r *= -1; + this.g *= -1; + this.b *= -1; + return this; + } + + /** + * Negate the current Color3 and stores the result in the given color "result" coordinates + * @param result defines the Color3 object where to store the result + * @returns the result + */ + public negateToRef(result: T): T { + return result.copyFromFloats(this.r * -1, this.g * -1, this.b * -1); + } + /** * Creates a new Color3 with the current Color3 values multiplied by scale * @param scale defines the scaling factor to apply * @returns a new Color3 object */ - public scale(scale: number): Color3 { - return new Color3(this.r * scale, this.g * scale, this.b * scale); + public scale(scale: number): this { + return new (this.constructor as Constructor)(this.r * scale, this.g * scale, this.b * scale); } /** @@ -186,7 +379,7 @@ export class Color3 { * @param scale defines the scaling factor to apply * @returns the current updated Color3 */ - public scaleInPlace(scale: number): Color3 { + public scaleInPlace(scale: number): this { this.r *= scale; this.g *= scale; this.b *= scale; @@ -197,26 +390,26 @@ export class Color3 { * Multiplies the rgb values by scale and stores the result into "result" * @param scale defines the scaling factor * @param result defines the Color3 object where to store the result - * @returns the unmodified current Color3 + * @returns the result Color3 */ - public scaleToRef(scale: number, result: Color3): Color3 { + public scaleToRef(scale: number, result: T): T { result.r = this.r * scale; result.g = this.g * scale; result.b = this.b * scale; - return this; + return result; } /** * Scale the current Color3 values by a factor and add the result to a given Color3 * @param scale defines the scale factor * @param result defines color to store the result into - * @returns the unmodified current Color3 + * @returns the result Color3 */ - public scaleAndAddToRef(scale: number, result: Color3): Color3 { + public scaleAndAddToRef(scale: number, result: T): T { result.r += this.r * scale; result.g += this.g * scale; result.b += this.b * scale; - return this; + return result; } /** @@ -224,13 +417,13 @@ export class Color3 { * @param min defines minimum clamping value (default is 0) * @param max defines maximum clamping value (default is 1) * @param result defines color to store the result into - * @returns the original Color3 + * @returns the result Color3 */ - public clampToRef(min: number = 0, max: number = 1, result: Color3): Color3 { + public clampToRef(min: number = 0, max: number = 1, result: T): T { result.r = Scalar.Clamp(this.r, min, max); result.g = Scalar.Clamp(this.g, min, max); result.b = Scalar.Clamp(this.b, min, max); - return this; + return result; } /** @@ -238,8 +431,34 @@ export class Color3 { * @param otherColor defines the second operand * @returns the new Color3 */ - public add(otherColor: DeepImmutable): Color3 { - return new Color3(this.r + otherColor.r, this.g + otherColor.g, this.b + otherColor.b); + public add(otherColor: DeepImmutable): this { + return new (this.constructor as Constructor)(this.r + otherColor.r, this.g + otherColor.g, this.b + otherColor.b); + } + + /** + * Adds the given color to the current Color3 + * @param otherColor defines the second operand + * @returns the current updated Color3 + */ + public addInPlace(otherColor: DeepImmutable): this { + this.r += otherColor.r; + this.g += otherColor.g; + this.b += otherColor.b; + return this; + } + + /** + * Adds the given coordinates to the current Color3 + * @param r defines the r coordinate of the operand + * @param g defines the g coordinate of the operand + * @param b defines the b coordinate of the operand + * @returns the current updated Color3 + */ + public addInPlaceFromFloats(r: number, g: number, b: number): this { + this.r += r; + this.g += g; + this.b += b; + return this; } /** @@ -248,11 +467,11 @@ export class Color3 { * @param result defines Color3 object to store the result into * @returns the unmodified current Color3 */ - public addToRef(otherColor: DeepImmutable, result: Color3): Color3 { + public addToRef(otherColor: DeepImmutable, result: T): T { result.r = this.r + otherColor.r; result.g = this.g + otherColor.g; result.b = this.b + otherColor.b; - return this; + return result; } /** @@ -260,8 +479,8 @@ export class Color3 { * @param otherColor defines the second operand * @returns the new Color3 */ - public subtract(otherColor: DeepImmutable): Color3 { - return new Color3(this.r - otherColor.r, this.g - otherColor.g, this.b - otherColor.b); + public subtract(otherColor: DeepImmutable): this { + return new (this.constructor as Constructor)(this.r - otherColor.r, this.g - otherColor.g, this.b - otherColor.b); } /** @@ -270,19 +489,54 @@ export class Color3 { * @param result defines Color3 object to store the result into * @returns the unmodified current Color3 */ - public subtractToRef(otherColor: DeepImmutable, result: Color3): Color3 { + public subtractToRef(otherColor: DeepImmutable, result: T): T { result.r = this.r - otherColor.r; result.g = this.g - otherColor.g; result.b = this.b - otherColor.b; + return result; + } + + /** + * Subtract the given color from the current Color3 + * @param otherColor defines the second operand + * @returns the current updated Color3 + */ + public subtractInPlace(otherColor: DeepImmutable): this { + this.r -= otherColor.r; + this.g -= otherColor.g; + this.b -= otherColor.b; return this; } + /** + * Returns a new Color3 set with the subtraction of the given floats from the current Color3 coordinates + * @param r defines the r coordinate of the operand + * @param g defines the g coordinate of the operand + * @param b defines the b coordinate of the operand + * @returns the resulting Color3 + */ + public subtractFromFloats(r: number, g: number, b: number): this { + return new (this.constructor as Constructor)(this.r - r, this.g - g, this.b - b); + } + + /** + * Subtracts the given floats from the current Color3 coordinates and set the given color "result" with this result + * @param r defines the r coordinate of the operand + * @param g defines the g coordinate of the operand + * @param b defines the b coordinate of the operand + * @param result defines the Color3 object where to store the result + * @returns the result + */ + public subtractFromFloatsToRef(r: number, g: number, b: number, result: T): T { + return result.copyFromFloats(this.r - r, this.g - g, this.b - b); + } + /** * Copy the current object * @returns a new Color3 copied the current one */ - public clone(): Color3 { - return new Color3(this.r, this.g, this.b); + public clone(): this { + return new (this.constructor as Constructor)(this.r, this.g, this.b); } /** @@ -290,7 +544,7 @@ export class Color3 { * @param source defines the source Color3 object * @returns the updated Color3 object */ - public copyFrom(source: DeepImmutable): Color3 { + public copyFrom(source: DeepImmutable): this { this.r = source.r; this.g = source.g; this.b = source.b; @@ -304,7 +558,7 @@ export class Color3 { * @param b defines the blue component to read from * @returns the current Color3 object */ - public copyFromFloats(r: number, g: number, b: number): Color3 { + public copyFromFloats(r: number, g: number, b: number): this { this.r = r; this.g = g; this.b = b; @@ -318,10 +572,20 @@ export class Color3 { * @param b defines the blue component to read from * @returns the current Color3 object */ - public set(r: number, g: number, b: number): Color3 { + public set(r: number, g: number, b: number): this { return this.copyFromFloats(r, g, b); } + /** + * Copies the given float to the current Color3 coordinates + * @param v defines the r, g and b coordinates of the operand + * @returns the current updated Color3 + */ + public setAll(v: number): this { + this.r = this.g = this.b = v; + return this; + } + /** * Compute the Color3 hexadecimal code as a string * @returns a string containing the hexadecimal representation of the Color3 object @@ -337,8 +601,8 @@ export class Color3 { * Converts current color in rgb space to HSV values * @returns a new color3 representing the HSV values */ - public toHSV(): Color3 { - const result = new Color3(); + public toHSV(): this { + const result = new (this.constructor as Constructor)(); this.toHSVToRef(result); @@ -349,7 +613,7 @@ export class Color3 { * Converts current color in rgb space to HSV values * @param result defines the Color3 where to store the HSV values */ - public toHSVToRef(result: Color3) { + public toHSVToRef(result: this) { const r = this.r; const g = this.g; const b = this.b; @@ -390,8 +654,8 @@ export class Color3 { * @param exact defines if the conversion will be done in an exact way which is slower but more accurate (default is false) * @returns a new Color3 object */ - public toLinearSpace(exact = false): Color3 { - const convertedColor = new Color3(); + public toLinearSpace(exact = false): this { + const convertedColor = new (this.constructor as Constructor)(); this.toLinearSpaceToRef(convertedColor, exact); return convertedColor; } @@ -402,7 +666,7 @@ export class Color3 { * @param exact defines if the conversion will be done in an exact way which is slower but more accurate (default is false) * @returns the unmodified Color3 */ - public toLinearSpaceToRef(convertedColor: Color3, exact = false): Color3 { + public toLinearSpaceToRef(convertedColor: this, exact = false): this { if (exact) { convertedColor.r = colorChannelToLinearSpaceExact(this.r); convertedColor.g = colorChannelToLinearSpaceExact(this.g); @@ -420,8 +684,8 @@ export class Color3 { * @param exact defines if the conversion will be done in an exact way which is slower but more accurate (default is false) * @returns a new Color3 object */ - public toGammaSpace(exact = false): Color3 { - const convertedColor = new Color3(); + public toGammaSpace(exact = false): this { + const convertedColor = new (this.constructor as Constructor)(); this.toGammaSpaceToRef(convertedColor, exact); return convertedColor; } @@ -432,7 +696,7 @@ export class Color3 { * @param exact defines if the conversion will be done in an exact way which is slower but more accurate (default is false) * @returns the unmodified Color3 */ - public toGammaSpaceToRef(convertedColor: Color3, exact = false): Color3 { + public toGammaSpaceToRef(convertedColor: this, exact = false): this { if (exact) { convertedColor.r = colorChannelToGammaSpaceExact(this.r); convertedColor.g = colorChannelToGammaSpaceExact(this.g); @@ -737,7 +1001,9 @@ export class Color3 { /** * Class used to hold a RBGA color */ -export class Color4 { +export class Color4 implements VectorLike<[number, number, number, number]> { + public readonly dimension: [number] = [4]; + /** * Creates a new Color4 object from red, green, blue values, all between 0 and 1 * @param r defines the red component (between 0 and 1, default is 0) @@ -766,24 +1032,11 @@ export class Color4 { // Operators - /** - * Adds in place the given Color4 values to the current Color4 object - * @param right defines the second operand - * @returns the current updated Color4 object - */ - public addInPlace(right: DeepImmutable): Color4 { - this.r += right.r; - this.g += right.g; - this.b += right.b; - this.a += right.a; - return this; - } - /** * Creates a new array populated with 4 numeric elements : red, green, blue, alpha values * @returns the new array */ - public asArray(): number[] { + public asArray(): [number, number, number, number] { return [this.r, this.g, this.b, this.a]; } @@ -793,7 +1046,7 @@ export class Color4 { * @param index defines an optional index in the target array to define where to start storing values * @returns the current Color4 object */ - public toArray(array: FloatArray, index: number = 0): Color4 { + public toArray(array: FloatArray, index: number = 0): this { array[index] = this.r; array[index + 1] = this.g; array[index + 2] = this.b; @@ -807,8 +1060,11 @@ export class Color4 { * @param offset defines an offset in the source array * @returns the current Color4 object */ - public fromArray(array: DeepImmutable>, offset: number = 0): Color4 { - Color4.FromArrayToRef(array, offset, this); + public fromArray(array: DeepImmutable>, offset: number = 0): this { + this.r = array[offset]; + this.g = array[offset + 1]; + this.b = array[offset + 2]; + this.a = array[offset + 3]; return this; } @@ -817,49 +1073,134 @@ export class Color4 { * @param otherColor defines the second operand * @returns true if the rgba values are equal to the given ones */ - public equals(otherColor: DeepImmutable): boolean { + public equals(otherColor: DeepImmutable): boolean { return otherColor && this.r === otherColor.r && this.g === otherColor.g && this.b === otherColor.b && this.a === otherColor.a; } /** * Creates a new Color4 set with the added values of the current Color4 and of the given one - * @param right defines the second operand + * @param otherColor defines the second operand * @returns a new Color4 object */ - public add(right: DeepImmutable): Color4 { - return new Color4(this.r + right.r, this.g + right.g, this.b + right.b, this.a + right.a); + public add(otherColor: DeepImmutable): this { + return new (this.constructor as Constructor)(this.r + otherColor.r, this.g + otherColor.g, this.b + otherColor.b, this.a + otherColor.a); + } + + /** + * Updates the given color "result" with the result of the addition of the current Color4 and the given one. + * @param otherColor the color to add + * @param result the color to store the result + * @returns result input + */ + public addToRef(otherColor: DeepImmutable, result: T): T { + result.r = this.r + otherColor.r; + result.g = this.g + otherColor.g; + result.b = this.b + otherColor.b; + result.a = this.a + otherColor.a; + return result; + } + + /** + * Adds in place the given Color4 values to the current Color4 object + * @param otherColor defines the second operand + * @returns the current updated Color4 object + */ + public addInPlace(otherColor: DeepImmutable): this { + this.r += otherColor.r; + this.g += otherColor.g; + this.b += otherColor.b; + this.a += otherColor.a; + return this; + } + + /** + * Adds the given coordinates to the current Color4 + * @param r defines the r coordinate of the operand + * @param g defines the g coordinate of the operand + * @param b defines the b coordinate of the operand + * @param a defines the a coordinate of the operand + * @returns the current updated Color4 + */ + public addInPlaceFromFloats(r: number, g: number, b: number, a: number): this { + this.r += r; + this.g += g; + this.b += b; + this.a += a; + return this; } /** * Creates a new Color4 set with the subtracted values of the given one from the current Color4 - * @param right defines the second operand + * @param otherColor defines the second operand * @returns a new Color4 object */ - public subtract(right: DeepImmutable): Color4 { - return new Color4(this.r - right.r, this.g - right.g, this.b - right.b, this.a - right.a); + public subtract(otherColor: DeepImmutable): this { + return new (this.constructor as Constructor)(this.r - otherColor.r, this.g - otherColor.g, this.b - otherColor.b, this.a - otherColor.a); } /** * Subtracts the given ones from the current Color4 values and stores the results in "result" - * @param right defines the second operand + * @param otherColor defines the second operand * @param result defines the Color4 object where to store the result - * @returns the current Color4 object + * @returns the result Color4 object */ - public subtractToRef(right: DeepImmutable, result: Color4): Color4 { - result.r = this.r - right.r; - result.g = this.g - right.g; - result.b = this.b - right.b; - result.a = this.a - right.a; + public subtractToRef(otherColor: DeepImmutable, result: T): T { + result.r = this.r - otherColor.r; + result.g = this.g - otherColor.g; + result.b = this.b - otherColor.b; + result.a = this.a - otherColor.a; + return result; + } + + /** + * Subtract in place the given color from the current Color4. + * @param otherColor the color to subtract + * @returns the updated Color4. + */ + public subtractInPlace(otherColor: DeepImmutable): this { + this.r -= otherColor.r; + this.g -= otherColor.g; + this.b -= otherColor.b; + this.a -= otherColor.a; return this; } + /** + * Returns a new Color4 set with the result of the subtraction of the given floats from the current Color4 coordinates. + * @param r value to subtract + * @param g value to subtract + * @param b value to subtract + * @param a value to subtract + * @returns new color containing the result + */ + public subtractFromFloats(r: number, g: number, b: number, a: number): this { + return new (this.constructor as Constructor)(this.r - r, this.g - g, this.b - b, this.a - a); + } + + /** + * Sets the given color "result" set with the result of the subtraction of the given floats from the current Color4 coordinates. + * @param r value to subtract + * @param g value to subtract + * @param b value to subtract + * @param a value to subtract + * @param result the color to store the result in + * @returns result input + */ + public subtractFromFloatsToRef(r: number, g: number, b: number, a: number, result: T): T { + result.r = this.r - r; + result.g = this.g - g; + result.b = this.b - b; + result.a = this.a - a; + return result; + } + /** * Creates a new Color4 with the current Color4 values multiplied by scale * @param scale defines the scaling factor to apply * @returns a new Color4 object */ - public scale(scale: number): Color4 { - return new Color4(this.r * scale, this.g * scale, this.b * scale, this.a * scale); + public scale(scale: number): this { + return new (this.constructor as Constructor)(this.r * scale, this.g * scale, this.b * scale, this.a * scale); } /** @@ -867,7 +1208,7 @@ export class Color4 { * @param scale defines the scaling factor to apply * @returns the current updated Color4 */ - public scaleInPlace(scale: number): Color4 { + public scaleInPlace(scale: number): this { this.r *= scale; this.g *= scale; this.b *= scale; @@ -879,28 +1220,28 @@ export class Color4 { * Multiplies the current Color4 values by scale and stores the result in "result" * @param scale defines the scaling factor to apply * @param result defines the Color4 object where to store the result - * @returns the current unmodified Color4 + * @returns the result Color4 */ - public scaleToRef(scale: number, result: Color4): Color4 { + public scaleToRef(scale: number, result: T): T { result.r = this.r * scale; result.g = this.g * scale; result.b = this.b * scale; result.a = this.a * scale; - return this; + return result; } /** * Scale the current Color4 values by a factor and add the result to a given Color4 * @param scale defines the scale factor * @param result defines the Color4 object where to store the result - * @returns the unmodified current Color4 + * @returns the result Color4 */ - public scaleAndAddToRef(scale: number, result: Color4): Color4 { + public scaleAndAddToRef(scale: number, result: T): T { result.r += this.r * scale; result.g += this.g * scale; result.b += this.b * scale; result.a += this.a * scale; - return this; + return result; } /** @@ -908,14 +1249,14 @@ export class Color4 { * @param min defines minimum clamping value (default is 0) * @param max defines maximum clamping value (default is 1) * @param result defines color to store the result into. - * @returns the current Color4 + * @returns the result Color4 */ - public clampToRef(min: number = 0, max: number = 1, result: Color4): Color4 { + public clampToRef(min: number = 0, max: number = 1, result: T): T { result.r = Scalar.Clamp(this.r, min, max); result.g = Scalar.Clamp(this.g, min, max); result.b = Scalar.Clamp(this.b, min, max); result.a = Scalar.Clamp(this.a, min, max); - return this; + return result; } /** @@ -923,8 +1264,8 @@ export class Color4 { * @param color defines the Color4 value to multiply by * @returns a new Color4 object */ - public multiply(color: Color4): Color4 { - return new Color4(this.r * color.r, this.g * color.g, this.b * color.b, this.a * color.a); + public multiply(color: DeepImmutable): this { + return new (this.constructor as Constructor)(this.r * color.r, this.g * color.g, this.b * color.b, this.a * color.a); } /** @@ -933,7 +1274,7 @@ export class Color4 { * @param result defines the Color4 to fill the result in * @returns the result Color4 */ - public multiplyToRef(color: Color4, result: Color4): Color4 { + public multiplyToRef(color: DeepImmutable, result: T): T { result.r = this.r * color.r; result.g = this.g * color.g; result.b = this.b * color.b; @@ -941,6 +1282,223 @@ export class Color4 { return result; } + /** + * Multiplies in place the current Color4 by the given one. + * @param otherColor color to multiple with + * @returns the updated Color4. + */ + public multiplyInPlace(otherColor: DeepImmutable): this { + this.r *= otherColor.r; + this.g *= otherColor.g; + this.b *= otherColor.b; + this.a *= otherColor.a; + return this; + } + + /** + * Returns a new Color4 set with the multiplication result of the given floats and the current Color4 coordinates. + * @param r value multiply with + * @param g value multiply with + * @param b value multiply with + * @param a value multiply with + * @returns resulting new color + */ + public multiplyByFloats(r: number, g: number, b: number, a: number): this { + return new (this.constructor as Constructor)(this.r * r, this.g * g, this.b * b, this.a * a); + } + + /** + * Returns a new Color4 set with the division result of the current Color4 by the given one. + * @param otherColor color to devide with + * @returns resulting new color + */ + public divide(otherColor: DeepImmutable): this { + return new (this.constructor as Constructor)(this.r / otherColor.r, this.g / otherColor.g, this.b / otherColor.b, this.a / otherColor.a); + } + /** + * Updates the given color "result" with the division result of the current Color4 by the given one. + * @param otherColor color to devide with + * @param result color to store the result + * @returns result input + */ + public divideToRef(otherColor: DeepImmutable, result: T): T { + result.r = this.r / otherColor.r; + result.g = this.g / otherColor.g; + result.b = this.b / otherColor.b; + result.a = this.a / otherColor.a; + return result; + } + + /** + * Divides the current Color3 coordinates by the given ones. + * @param otherColor color to devide with + * @returns the updated Color3. + */ + public divideInPlace(otherColor: DeepImmutable): this { + return this.divideToRef(otherColor, this); + } + + /** + * Updates the Color4 coordinates with the minimum values between its own and the given color ones + * @param other defines the second operand + * @returns the current updated Color4 + */ + public minimizeInPlace(other: DeepImmutable): this { + this.r = Math.min(this.r, other.r); + this.g = Math.min(this.g, other.g); + this.b = Math.min(this.b, other.b); + this.a = Math.min(this.a, other.a); + return this; + } + /** + * Updates the Color4 coordinates with the maximum values between its own and the given color ones + * @param other defines the second operand + * @returns the current updated Color4 + */ + public maximizeInPlace(other: DeepImmutable): this { + this.r = Math.max(this.r, other.r); + this.g = Math.max(this.g, other.g); + this.b = Math.max(this.b, other.b); + this.a = Math.max(this.a, other.a); + return this; + } + + /** + * Updates the current Color4 with the minimal coordinate values between its and the given coordinates + * @param r defines the r coordinate of the operand + * @param g defines the g coordinate of the operand + * @param b defines the b coordinate of the operand + * @param a defines the a coordinate of the operand + * @returns the current updated Color4 + */ + public minimizeInPlaceFromFloats(r: number, g: number, b: number, a: number): this { + this.r = Math.min(r, this.r); + this.g = Math.min(g, this.g); + this.b = Math.min(b, this.b); + this.a = Math.min(a, this.a); + return this; + } + + /** + * Updates the current Color4 with the maximal coordinate values between its and the given coordinates. + * @param r defines the r coordinate of the operand + * @param g defines the g coordinate of the operand + * @param b defines the b coordinate of the operand + * @param a defines the a coordinate of the operand + * @returns the current updated Color4 + */ + public maximizeInPlaceFromFloats(r: number, g: number, b: number, a: number): this { + this.r = Math.max(r, this.r); + this.g = Math.max(g, this.g); + this.b = Math.max(b, this.b); + this.a = Math.max(a, this.a); + return this; + } + + /** + * Gets the current Color4's floored values and stores them in result + * @param result the color to store the result in + * @returns the result color + */ + public floorToRef(result: T): T { + result.r = Math.floor(this.r); + result.g = Math.floor(this.g); + result.b = Math.floor(this.b); + result.a = Math.floor(this.a); + return result; + } + + /** + * Gets a new Color4 from current Color4 floored values + * @returns a new Color4 + */ + public floor(): this { + return new (this.constructor as Constructor)(Math.floor(this.r), Math.floor(this.g), Math.floor(this.b), Math.floor(this.a)); + } + + /** + * Gets the current Color4's fractional values and stores them in result + * @param result the color to store the result in + * @returns the result color + */ + public fractToRef(result: T): T { + result.r = this.r - Math.floor(this.r); + result.g = this.g - Math.floor(this.g); + result.b = this.b - Math.floor(this.b); + result.a = this.a - Math.floor(this.a); + return result; + } + + /** + * Gets a new Color4 from current Color4 fractional values + * @returns a new Color4 + */ + public fract(): this { + return new (this.constructor as Constructor)( + this.r - Math.floor(this.r), + this.g - Math.floor(this.g), + this.b - Math.floor(this.b), + this.a - Math.floor(this.a) + ); + } + + /** + * Returns a new Color4 set with the current Color4 negated coordinates. + * @returns a new color with the negated values + */ + public negate(): this { + return new (this.constructor as Constructor)(-this.r, -this.g, -this.b, -this.a); + } + + /** + * Negate this color in place + * @returns this + */ + public negateInPlace(): this { + this.r *= -1; + this.g *= -1; + this.b *= -1; + this.a *= -1; + return this; + } + + /** + * Negate the current Color4 and stores the result in the given color "result" coordinates + * @param result defines the Color3 object where to store the result + * @returns the result + */ + public negateToRef(result: T): T { + return result.copyFromFloats(this.r * -1, this.g * -1, this.b * -1, this.a * -1); + } + + /** + * Boolean : True if the current Color4 coordinates are each beneath the distance "epsilon" from the given color ones. + * @param otherColor color to compare against + * @param epsilon (Default: very small number) + * @returns true if they are equal + */ + public equalsWithEpsilon(otherColor: DeepImmutable, epsilon: number = Epsilon): boolean { + return ( + otherColor && + Scalar.WithinEpsilon(this.r, otherColor.r, epsilon) && + Scalar.WithinEpsilon(this.g, otherColor.g, epsilon) && + Scalar.WithinEpsilon(this.b, otherColor.b, epsilon) && + Scalar.WithinEpsilon(this.a, otherColor.a, epsilon) + ); + } + + /** + * Boolean : True if the given floats are strictly equal to the current Color4 coordinates. + * @param x x value to compare against + * @param y y value to compare against + * @param z z value to compare against + * @param w w value to compare against + * @returns true if equal + */ + public equalsToFloats(x: number, y: number, z: number, w: number): boolean { + return this.r === x && this.g === y && this.b === z && this.a === w; + } + /** * Creates a string with the Color4 current values * @returns the string representation of the Color4 object @@ -973,8 +1531,9 @@ export class Color4 { * Creates a new Color4 copied from the current one * @returns a new Color4 object */ - public clone(): Color4 { - return new Color4(this.r, this.g, this.b, this.a); + public clone(): this { + const result = new (this.constructor as Constructor)(); + return result.copyFrom(this); } /** @@ -982,7 +1541,7 @@ export class Color4 { * @param source defines the source Color4 object * @returns the current updated Color4 object */ - public copyFrom(source: Color4): Color4 { + public copyFrom(source: DeepImmutable): this { this.r = source.r; this.g = source.g; this.b = source.b; @@ -998,7 +1557,7 @@ export class Color4 { * @param a defines the alpha component to read from * @returns the current updated Color4 object */ - public copyFromFloats(r: number, g: number, b: number, a: number): Color4 { + public copyFromFloats(r: number, g: number, b: number, a: number): this { this.r = r; this.g = g; this.b = b; @@ -1014,10 +1573,20 @@ export class Color4 { * @param a defines the alpha component to read from * @returns the current updated Color4 object */ - public set(r: number, g: number, b: number, a: number): Color4 { + public set(r: number, g: number, b: number, a: number): this { return this.copyFromFloats(r, g, b, a); } + /** + * Copies the given float to the current Vector4 coordinates + * @param v defines the r, g, b, and a coordinates of the operand + * @returns the current updated Vector4 + */ + public setAll(v: number): this { + this.r = this.g = this.b = this.a = v; + return this; + } + /** * Compute the Color4 hexadecimal code as a string * @param returnAsColor3 defines if the string should only contains RGB values (off by default) diff --git a/packages/dev/core/src/Maths/math.polar.ts b/packages/dev/core/src/Maths/math.polar.ts index 12bb749901f..f0804f65da5 100644 --- a/packages/dev/core/src/Maths/math.polar.ts +++ b/packages/dev/core/src/Maths/math.polar.ts @@ -671,7 +671,7 @@ export class Spherical { * @param ref the Vector3 to update * @returns the updated Vector3 */ - public toVector3ToRef(ref: DeepImmutable): Vector3 { + public toVector3ToRef(ref: Vector3): Vector3 { const x = this.radius * Math.sin(this.theta) * Math.cos(this.phi); const y = this.radius * Math.cos(this.theta); const z = this.radius * Math.sin(this.theta) * Math.sin(this.phi); diff --git a/packages/dev/core/src/Maths/math.vector.ts b/packages/dev/core/src/Maths/math.vector.ts index 31310d9db38..3efd55c0d4a 100644 --- a/packages/dev/core/src/Maths/math.vector.ts +++ b/packages/dev/core/src/Maths/math.vector.ts @@ -2,7 +2,7 @@ import { Scalar } from "./math.scalar"; import { Epsilon } from "./math.constants"; import type { Viewport } from "./math.viewport"; -import type { DeepImmutable, Nullable, FloatArray, float } from "../types"; +import type { DeepImmutable, Nullable, FloatArray, float, Constructor } from "../types"; import { ArrayTools } from "../Misc/arrayTools"; import type { IPlaneLike } from "./math.like"; import { RegisterClass } from "../Misc/typeStore"; @@ -11,24 +11,615 @@ import { PerformanceConfigurator } from "../Engines/performanceConfigurator"; import { EngineStore } from "../Engines/engineStore"; import type { TransformNode } from "../Meshes/transformNode"; -export type Vector2Constructor = new (...args: ConstructorParameters) => T; -export type Vector3Constructor = new (...args: ConstructorParameters) => T; -export type Vector4Constructor = new (...args: ConstructorParameters) => T; -export type QuaternionConstructor = new (...args: ConstructorParameters) => T; -export type MatrixConstructor = new () => T; +// eslint-disable-next-line @typescript-eslint/naming-convention +const _ExtractAsInt = (value: number) => { + return parseInt(value.toString().replace(/\W/g, "")); +}; + +export declare abstract class VectorLike { + /** + * The number of dimensions the vector has (i.e. the length of the coordinate array) + * Note this is abstract to allow a getter implementation in DynamicVector + */ + abstract readonly dimension: [number]; + + /** + * Creates a new Vector from the given coordinates + */ + constructor(...coords: N); + + /** + * Gets a string with the Vector coordinates + * @returns a string with the Vector coordinates + */ + + toString(): string; + + /** + * Gets class name + * @returns the string "Vector" + */ + + getClassName(): string; + + /** + * Gets current vector hash code + * @returns the Vector hash code as a number + */ + getHashCode(): number; + + /** + * Sets the Vector coordinates in the given array from the given index. + * @param array defines the source array + * @param index defines the offset in source array + * @returns the current Vector + */ + toArray(array: FloatArray, index?: number): this; + + /** + * Update the current vector from an array + * @param array defines the destination array + * @param index defines the offset in the destination array + * @returns the current Vector + */ + fromArray(array: FloatArray, index?: number): this; + + /** + * Copy the current vector to an array + * @returns a new array with the Vector coordinates. + */ + asArray(): N; + + /** + * Sets the current Vector coordinates with the given source coordinates + * @param source defines the source Vector + * @returns the current updated Vector + */ + copyFrom(source: DeepImmutable): this; + + /** + * Sets the Vector coordinates with the given floats + * @returns the current updated Vector + */ + + copyFromFloats(...floats: N): this; + + /** + * Sets the Vector coordinates with the given floats + * @returns the current updated Vector + */ + set(...values: N): this; + + /** + * Sets the Vector coordinates to the given value + * @returns the current updated Vector + */ + setAll(value: number): this; + + /** + * Add another vector with the current one + * @param otherVector defines the other vector + * @returns a new Vector set with the addition of the current Vector and the given one coordinates + */ + add(otherVector: DeepImmutable): this; + + /** + * Sets the "result" coordinates with the addition of the current Vector and the given one coordinates + * @param otherVector defines the other vector + * @param result defines the target vector + * @returns result input + */ + addToRef(otherVector: DeepImmutable, result: T): T; + + /** + * Set the Vector coordinates by adding the given Vector coordinates + * @param otherVector defines the other vector + * @returns the current updated Vector + */ + addInPlace(otherVector: DeepImmutable): this; + + /** + * Adds the given coordinates to the current Vector + * @param floats the floats to add + * @returns the current updated Vector + */ + addInPlaceFromFloats(...floats: N): this; + + /** + * Gets a new Vector2 set with the subtracted coordinates of the given one from the current Vector2 + * @param otherVector defines the other vector + * @returns a new Vector + */ + subtract(otherVector: DeepImmutable): this; + + /** + * Sets the "result" coordinates with the subtraction of the given one from the current Vector coordinates. + * @param otherVector defines the other vector + * @param result defines the target vector + * @returns result input + */ + subtractToRef(otherVector: DeepImmutable, result: T): T; + + /** + * Sets the current Vector coordinates by subtracting from it the given one coordinates + * @param otherVector defines the other vector + * @returns the current updated Vector + */ + subtractInPlace(otherVector: DeepImmutable): this; + + /** + * Returns a new Vector set with the subtraction of the given floats from the current Vector coordinates + * @param floats the coordinates to subtract + * @returns the resulting Vector + */ + subtractFromFloats(...floats: N): this; + + /** + * Subtracts the given floats from the current Vector coordinates and set the given vector "result" with this result + * Note: Implementation uses array magic so types may be confusing. + * @param args the coordinates to subtract with the last element as the result + * @returns the result + */ + subtractFromFloatsToRef(...args: [...N, T]): T; + + /** + * Returns a new Vector set with the multiplication of the current Vector and the given one coordinates + * @param otherVector defines the other vector + * @returns a new Vector + */ + multiply(otherVector: DeepImmutable): this; + + /** + * Sets "result" coordinates with the multiplication of the current Vector and the given one coordinates + * @param otherVector defines the other vector + * @param result defines the target vector + * @returns result input + */ + multiplyToRef(otherVector: DeepImmutable, result: T): T; + + /** + * Multiplies in place the current Vector coordinates by the given ones + * @param otherVector defines the other vector + * @returns the current updated Vector + */ + multiplyInPlace(otherVector: DeepImmutable): this; + + /** + * Gets a new Vector set with the Vector coordinates multiplied by the given floats + * @returns a new Vector + */ + multiplyByFloats(...floats: N): this; + + /** + * Returns a new Vector set with the Vector coordinates divided by the given one coordinates + * @param otherVector defines the other vector + * @returns a new Vector + */ + divide(otherVector: DeepImmutable): this; + + /** + * Sets the "result" coordinates with the Vector divided by the given one coordinates + * @param otherVector defines the other vector + * @param result defines the target vector + * @returns result input + */ + divideToRef(otherVector: DeepImmutable, result: T): T; + + /** + * Divides the current Vector coordinates by the given ones + * @param otherVector defines the other vector + * @returns the current updated Vector + */ + divideInPlace(otherVector: DeepImmutable): this; + + /** + * Updates the current Vector with the minmal coordinate values between its and the given vector ones. + * @param otherVector defines the other vector + * @returns this current updated Vector + */ + minimizeInPlace(otherVector: DeepImmutable): this; + + /** + * Updates the current Vector with the minmal coordinate values between its and the given floats. + * @param floats defines the floats to compare against + * @returns this current updated Vector + */ + minimizeInPlaceFromFloats(...floats: N): this; + + /** + * Updates the current Vector with the maximal coordinate values between its and the given vector ones. + * @param otherVector defines the other vector + * @returns this current updated Vector + */ + maximizeInPlace(otherVector: DeepImmutable): this; + + /** + * Updates the current Vector with the maximal coordinate values between its and the given floats. + * @param floats defines the floats to compare against + * @returns this current updated Vector + */ + maximizeInPlaceFromFloats(...floats: N): this; + + /** + * Gets a new Vector with current Vector negated coordinates + * @returns a new Vector + */ + negate(): this; + + /** + * Negate this vector in place + * @returns this + */ + negateInPlace(): this; + + /** + * Negate the current Vector and stores the result in the given vector "result" coordinates + * @param result defines the Vector object where to store the result + * @returns the result + */ + negateToRef(result: T): T; + + /** + * Multiply the Vector coordinates by + * @param scale defines the scaling factor + * @returns the current updated Vector + */ + scaleInPlace(scale: number): this; + + /** + * Returns a new Vector scaled by "scale" from the current Vector + * Example Playground https://playground.babylonjs.com/#QYBWV4#52 + * @param scale defines the scaling factor + * @returns a new Vector + */ + scale(scale: number): this; + + /** + * Scale the current Vector values by a factor to a given Vector + * Example Playground https://playground.babylonjs.com/#QYBWV4#57 + * @param scale defines the scale factor + * @param result defines the Vector object where to store the result + * @returns result input + */ + scaleToRef(scale: number, result: T): T; + + /** + * Scale the current Vector values by a factor and add the result to a given Vector + * @param scale defines the scale factor + * @param result defines the Vector object where to store the result + * @returns result input + */ + scaleAndAddToRef(scale: number, result: T): T; + + /** + * Gets a boolean if two vectors are equals + * @param otherVector defines the other vector + * @returns true if the given vector coordinates strictly equal the current Vector ones + */ + equals(otherVector: DeepImmutable): boolean; + + /** + * Gets a boolean if two vectors are equals (using an epsilon value) + * @param otherVector defines the other vector + * @param epsilon defines the minimal distance to consider equality + * @returns true if the given vector coordinates are close to the current ones by a distance of epsilon. + */ + equalsWithEpsilon(otherVector: DeepImmutable, epsilon?: number): boolean; + + /** + * Returns true if the current Vectoe coordinates equals the given floats + * @param floats defines the coordinates to compare against + * @returns true if both vectors are equal + */ + equalsToFloats(...floats: N): boolean; + + /** + * Gets a new Vector from current Vector floored values + * eg (1.2, 2.31) returns (1, 2) + * @returns a new Vector + */ + floor(): this; + + /** + * Gets the current Vector's floored values and stores them in result + * @param result the Vector to store the result in + * @returns the result Vector + */ + floorToRef(result: T): T; + + /** + * Gets a new Vector from current Vector fractional values + * eg (1.2, 2.31) returns (0.2, 0.31) + * @returns a new Vector + */ + fract(): this; + + /** + * Gets the current Vector's fractional values and stores them in result + * @param result the Vector to store the result in + * @returns the result Vector + */ + fractToRef(result: T): T; + + /** + * Gets a new Vector copied from the Vector + * @returns a new Vector + */ + clone(): this; + + /** + * Returns a new Vector with random values between min and max + * @param min the minimum random value + * @param max the maximum random value + * @returns a Vector with random values between min and max + */ + static Random(min?: number, max?: number): T; + + /** + * Returns a new Vector with random values between min and max + * @param min the minimum random value + * @param max the maximum random value + * @param result the result to store the random values in + * @returns the updated result Vector + */ + static RandomToRef(min: number | undefined, max: number | undefined, result: T): T; + + /** + * Gets a new vector from the given index element of the given array + * @param array defines the data source + * @param offset defines the offset in the data source + * @returns a new vector + */ + static FromArray(array: ArrayLike, offset?: number): Vector; + + /** + * Sets "result" from the given index element of the given array + * @param array defines the data source + * @param offset defines the offset in the data source + * @param result defines the target vector + * @returns result input + */ + static FromArrayToRef(array: ArrayLike, offset: number, result: T): T; + + /** + * Sets the given vector "result" with the given floats. + * @param args defines the coordinates of the source with the last paramater being the result + */ + static FromFloatsToRef(...args: [...N, T]): T; + + /** + * Gets the dot product of the vector "left" and the vector "right" + * @param left defines first vector + * @param right defines second vector + * @returns the dot product (float) + */ + static Dot(left: DeepImmutable, right: DeepImmutable): number; + + /** + * Gets a new Vector set with the minimal coordinate values from the "left" and "right" vectors + * @param left defines 1st vector + * @param right defines 2nd vector + * @returns a new Vector + */ + static Minimize(left: DeepImmutable, right: DeepImmutable): T; + + /** + * Gets a new Vector set with the maximal coordinate values from the "left" and "right" vectors + * @param left defines 1st vector + * @param right defines 2nd vector + * @returns a new Vector + */ + static Maximize(left: DeepImmutable, right: DeepImmutable): T; + + /** + * Gets the distance between the vectors "value1" and "value2" + * @param value1 defines first vector + * @param value2 defines second vector + * @returns the distance between vectors + */ + static Distance(value1: DeepImmutable, value2: DeepImmutable): number; + + /** + * Returns the squared distance between the vectors "value1" and "value2" + * @param value1 defines first vector + * @param value2 defines second vector + * @returns the squared distance between vectors + */ + static DistanceSquared(value1: DeepImmutable, value2: DeepImmutable): number; + + /** + * Gets a new Vector located at the center of the vectors "value1" and "value2" + * @param value1 defines first vector + * @param value2 defines second vector + * @returns a new Vector + */ + static Center(value1: DeepImmutable, value2: DeepImmutable): T; + + /** + * Gets the center of the vectors "value1" and "value2" and stores the result in the vector "ref" + * @param value1 defines first vector + * @param value2 defines second vector + * @param ref defines third vector + * @returns ref + */ + static CenterToRef(value1: DeepImmutable, value2: DeepImmutable, ref: T): T; +} + +export declare abstract class Vector extends VectorLike { + /** + * Gets the length of the vector + * @returns the vector length (float) + */ + length(): number; + + /** + * Gets the vector squared length + * @returns the vector squared length (float) + */ + lengthSquared(): number; + + /** + * Normalize the vector + * @returns the current updated Vector + */ + normalize(): this; + + /** + * Normalize the current Vector with the given input length. + * Please note that this is an in place operation. + * @param len the length of the vector + * @returns the current updated Vector + */ + normalizeFromLength(len: number): this; + + /** + * Normalize the current Vector to a new vector + * @returns the new Vector + */ + normalizeToNew(): this; + + /** + * Normalize the current Vector to the reference + * @param reference define the Vector to update + * @returns the updated Vector + */ + normalizeToRef(reference: T): T; + + /** + * Gets a new Vector located for "amount" (float) on the CatmullRom spline defined by the given four Vector + * @param value1 defines 1st point of control + * @param value2 defines 2nd point of control + * @param value3 defines 3rd point of control + * @param value4 defines 4th point of control + * @param amount defines the interpolation factor + * @returns a new Vector + */ + static CatmullRom(value1: DeepImmutable, value2: DeepImmutable, value3: DeepImmutable, value4: DeepImmutable, amount: number): T; + + /** + * Returns a new Vector set with same the coordinates than "value" ones if the vector "value" is in the square defined by "min" and "max". + * If a coordinate of "value" is lower than "min" coordinates, the returned Vector is given this "min" coordinate. + * If a coordinate of "value" is greater than "max" coordinates, the returned Vector is given this "max" coordinate + * @param value defines the value to clamp + * @param min defines the lower limit + * @param max defines the upper limit + * @returns a new Vector + */ + static Clamp(value: DeepImmutable, min: DeepImmutable, max: DeepImmutable): T; + + /** + * Returns a new Vector set with same the coordinates than "value" ones if the vector "value" is in the square defined by "min" and "max". + * If a coordinate of "value" is lower than "min" coordinates, the returned Vector is given this "min" coordinate. + * If a coordinate of "value" is greater than "max" coordinates, the returned Vector is given this "max" coordinate + * @param value defines the value to clamp + * @param min defines the lower limit + * @param max defines the upper limit + * @param result defines the vector where to store the result + * @returns the updated result Vector + */ + static ClampToRef(value: DeepImmutable, min: DeepImmutable, max: DeepImmutable, result: T): T; + + /** + * Checks if a given vector is inside a specific range + * @param v defines the vector to test + * @param min defines the minimum range + * @param max defines the maximum range + */ + static CheckExtends(v: Vector, min: Vector, max: Vector): void; + + /** + * Returns a new Vector located for "amount" (float) on the Hermite spline defined by the vectors "value1", "value2", "tangent1", "tangent2" + * @param value1 defines the 1st control point + * @param tangent1 defines the outgoing tangent + * @param value2 defines the 2nd control point + * @param tangent2 defines the incoming tangent + * @param amount defines the interpolation factor + * @returns a new Vector + */ + static Hermite(value1: DeepImmutable, tangent1: DeepImmutable, value2: DeepImmutable, tangent2: DeepImmutable, amount: number): T; + + /** + * Returns a new Vector which is the 1st derivative of the Hermite spline defined by the vectors "value1", "value2", "tangent1", "tangent2". + * @param value1 defines the first control point + * @param tangent1 defines the first tangent + * @param value2 defines the second control point + * @param tangent2 defines the second tangent + * @param time define where the derivative must be done + * @returns 1st derivative + */ + static Hermite1stDerivative(value1: DeepImmutable, tangent1: DeepImmutable, value2: DeepImmutable, tangent2: DeepImmutable, time: number): T; + + /** + * Returns a new Vector which is the 1st derivative of the Hermite spline defined by the vectors "value1", "value2", "tangent1", "tangent2". + * @param value1 defines the first control point + * @param tangent1 defines the first tangent + * @param value2 defines the second control point + * @param tangent2 defines the second tangent + * @param time define where the derivative must be done + * @param result define where the derivative will be stored + * @returns result input + */ + static Hermite1stDerivativeToRef( + value1: DeepImmutable, + tangent1: DeepImmutable, + value2: DeepImmutable, + tangent2: DeepImmutable, + time: number, + result: T + ): T; + + /** + * Returns a new Vector located for "amount" (float) on the linear interpolation between the vector "start" adn the vector "end". + * @param start defines the start vector + * @param end defines the end vector + * @param amount defines the interpolation factor + * @returns a new Vector + */ + static Lerp(start: DeepImmutable, end: DeepImmutable, amount: number): T; -// eslint-disable-next-line @typescript-eslint/naming-convention -const _ExtractAsInt = (value: number) => { - return parseInt(value.toString().replace(/\W/g, "")); -}; + /** + * Returns a new Vector located for "amount" (float) on the linear interpolation between the vector "start" adn the vector "end". + * @param start defines the start vector + * @param end defines the end vector + * @param amount defines the interpolation factor + * @returns a new Vector + */ + static LerpToRef(start: DeepImmutable, end: DeepImmutable, amount: number, result: T): T; + + /** + * Returns a new Vector equal to the normalized given vector + * @param vector defines the vector to normalize + * @returns a new Vector + */ + static Normalize(vector: DeepImmutable): T; + + /** + * Normalize a given vector into a second one + * @param vector defines the vector to normalize + * @param result defines the vector where to store the result + * @returns result input + */ + static NormalizeToRef(vector: DeepImmutable, result: T): T; + + /** + * Gets the shortest distance (float) between the point "p" and the segment defined by the two points "segA" and "segB". + * @param p defines the middle point + * @param segA defines one point of the segment + * @param segB defines the other point of the segment + * @returns the shortest distance + */ + static DistanceOfPointFromSegment(p: DeepImmutable, segA: DeepImmutable, segB: DeepImmutable): number; +} /** * Class representing a vector containing 2 coordinates * Example Playground - Overview - https://playground.babylonjs.com/#QYBWV4#9 */ -export class Vector2 { +export class Vector2 implements Vector<[number, number]> { private static _ZeroReadOnly = Vector2.Zero() as DeepImmutable; + public readonly dimension: [number] = [2]; + /** * Creates a new Vector2 from the given x and y coordinates * @param x defines the first coordinate @@ -88,11 +679,11 @@ export class Vector2 { * Update the current vector from an array * Example Playground https://playground.babylonjs.com/#QYBWV4#39 * @param array defines the destination array - * @param index defines the offset in the destination array + * @param offset defines the offset in the destination array * @returns the current Vector2 */ - public fromArray(array: FloatArray, index: number = 0): this { - Vector2.FromArrayToRef(array, index, this); + public fromArray(array: FloatArray, offset: number = 0): this { + Vector2.FromArrayToRef(array, offset, this); return this; } @@ -101,10 +692,8 @@ export class Vector2 { * Example Playground https://playground.babylonjs.com/#QYBWV4#40 * @returns a new array with 2 elements: the Vector2 coordinates. */ - public asArray(): number[] { - const result = new Array(); - this.toArray(result, 0); - return result; + public asArray(): [number, number] { + return [this.x, this.y]; } /** @@ -142,6 +731,16 @@ export class Vector2 { public set(x: number, y: number): this { return this.copyFromFloats(x, y); } + + /** + * Copies the given float to the current Vector2 coordinates + * @param v defines the x and y coordinates of the operand + * @returns the current updated Vector2 + */ + public setAll(v: number): this { + return this.copyFromFloats(v, v); + } + /** * Add another vector with the current one * Example Playground https://playground.babylonjs.com/#QYBWV4#11 @@ -149,7 +748,7 @@ export class Vector2 { * @returns a new Vector2 set with the addition of the current Vector2 and the given one coordinates */ public add(otherVector: DeepImmutable): this { - return new (this.constructor as Vector2Constructor)(this.x + otherVector.x, this.y + otherVector.y); + return new (this.constructor as Constructor)(this.x + otherVector.x, this.y + otherVector.y); } /** @@ -177,6 +776,18 @@ export class Vector2 { return this; } + /** + * Adds the given coordinates to the current Vector2 + * @param x defines the x coordinate of the operand + * @param y defines the y coordinate of the operand + * @returns the current updated Vector2 + */ + public addInPlaceFromFloats(x: number, y: number): this { + this.x += x; + this.y += y; + return this; + } + /** * Gets a new Vector2 by adding the current Vector2 coordinates to the given Vector3 x, y coordinates * Example Playground https://playground.babylonjs.com/#QYBWV4#14 @@ -184,7 +795,7 @@ export class Vector2 { * @returns a new Vector2 */ public addVector3(otherVector: Vector3): this { - return new (this.constructor as Vector2Constructor)(this.x + otherVector.x, this.y + otherVector.y); + return new (this.constructor as Constructor)(this.x + otherVector.x, this.y + otherVector.y); } /** @@ -193,8 +804,8 @@ export class Vector2 { * @param otherVector defines the other vector * @returns a new Vector2 */ - public subtract(otherVector: Vector2): this { - return new (this.constructor as Vector2Constructor)(this.x - otherVector.x, this.y - otherVector.y); + public subtract(otherVector: DeepImmutable): this { + return new (this.constructor as Constructor)(this.x - otherVector.x, this.y - otherVector.y); } /** @@ -240,7 +851,7 @@ export class Vector2 { * @returns a new Vector2 */ public multiply(otherVector: DeepImmutable): this { - return new (this.constructor as Vector2Constructor)(this.x * otherVector.x, this.y * otherVector.y); + return new (this.constructor as Constructor)(this.x * otherVector.x, this.y * otherVector.y); } /** @@ -264,7 +875,7 @@ export class Vector2 { * @returns a new Vector2 */ public multiplyByFloats(x: number, y: number): this { - return new (this.constructor as Vector2Constructor)(this.x * x, this.y * y); + return new (this.constructor as Constructor)(this.x * x, this.y * y); } /** @@ -273,8 +884,8 @@ export class Vector2 { * @param otherVector defines the other vector * @returns a new Vector2 */ - public divide(otherVector: Vector2): this { - return new (this.constructor as Vector2Constructor)(this.x / otherVector.x, this.y / otherVector.y); + public divide(otherVector: DeepImmutable): this { + return new (this.constructor as Constructor)(this.x / otherVector.x, this.y / otherVector.y); } /** @@ -297,16 +908,80 @@ export class Vector2 { * @returns the current updated Vector2 */ public divideInPlace(otherVector: DeepImmutable): this { - return this.divideToRef(otherVector, this); + this.x = this.x / otherVector.x; + this.y = this.y / otherVector.y; + return this; + } + + /** + * Updates the current Vector2 with the minimal coordinate values between its and the given vector ones + * @param other defines the second operand + * @returns the current updated Vector2 + */ + public minimizeInPlace(other: DeepImmutable): this { + return this.minimizeInPlaceFromFloats(other.x, other.y); + } + + /** + * Updates the current Vector2 with the maximal coordinate values between its and the given vector ones. + * @param other defines the second operand + * @returns the current updated Vector2 + */ + public maximizeInPlace(other: DeepImmutable): this { + return this.maximizeInPlaceFromFloats(other.x, other.y); + } + + /** + * Updates the current Vector2 with the minimal coordinate values between its and the given coordinates + * @param x defines the x coordinate of the operand + * @param y defines the y coordinate of the operand + * @returns the current updated Vector2 + */ + public minimizeInPlaceFromFloats(x: number, y: number): this { + this.x = Math.min(x, this.x); + this.y = Math.min(y, this.y); + return this; + } + + /** + * Updates the current Vector2 with the maximal coordinate values between its and the given coordinates. + * @param x defines the x coordinate of the operand + * @param y defines the y coordinate of the operand + * @returns the current updated Vector2 + */ + public maximizeInPlaceFromFloats(x: number, y: number): this { + this.x = Math.max(x, this.x); + this.y = Math.max(y, this.y); + return this; + } + + /** + * Returns a new Vector2 set with the subtraction of the given floats from the current Vector2 coordinates + * @param x defines the x coordinate of the operand + * @param y defines the y coordinate of the operand + * @returns the resulting Vector2 + */ + public subtractFromFloats(x: number, y: number): this { + return new (this.constructor as Constructor)(this.x - x, this.y - y); + } + + /** + * Subtracts the given floats from the current Vector2 coordinates and set the given vector "result" with this result + * @param x defines the x coordinate of the operand + * @param y defines the y coordinate of the operand + * @param result defines the Vector2 object where to store the result + * @returns the result + */ + public subtractFromFloatsToRef(x: number, y: number, result: T): T { + return result.copyFromFloats(this.x - x, this.y - y); } /** * Gets a new Vector2 with current Vector2 negated coordinates - * Example Playground https://playground.babylonjs.com/#QYBWV4#22 * @returns a new Vector2 */ public negate(): this { - return new (this.constructor as Vector2Constructor)(-this.x, -this.y); + return new (this.constructor as Constructor)(-this.x, -this.y); } /** @@ -349,9 +1024,7 @@ export class Vector2 { * @returns a new Vector2 */ public scale(scale: number): this { - const result = new (this.constructor as Vector2Constructor)(0, 0); - this.scaleToRef(scale, result); - return result; + return new (this.constructor as Constructor)(this.x * scale, this.y * scale); } /** @@ -401,6 +1074,16 @@ export class Vector2 { return otherVector && Scalar.WithinEpsilon(this.x, otherVector.x, epsilon) && Scalar.WithinEpsilon(this.y, otherVector.y, epsilon); } + /** + * Returns true if the current Vector2 coordinates equals the given floats + * @param x defines the x coordinate of the operand + * @param y defines the y coordinate of the operand + * @returns true if both vectors are equal + */ + public equalsToFloats(x: number, y: number): boolean { + return this.x === x && this.y === y; + } + /** * Gets a new Vector2 from current Vector2 floored values * Example Playground https://playground.babylonjs.com/#QYBWV4#35 @@ -408,7 +1091,18 @@ export class Vector2 { * @returns a new Vector2 */ public floor(): this { - return new (this.constructor as Vector2Constructor)(Math.floor(this.x), Math.floor(this.y)); + return new (this.constructor as Constructor)(Math.floor(this.x), Math.floor(this.y)); + } + + /** + * Gets the current Vector2's floored values and stores them in result + * @param result the Vector2 to store the result in + * @returns the result Vector2 + */ + public floorToRef(result: T): T { + result.x = Math.floor(this.x); + result.y = Math.floor(this.y); + return result; } /** @@ -418,7 +1112,18 @@ export class Vector2 { * @returns a new Vector2 */ public fract(): this { - return new (this.constructor as Vector2Constructor)(this.x - Math.floor(this.x), this.y - Math.floor(this.y)); + return new (this.constructor as Constructor)(this.x - Math.floor(this.x), this.y - Math.floor(this.y)); + } + + /** + * Gets the current Vector2's fractional values and stores them in result + * @param result the Vector2 to store the result in + * @returns the result Vector2 + */ + public fractToRef(result: T): T { + result.x = this.x - Math.floor(this.x); + result.y = this.y - Math.floor(this.y); + return result; } /** @@ -464,8 +1169,44 @@ export class Vector2 { * @returns the current updated Vector2 */ public normalize(): this { - Vector2.NormalizeToRef(this, this); - return this; + return this.normalizeFromLength(this.length()); + } + + /** + * Normalize the current Vector with the given input length. + * Please note that this is an in place operation. + * @param len the length of the vector + * @returns the current updated Vector + */ + public normalizeFromLength(len: number): this { + if (len === 0 || len === 1.0) { + return this; + } + + return this.scaleInPlace(1.0 / len); + } + + /** + * Normalize the current Vector to a new vector + * @returns the new Vector + */ + public normalizeToNew(): this { + const normalized = new (this.constructor as Constructor)(); + this.normalizeToRef(normalized); + return normalized; + } + + /** + * Normalize the current Vector to the reference + * @param reference define the Vector to update + * @returns the updated Vector + */ + public normalizeToRef(reference: T): T { + const len = this.length(); + if (len === 0) { + return reference.copyFrom(this as DeepImmutable); + } + return this.scaleToRef(1.0 / len, reference); } /** @@ -474,7 +1215,7 @@ export class Vector2 { * @returns a new Vector2 */ public clone(): this { - return new (this.constructor as Vector2Constructor)(this.x, this.y); + return new (this.constructor as Constructor)(this.x, this.y); } // Statics @@ -571,7 +1312,7 @@ export class Vector2 { (2.0 * value1.y - 5.0 * value2.y + 4.0 * value3.y - value4.y) * squared + (-value1.y + 3.0 * value2.y - 3.0 * value3.y + value4.y) * cubed); - return new (value1.constructor as Vector2Constructor)(x, y); + return new (value1.constructor as Constructor)(x, y); } /** @@ -593,7 +1334,7 @@ export class Vector2 { y = y > max.y ? max.y : y; y = y < min.y ? min.y : y; - return new (value.constructor as Vector2Constructor)(x, y); + return new (value.constructor as Constructor)(x, y); } /** @@ -623,7 +1364,7 @@ export class Vector2 { const x = value1.x * part1 + value2.x * part2 + tangent1.x * part3 + tangent2.x * part4; const y = value1.y * part1 + value2.y * part2 + tangent1.y * part3 + tangent2.y * part4; - return new (value1.constructor as Vector2Constructor)(x, y); + return new (value1.constructor as Constructor)(x, y); } /** @@ -643,7 +1384,7 @@ export class Vector2 { tangent2: DeepImmutable, time: number ): T { - const result = new (value1.constructor as Vector2Constructor)(); + const result = new (value1.constructor as Constructor)(); this.Hermite1stDerivativeToRef(value1, tangent1, value2, tangent2, time, result); @@ -688,7 +1429,7 @@ export class Vector2 { public static Lerp(start: DeepImmutable, end: DeepImmutable, amount: number): Vector2 { const x = start.x + (end.x - start.x) * amount; const y = start.y + (end.y - start.y) * amount; - return new (start.constructor as Vector2Constructor)(x, y); + return new (start.constructor as Constructor)(x, y); } /** @@ -709,7 +1450,7 @@ export class Vector2 { * @returns a new Vector2 */ public static Normalize(vector: DeepImmutable): T { - const newVector = new (vector.constructor as Vector2Constructor)(); + const newVector = new (vector.constructor as Constructor)(); this.NormalizeToRef(vector, newVector); return newVector; } @@ -743,7 +1484,7 @@ export class Vector2 { public static Minimize(left: DeepImmutable, right: DeepImmutable): T { const x = left.x < right.x ? left.x : right.x; const y = left.y < right.y ? left.y : right.y; - return new (left.constructor as Vector2Constructor)(x, y); + return new (left.constructor as Constructor)(x, y); } /** @@ -756,7 +1497,7 @@ export class Vector2 { public static Maximize(left: DeepImmutable, right: DeepImmutable): T { const x = left.x > right.x ? left.x : right.x; const y = left.y > right.y ? left.y : right.y; - return new (left.constructor as Vector2Constructor)(x, y); + return new (left.constructor as Constructor)(x, y); } /** @@ -767,7 +1508,7 @@ export class Vector2 { * @returns a new Vector2 */ public static Transform(vector: DeepImmutable, transformation: DeepImmutable): T { - const result = new (vector.constructor as Vector2Constructor)(); + const result = new (vector.constructor as Constructor)(); Vector2.TransformToRef(vector, transformation, result); return result; } @@ -840,7 +1581,7 @@ export class Vector2 { * @returns a new Vector2 */ public static Center(value1: DeepImmutable, value2: DeepImmutable): T { - const result = new (value1.constructor as Vector2Constructor)(); + const result = new (value1.constructor as Constructor)(); return Vector2.CenterToRef(value1, value2, result); } @@ -883,7 +1624,7 @@ export class Vector2 { * Reminder: js uses a left handed forward facing system * Example Playground - Overview - https://playground.babylonjs.com/#R1F8YU */ -export class Vector3 { +export class Vector3 implements Vector<[number, number, number]> { private static _UpReadOnly = Vector3.Up() as DeepImmutable; private static _DownReadOnly = Vector3.Down() as DeepImmutable; private static _LeftHandedForwardReadOnly = Vector3.Forward(false) as DeepImmutable; @@ -895,6 +1636,8 @@ export class Vector3 { private static _ZeroReadOnly = Vector3.Zero() as DeepImmutable; private static _OneReadOnly = Vector3.One() as DeepImmutable; + public readonly dimension: [number] = [3]; + /** @internal */ public _x: number; @@ -988,10 +1731,10 @@ export class Vector3 { * Example Playground https://playground.babylonjs.com/#R1F8YU#10 * @returns a new array of numbers */ - public asArray(): number[] { + public asArray(): [number, number, number] { const result: number[] = []; this.toArray(result, 0); - return result; + return result as [number, number, number]; } /** @@ -1012,11 +1755,11 @@ export class Vector3 { * Update the current vector from an array * Example Playground https://playground.babylonjs.com/#R1F8YU#24 * @param array defines the destination array - * @param index defines the offset in the destination array + * @param offset defines the offset in the destination array * @returns the current Vector3 */ - public fromArray(array: FloatArray, index: number = 0): this { - Vector3.FromArrayToRef(array, index, this); + public fromArray(array: FloatArray, offset: number = 0): this { + Vector3.FromArrayToRef(array, offset, this); return this; } @@ -1036,7 +1779,11 @@ export class Vector3 { * @returns the current updated Vector3 */ public addInPlace(otherVector: DeepImmutable): this { - return this.addInPlaceFromFloats(otherVector._x, otherVector._y, otherVector._z); + this._x += otherVector._x; + this._y += otherVector._y; + this._z += otherVector._z; + this._isDirty = true; + return this; } /** @@ -1062,7 +1809,7 @@ export class Vector3 { * @returns the resulting Vector3 */ public add(otherVector: DeepImmutable): this { - return new (this.constructor as Vector3Constructor)(this._x + otherVector._x, this._y + otherVector._y, this._z + otherVector._z); + return new (this.constructor as Constructor)(this._x + otherVector._x, this._y + otherVector._y, this._z + otherVector._z); } /** @@ -1097,7 +1844,7 @@ export class Vector3 { * @returns the resulting Vector3 */ public subtract(otherVector: DeepImmutable): this { - return new (this.constructor as Vector3Constructor)(this._x - otherVector._x, this._y - otherVector._y, this._z - otherVector._z); + return new (this.constructor as Constructor)(this._x - otherVector._x, this._y - otherVector._y, this._z - otherVector._z); } /** @@ -1120,7 +1867,7 @@ export class Vector3 { * @returns the resulting Vector3 */ public subtractFromFloats(x: number, y: number, z: number): this { - return new (this.constructor as Vector3Constructor)(this._x - x, this._y - y, this._z - z); + return new (this.constructor as Constructor)(this._x - x, this._y - y, this._z - z); } /** @@ -1142,7 +1889,7 @@ export class Vector3 { * @returns a new Vector3 */ public negate(): this { - return new (this.constructor as Vector3Constructor)(-this._x, -this._y, -this._z); + return new (this.constructor as Constructor)(-this._x, -this._y, -this._z); } /** @@ -1189,7 +1936,7 @@ export class Vector3 { * @returns a new Vector3 */ public scale(scale: number): this { - return new (this.constructor as Vector3Constructor)(this._x * scale, this._y * scale, this._z * scale); + return new (this.constructor as Constructor)(this._x * scale, this._y * scale, this._z * scale); } /** @@ -1214,7 +1961,7 @@ export class Vector3 { * @param result defines the Vector3 object where to store the resultant normal * returns the result */ - public getNormalToRef(result: DeepImmutable): Vector3 { + public getNormalToRef(result: Vector3): Vector3 { /** * Calculates the spherical coordinates of the current vector * so saves on memory rather than importing whole Spherical Class @@ -1285,7 +2032,7 @@ export class Vector3 { * @returns a new Vector3 */ public applyRotationQuaternion(q: Quaternion): this { - return this.applyRotationQuaternionToRef(q, new (this.constructor as Vector3Constructor)()); + return this.applyRotationQuaternionToRef(q, new (this.constructor as Constructor)()); } /** @@ -1307,7 +2054,7 @@ export class Vector3 { * @returns the projected vector3 */ public projectOnPlane(plane: Plane, origin: Vector3): T { - const result = new (this.constructor as Vector3Constructor)(); + const result = new (this.constructor as Constructor)(); this.projectOnPlaneToRef(plane, origin, result); return result; @@ -1430,7 +2177,7 @@ export class Vector3 { * @returns the new Vector3 */ public multiplyByFloats(x: number, y: number, z: number): this { - return new (this.constructor as Vector3Constructor)(this._x * x, this._y * y, this._z * z); + return new (this.constructor as Constructor)(this._x * x, this._y * y, this._z * z); } /** @@ -1440,7 +2187,7 @@ export class Vector3 { * @returns the new Vector3 */ public divide(otherVector: DeepImmutable): this { - return new (this.constructor as Vector3Constructor)(this._x / otherVector._x, this._y / otherVector._y, this._z / otherVector._z); + return new (this.constructor as Constructor)(this._x / otherVector._x, this._y / otherVector._y, this._z / otherVector._z); } /** @@ -1460,8 +2207,12 @@ export class Vector3 { * @param otherVector defines the second operand * @returns the current updated Vector3 */ - public divideInPlace(otherVector: Vector3): this { - return this.divideToRef(otherVector, this); + public divideInPlace(otherVector: DeepImmutable): this { + this._x = this._x / otherVector._x; + this._y = this._y / otherVector._y; + this._z = this._z / otherVector._z; + this._isDirty = true; + return this; } /** @@ -1493,15 +2244,10 @@ export class Vector3 { * @returns the current updated Vector3 */ public minimizeInPlaceFromFloats(x: number, y: number, z: number): this { - if (x < this._x) { - this.x = x; - } - if (y < this._y) { - this.y = y; - } - if (z < this._z) { - this.z = z; - } + this._x = Math.min(x, this._x); + this._y = Math.min(y, this._y); + this._z = Math.min(z, this._z); + this._isDirty = true; return this; } @@ -1514,15 +2260,10 @@ export class Vector3 { * @returns the current updated Vector3 */ public maximizeInPlaceFromFloats(x: number, y: number, z: number): this { - if (x > this._x) { - this.x = x; - } - if (y > this._y) { - this.y = y; - } - if (z > this._z) { - this.z = z; - } + this._x = Math.max(x, this._x); + this._y = Math.max(y, this._y); + this._z = Math.max(z, this._z); + this._isDirty = true; return this; } @@ -1569,13 +2310,40 @@ export class Vector3 { return false; } + /** + * Gets the current Vector3's floored values and stores them in result + * @param result the vector to store the result in + * @returns the result vector + */ + public floorToRef(result: T): T { + result._x = Math.floor(this._x); + result._y = Math.floor(this._y); + result._z = Math.floor(this._z); + result._isDirty = true; + return result; + } + /** * Gets a new Vector3 from current Vector3 floored values * Example Playground https://playground.babylonjs.com/#R1F8YU#22 * @returns a new Vector3 */ public floor(): this { - return new (this.constructor as Vector3Constructor)(Math.floor(this._x), Math.floor(this._y), Math.floor(this._z)); + const result = new (this.constructor as Constructor)(); + return this.floorToRef(result); + } + + /** + * Gets the current Vector3's fractional values and stores them in result + * @param result the vector to store the result in + * @returns the result vector + */ + public fractToRef(result: T): T { + result._x = this.x - Math.floor(this._x); + result._y = this.y - Math.floor(this._y); + result._z = this.z - Math.floor(this._z); + result._isDirty = true; + return result; } /** @@ -1584,7 +2352,8 @@ export class Vector3 { * @returns a new Vector3 */ public fract(): this { - return new (this.constructor as Vector3Constructor)(this._x - Math.floor(this._x), this._y - Math.floor(this._y), this._z - Math.floor(this._z)); + const result = new (this.constructor as Constructor)(); + return this.fractToRef(result); } // Properties @@ -1594,7 +2363,7 @@ export class Vector3 { * @returns the length of the Vector3 */ public length(): number { - return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z); + return Math.sqrt(this.lengthSquared()); } /** @@ -1678,7 +2447,7 @@ export class Vector3 { * @returns the cross product */ public cross(other: Vector3): this { - const result = new (this.constructor as Vector3Constructor)(); + const result = new (this.constructor as Constructor)(); return Vector3.CrossToRef(this, other, result); } @@ -1703,7 +2472,7 @@ export class Vector3 { * @returns the new Vector3 */ public normalizeToNew(): this { - const normalized = new (this.constructor as Vector3Constructor)(0, 0, 0); + const normalized = new (this.constructor as Constructor)(0, 0, 0); this.normalizeToRef(normalized); return normalized; } @@ -1717,7 +2486,7 @@ export class Vector3 { public normalizeToRef(reference: T): T { const len = this.length(); if (len === 0 || len === 1.0) { - return reference.copyFromFloats(this._x, this._y, this._z); + return reference.copyFrom(this); } return this.scaleToRef(1.0 / len, reference); @@ -1729,7 +2498,7 @@ export class Vector3 { * @returns the new Vector3 */ public clone(): this { - return new (this.constructor as Vector3Constructor)(this._x, this._y, this._z); + return new (this.constructor as Constructor)(this._x, this._y, this._z); } /** @@ -1835,7 +2604,7 @@ export class Vector3 { * @param normal Normal of the projection plane * @returns the angle in radians (float) between vector0 and vector1 projected on the plane with the specified normal */ - public static GetAngleBetweenVectorsOnPlane(vector0: Vector3, vector1: Vector3, normal: Vector3): number { + public static GetAngleBetweenVectorsOnPlane(vector0: DeepImmutable, vector1: DeepImmutable, normal: DeepImmutable): number { MathTmp.Vector3[0].copyFrom(vector0); const v0 = MathTmp.Vector3[0]; MathTmp.Vector3[1].copyFrom(vector1); @@ -2298,7 +3067,7 @@ export class Vector3 { (2.0 * value1._z - 5.0 * value2._z + 4.0 * value3._z - value4._z) * squared + (-value1._z + 3.0 * value2._z - 3.0 * value3._z + value4._z) * cubed); - return new (value1.constructor as Vector3Constructor)(x, y, z); + return new (value1.constructor as Constructor)(x, y, z); } /** @@ -2312,7 +3081,7 @@ export class Vector3 { * @returns the new Vector3 */ public static Clamp(value: DeepImmutable, min: DeepImmutable, max: DeepImmutable): T { - const result = new (value.constructor as Vector3Constructor)(); + const result = new (value.constructor as Constructor)(); Vector3.ClampToRef(value, min, max, result); return result; } @@ -2383,7 +3152,7 @@ export class Vector3 { const x = value1._x * part1 + value2._x * part2 + tangent1._x * part3 + tangent2._x * part4; const y = value1._y * part1 + value2._y * part2 + tangent1._y * part3 + tangent2._y * part4; const z = value1._z * part1 + value2._z * part2 + tangent1._z * part3 + tangent2._z * part4; - return new (value1.constructor as Vector3Constructor)(x, y, z); + return new (value1.constructor as Constructor)(x, y, z); } /** @@ -2403,7 +3172,7 @@ export class Vector3 { tangent2: DeepImmutable, time: number ): T { - const result = new (value1.constructor as Vector3Constructor)(); + const result = new (value1.constructor as Constructor)(); this.Hermite1stDerivativeToRef(value1, tangent1, value2, tangent2, time, result); @@ -2447,7 +3216,7 @@ export class Vector3 { * @returns the new Vector3 */ public static Lerp(start: DeepImmutable, end: DeepImmutable, amount: number): T { - const result = new (start.constructor as Vector3Constructor)(0, 0, 0); + const result = new (start.constructor as Constructor)(0, 0, 0); Vector3.LerpToRef(start, end, amount, result); return result; } @@ -2489,7 +3258,7 @@ export class Vector3 { * @returns the cross product */ public static Cross(left: DeepImmutable, right: DeepImmutable): T { - const result = new (left.constructor as Vector3Constructor)(); + const result = new (left.constructor as Constructor)(); Vector3.CrossToRef(left, right, result); return result; } @@ -2545,7 +3314,7 @@ export class Vector3 { * @returns the new Vector3 */ public static Project(vector: DeepImmutable, world: DeepImmutable, transform: DeepImmutable, viewport: DeepImmutable): T { - const result = new (vector.constructor as Vector3Constructor)(); + const result = new (vector.constructor as Constructor)(); Vector3.ProjectToRef(vector, world, transform, viewport, result); return result; } @@ -2660,7 +3429,7 @@ export class Vector3 { view: DeepImmutable, projection: DeepImmutable ): T { - const result = new (source.constructor as Vector3Constructor)(); + const result = new (source.constructor as Constructor)(); Vector3.UnprojectToRef(source, viewportWidth, viewportHeight, world, view, projection, result); @@ -2743,7 +3512,7 @@ export class Vector3 { * @returns the new Vector3 */ public static Minimize(left: DeepImmutable, right: DeepImmutable): T { - const min = new (left.constructor as Vector3Constructor)(); + const min = new (left.constructor as Constructor)(); min.copyFrom(left); min.minimizeInPlace(right); return min; @@ -2757,7 +3526,7 @@ export class Vector3 { * @returns the new Vector3 */ public static Maximize(left: DeepImmutable, right: DeepImmutable): T { - const max = new (left.constructor as Vector3Constructor)(); + const max = new (left.constructor as Constructor)(); max.copyFrom(left); max.maximizeInPlace(right); return max; @@ -2982,7 +3751,7 @@ export class Vector3 { * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/transforms/center_origin/target_align */ public static RotationFromAxis(axis1: DeepImmutable, axis2: DeepImmutable, axis3: DeepImmutable): T { - const rotation = new (axis1.constructor as Vector3Constructor)(); + const rotation = new (axis1.constructor as Constructor)(); Vector3.RotationFromAxisToRef(axis1, axis2, axis3, rotation); return rotation; } @@ -3007,9 +3776,11 @@ export class Vector3 { /** * Vector4 class created for EulerAngle class conversion to Quaternion */ -export class Vector4 { +export class Vector4 implements Vector<[number, number, number, number]> { private static _ZeroReadOnly = Vector4.Zero() as DeepImmutable; + public readonly dimension: [4] = [4]; + /** * Creates a Vector4 object from the given floats. * @param x x value of the vector @@ -3066,12 +3837,12 @@ export class Vector4 { * Returns a new array populated with 4 elements : the Vector4 coordinates. * @returns the resulting array */ - public asArray(): number[] { + public asArray(): [number, number, number, number] { const result = new Array(); this.toArray(result, 0); - return result; + return result as [number, number, number, number]; } /** @@ -3094,11 +3865,11 @@ export class Vector4 { /** * Update the current vector from an array * @param array defines the destination array - * @param index defines the offset in the destination array + * @param offset defines the offset in the destination array * @returns the current Vector3 */ - public fromArray(array: FloatArray, index: number = 0): this { - Vector4.FromArrayToRef(array, index, this); + public fromArray(array: FloatArray, offset: number = 0): this { + Vector4.FromArrayToRef(array, offset, this); return this; } @@ -3115,13 +3886,29 @@ export class Vector4 { return this; } + /** + * Adds the given coordinates to the current Vector4 + * @param x defines the x coordinate of the operand + * @param y defines the y coordinate of the operand + * @param z defines the z coordinate of the operand + * @param w defines the w coordinate of the operand + * @returns the current updated Vector4 + */ + public addInPlaceFromFloats(x: number, y: number, z: number, w: number): this { + this.x += x; + this.y += y; + this.z += z; + this.w += w; + return this; + } + /** * Returns a new Vector4 as the result of the addition of the current Vector4 and the given one. * @param otherVector the vector to add * @returns the resulting vector */ public add(otherVector: DeepImmutable): this { - return new (this.constructor as Vector4Constructor)(this.x + otherVector.x, this.y + otherVector.y, this.z + otherVector.z, this.w + otherVector.w); + return new (this.constructor as Constructor)(this.x + otherVector.x, this.y + otherVector.y, this.z + otherVector.z, this.w + otherVector.w); } /** @@ -3157,7 +3944,7 @@ export class Vector4 { * @returns the new vector with the result */ public subtract(otherVector: DeepImmutable): this { - return new (this.constructor as Vector4Constructor)(this.x - otherVector.x, this.y - otherVector.y, this.z - otherVector.z, this.w - otherVector.w); + return new (this.constructor as Constructor)(this.x - otherVector.x, this.y - otherVector.y, this.z - otherVector.z, this.w - otherVector.w); } /** @@ -3174,9 +3961,6 @@ export class Vector4 { return result; } - /** - * Returns a new Vector4 set with the result of the subtraction of the given floats from the current Vector4 coordinates. - */ /** * Returns a new Vector4 set with the result of the subtraction of the given floats from the current Vector4 coordinates. * @param x value to subtract @@ -3186,7 +3970,7 @@ export class Vector4 { * @returns new vector containing the result */ public subtractFromFloats(x: number, y: number, z: number, w: number): this { - return new (this.constructor as Vector4Constructor)(this.x - x, this.y - y, this.z - z, this.w - w); + return new (this.constructor as Constructor)(this.x - x, this.y - y, this.z - z, this.w - w); } /** @@ -3211,7 +3995,7 @@ export class Vector4 { * @returns a new vector with the negated values */ public negate(): this { - return new (this.constructor as Vector4Constructor)(-this.x, -this.y, -this.z, -this.w); + return new (this.constructor as Constructor)(-this.x, -this.y, -this.z, -this.w); } /** @@ -3254,7 +4038,7 @@ export class Vector4 { * @returns a new vector with the result */ public scale(scale: number): this { - return new (this.constructor as Vector4Constructor)(this.x * scale, this.y * scale, this.z * scale, this.w * scale); + return new (this.constructor as Constructor)(this.x * scale, this.y * scale, this.z * scale, this.w * scale); } /** @@ -3327,7 +4111,7 @@ export class Vector4 { * @param otherVector vector to multiple with * @returns the updated Vector4. */ - public multiplyInPlace(otherVector: Vector4): this { + public multiplyInPlace(otherVector: DeepImmutable): this { this.x *= otherVector.x; this.y *= otherVector.y; this.z *= otherVector.z; @@ -3341,7 +4125,7 @@ export class Vector4 { * @returns resulting new vector */ public multiply(otherVector: DeepImmutable): this { - return new (this.constructor as Vector4Constructor)(this.x * otherVector.x, this.y * otherVector.y, this.z * otherVector.z, this.w * otherVector.w); + return new (this.constructor as Constructor)(this.x * otherVector.x, this.y * otherVector.y, this.z * otherVector.z, this.w * otherVector.w); } /** * Updates the given vector "result" with the multiplication result of the current Vector4 and the given one. @@ -3365,7 +4149,7 @@ export class Vector4 { * @returns resulting new vector */ public multiplyByFloats(x: number, y: number, z: number, w: number): this { - return new (this.constructor as Vector4Constructor)(this.x * x, this.y * y, this.z * z, this.w * w); + return new (this.constructor as Constructor)(this.x * x, this.y * y, this.z * z, this.w * w); } /** * Returns a new Vector4 set with the division result of the current Vector4 by the given one. @@ -3373,7 +4157,7 @@ export class Vector4 { * @returns resulting new vector */ public divide(otherVector: DeepImmutable): this { - return new (this.constructor as Vector4Constructor)(this.x / otherVector.x, this.y / otherVector.y, this.z / otherVector.z, this.w / otherVector.w); + return new (this.constructor as Constructor)(this.x / otherVector.x, this.y / otherVector.y, this.z / otherVector.z, this.w / otherVector.w); } /** * Updates the given vector "result" with the division result of the current Vector4 by the given one. @@ -3439,12 +4223,70 @@ export class Vector4 { return this; } + /** + * Updates the current Vector4 with the minimal coordinate values between its and the given coordinates + * @param x defines the x coordinate of the operand + * @param y defines the y coordinate of the operand + * @param z defines the z coordinate of the operand + * @param w defines the w coordinate of the operand + * @returns the current updated Vector4 + */ + public minimizeInPlaceFromFloats(x: number, y: number, z: number, w: number): this { + this.x = Math.min(x, this.x); + this.y = Math.min(y, this.y); + this.z = Math.min(z, this.z); + this.w = Math.min(w, this.w); + return this; + } + + /** + * Updates the current Vector4 with the maximal coordinate values between its and the given coordinates. + * @param x defines the x coordinate of the operand + * @param y defines the y coordinate of the operand + * @param z defines the z coordinate of the operand + * @param w defines the w coordinate of the operand + * @returns the current updated Vector4 + */ + public maximizeInPlaceFromFloats(x: number, y: number, z: number, w: number): this { + this.x = Math.max(x, this.x); + this.y = Math.max(y, this.y); + this.z = Math.max(z, this.z); + this.w = Math.max(w, this.w); + return this; + } + + /** + * Gets the current Vector4's floored values and stores them in result + * @param result the vector to store the result in + * @returns the result vector + */ + public floorToRef(result: T): T { + result.x = Math.floor(this.x); + result.y = Math.floor(this.y); + result.z = Math.floor(this.z); + result.w = Math.floor(this.w); + return result; + } + /** * Gets a new Vector4 from current Vector4 floored values * @returns a new Vector4 */ public floor(): this { - return new (this.constructor as Vector4Constructor)(Math.floor(this.x), Math.floor(this.y), Math.floor(this.z), Math.floor(this.w)); + return new (this.constructor as Constructor)(Math.floor(this.x), Math.floor(this.y), Math.floor(this.z), Math.floor(this.w)); + } + + /** + * Gets the current Vector4's fractional values and stores them in result + * @param result the vector to store the result in + * @returns the result vector + */ + public fractToRef(result: T): T { + result.x = this.x - Math.floor(this.x); + result.y = this.y - Math.floor(this.y); + result.z = this.z - Math.floor(this.z); + result.w = this.w - Math.floor(this.w); + return result; } /** @@ -3452,7 +4294,7 @@ export class Vector4 { * @returns a new Vector4 */ public fract(): this { - return new (this.constructor as Vector4Constructor)( + return new (this.constructor as Constructor)( this.x - Math.floor(this.x), this.y - Math.floor(this.y), this.z - Math.floor(this.z), @@ -3491,6 +4333,44 @@ export class Vector4 { return this.scaleInPlace(1.0 / len); } + /** + * Normalize the current Vector4 with the given input length. + * Please note that this is an in place operation. + * @param len the length of the vector + * @returns the current updated Vector4 + */ + public normalizeFromLength(len: number): this { + if (len === 0 || len === 1.0) { + return this; + } + + return this.scaleInPlace(1.0 / len); + } + + /** + * Normalize the current Vector4 to a new vector + * @returns the new Vector4 + */ + public normalizeToNew(): this { + const normalized = new (this.constructor as Constructor)(); + this.normalizeToRef(normalized); + return normalized; + } + + /** + * Normalize the current Vector4 to the reference + * @param reference define the Vector4 to update + * @returns the updated Vector4 + */ + public normalizeToRef(reference: T): T { + const len = this.length(); + if (len === 0 || len === 1.0) { + return reference.copyFrom(this); + } + + return this.scaleToRef(1.0 / len, reference); + } + /** * Returns a new Vector3 from the Vector4 (x, y, z) coordinates. * @returns this converted to a new vector3 @@ -3504,7 +4384,7 @@ export class Vector4 { * @returns the new cloned vector */ public clone(): this { - return new (this.constructor as Vector4Constructor)(this.x, this.y, this.z, this.w); + return new (this.constructor as Constructor)(this.x, this.y, this.z, this.w); } /** * Updates the current Vector4 with the given one coordinates. @@ -3546,9 +4426,9 @@ export class Vector4 { } /** - * Copies the given float to the current Vector3 coordinates + * Copies the given float to the current Vector4 coordinates * @param v defines the x, y, z and w coordinates of the operand - * @returns the current updated Vector3 + * @returns the current updated Vector4 */ public setAll(v: number): this { this.x = this.y = this.z = this.w = v; @@ -3669,7 +4549,7 @@ export class Vector4 { * @returns a new vector with the minimum of the left and right vector values */ public static Minimize(left: DeepImmutable, right: DeepImmutable): T { - const min = new (left.constructor as Vector4Constructor)(); + const min = new (left.constructor as Constructor)(); min.copyFrom(left); min.minimizeInPlace(right); return min; @@ -3682,7 +4562,7 @@ export class Vector4 { * @returns a new vector with the maximum of the left and right vector values */ public static Maximize(left: DeepImmutable, right: DeepImmutable): T { - const max = new (left.constructor as Vector4Constructor)(); + const max = new (left.constructor as Constructor)(); max.copyFrom(left); max.maximizeInPlace(right); return max; @@ -3792,7 +4672,7 @@ export class Vector4 { * @returns the new vector */ public static TransformNormal(vector: DeepImmutable, transformation: DeepImmutable): T { - const result = new (vector.constructor as Vector4Constructor)(); + const result = new (vector.constructor as Constructor)(); Vector4.TransformNormalToRef(vector, transformation, result); return result; } @@ -4013,7 +4893,7 @@ export class Quaternion { * @returns a new quaternion copied from the current one */ public clone(): this { - return new (this.constructor as QuaternionConstructor)(this._x, this._y, this._z, this._w); + return new (this.constructor as Constructor)(this._x, this._y, this._z, this._w); } /** @@ -4069,7 +4949,7 @@ export class Quaternion { * @returns a new quaternion as the addition result of the given one and the current quaternion */ public add(other: DeepImmutable): this { - return new (this.constructor as QuaternionConstructor)(this._x + other._x, this._y + other._y, this._z + other._z, this._w + other._w); + return new (this.constructor as Constructor)(this._x + other._x, this._y + other._y, this._z + other._z, this._w + other._w); } /** @@ -4094,7 +4974,7 @@ export class Quaternion { * @returns a new quaternion as the subtraction result of the given one from the current one */ public subtract(other: Quaternion): this { - return new (this.constructor as QuaternionConstructor)(this._x - other._x, this._y - other._y, this._z - other._z, this._w - other._w); + return new (this.constructor as Constructor)(this._x - other._x, this._y - other._y, this._z - other._z, this._w - other._w); } /** @@ -4119,7 +4999,7 @@ export class Quaternion { * @returns a new quaternion set by multiplying the current quaternion coordinates by the float "scale" */ public scale(value: number): this { - return new (this.constructor as QuaternionConstructor)(this._x * value, this._y * value, this._z * value, this._w * value); + return new (this.constructor as Constructor)(this._x * value, this._y * value, this._z * value, this._w * value); } /** @@ -4177,7 +5057,7 @@ export class Quaternion { * @returns a new quaternion set as the multiplication result of the current one with the given one "q1" */ public multiply(q1: DeepImmutable): this { - const result = new (this.constructor as QuaternionConstructor)(0, 0, 0, 1.0); + const result = new (this.constructor as Constructor)(0, 0, 0, 1.0); this.multiplyToRef(q1, result); return result; } @@ -4239,7 +5119,7 @@ export class Quaternion { * @returns a new quaternion */ public conjugate(): this { - return new (this.constructor as QuaternionConstructor)(-this._x, -this._y, -this._z, this._w); + return new (this.constructor as Constructor)(-this._x, -this._y, -this._z, this._w); } /** @@ -4523,7 +5403,7 @@ export class Quaternion { * @returns a new quaternion as the inverted current quaternion */ public static Inverse(q: DeepImmutable): T { - return new (q.constructor as QuaternionConstructor)(-q._x, -q._y, -q._z, q._w); + return new (q.constructor as Constructor)(-q._x, -q._y, -q._z, q._w); } /** @@ -4947,7 +5827,7 @@ export class Quaternion { const y = value1._y * part1 + value2._y * part2 + tangent1._y * part3 + tangent2._y * part4; const z = value1._z * part1 + value2._z * part2 + tangent1._z * part3 + tangent2._z * part4; const w = value1._w * part1 + value2._w * part2 + tangent1._w * part3 + tangent2._w * part4; - return new (value1.constructor as QuaternionConstructor)(x, y, z, w); + return new (value1.constructor as Constructor)(x, y, z, w); } /** @@ -4967,7 +5847,7 @@ export class Quaternion { tangent2: DeepImmutable, time: number ): T { - const result = new (value1.constructor as QuaternionConstructor)(); + const result = new (value1.constructor as Constructor)(); this.Hermite1stDerivativeToRef(value1, tangent1, value2, tangent2, time, result); @@ -5248,7 +6128,7 @@ export class Matrix { * @returns a new matrix as the addition of the current matrix and the given one */ public add(other: DeepImmutable): this { - const result = new (this.constructor as MatrixConstructor)(); + const result = new (this.constructor as Constructor)(); this.addToRef(other, result); return result; } @@ -5499,7 +6379,7 @@ export class Matrix { * @returns a new matrix set with the multiplication result of the current Matrix and the given one */ public multiply(other: DeepImmutable): this { - const result = new (this.constructor as MatrixConstructor)(); + const result = new (this.constructor as Constructor)(); this.multiplyToRef(other, result); return result; } @@ -5680,7 +6560,7 @@ export class Matrix { * @returns a new matrix from the current matrix */ public clone(): this { - const matrix = new (this.constructor as MatrixConstructor)(); + const matrix = new (this.constructor as Constructor)(); matrix.copyFrom(this); return matrix; } @@ -5849,7 +6729,7 @@ export class Matrix { * @returns the new transposed matrix */ public transpose(): this { - const result = new (this.constructor as MatrixConstructor)(); + const result = new (this.constructor as Constructor)(); Matrix.TransposeToRef(this, result); return result; } @@ -5895,7 +6775,7 @@ export class Matrix { * @returns a new matrix */ public scale(scale: number): this { - const result = new (this.constructor as MatrixConstructor)(); + const result = new (this.constructor as Constructor)(); this.scaleToRef(scale, result); return result; } @@ -5947,7 +6827,7 @@ export class Matrix { * @returns a new matrix sets to the extracted rotation matrix from the current one */ public getRotationMatrix(): this { - const result = new (this.constructor as MatrixConstructor)(); + const result = new (this.constructor as Constructor)(); this.getRotationMatrixToRef(result); return result; } @@ -6294,7 +7174,7 @@ export class Matrix { * @returns the new matrix */ public static Invert(source: DeepImmutable): T { - const result = new (source.constructor as MatrixConstructor)(); + const result = new (source.constructor as Constructor)(); source.invertToRef(result); return result; } @@ -6573,7 +7453,7 @@ export class Matrix { * @returns the new matrix */ public static Lerp(startValue: DeepImmutable, endValue: DeepImmutable, gradient: number): T { - const result = new (startValue.constructor as MatrixConstructor)(); + const result = new (startValue.constructor as Constructor)(); Matrix.LerpToRef(startValue, endValue, gradient, result); return result; } @@ -6611,7 +7491,7 @@ export class Matrix { * @returns the new matrix */ public static DecomposeLerp(startValue: DeepImmutable, endValue: DeepImmutable, gradient: number): T { - const result = new (startValue.constructor as MatrixConstructor)(); + const result = new (startValue.constructor as Constructor)(); Matrix.DecomposeLerpToRef(startValue, endValue, gradient, result); return result; } @@ -7325,7 +8205,7 @@ export class Matrix { const viewportMatrix = Matrix.FromValues(cw / 2.0, 0.0, 0.0, 0.0, 0.0, -ch / 2.0, 0.0, 0.0, 0.0, 0.0, zmax - zmin, 0.0, cx + cw / 2.0, ch / 2.0 + cy, zmin, 1.0); - const matrix = new (world.constructor as MatrixConstructor)(); + const matrix = new (world.constructor as Constructor)(); world.multiplyToRef(view, matrix); matrix.multiplyToRef(projection, matrix); return matrix.multiplyToRef(viewportMatrix, matrix); @@ -7359,7 +8239,7 @@ export class Matrix { * @returns the new matrix */ public static Transpose(matrix: DeepImmutable): T { - const result = new (matrix.constructor as MatrixConstructor)(); + const result = new (matrix.constructor as Constructor)(); Matrix.TransposeToRef(matrix, result); return result; } diff --git a/packages/dev/core/src/types.ts b/packages/dev/core/src/types.ts index 0d3eaeccc85..954555b6df5 100644 --- a/packages/dev/core/src/types.ts +++ b/packages/dev/core/src/types.ts @@ -62,3 +62,7 @@ export type DeepImmutableObject = { readonly [K in keyof T]: DeepImmutable extends ReadonlyArray> {} /** @internal */ /* interface DeepImmutableMap extends ReadonlyMap, DeepImmutable> {} // es2015+ only */ + +export type Constructor any, I extends InstanceType = InstanceType> = { + new (...args: ConstructorParameters): I; +};