diff --git a/docs/modules/core/api-reference/matrix4.md b/docs/modules/core/api-reference/matrix4.md index 30121a61..e351357e 100644 --- a/docs/modules/core/api-reference/matrix4.md +++ b/docs/modules/core/api-reference/matrix4.md @@ -99,6 +99,15 @@ Sets the matrix to a transformation corresponding to the rotations represented b - `quaternion` (`Quaternion`) - the quaternion to create matrix from +##### fromTranslationQuaternion(translation: Vector3, quaternion: Quaternion): this + +Sets the matrix to a transformation corresponding to the translation and rotations represented by the given parameters. + +`matrix4.fromTranslationQuaternion(translation, quaternion)` + +- `translation` (`Vector3`) - the translation to create matrix from +- `quaternion` (`Quaternion`) - the quaternion to create matrix from + ##### `frustum(options: {left: number, right: number, bottom: number, top: number, near: number, far: number}): this` Generates a frustum matrix with the given bounds. The frustum far plane can be infinite. diff --git a/modules/core/src/classes/matrix4.ts b/modules/core/src/classes/matrix4.ts index d05236aa..3b0f097e 100644 --- a/modules/core/src/classes/matrix4.ts +++ b/modules/core/src/classes/matrix4.ts @@ -10,6 +10,7 @@ import {vec2_transformMat4AsVector, vec3_transformMat4AsVector} from '../lib/gl- // @ts-ignore gl-matrix types... import { fromQuat as mat4_fromQuat, + fromRotationTranslation as mat4_fromRotationTranslation, frustum as mat4_frustum, lookAt as mat4_lookAt, ortho as mat4_ortho, @@ -231,6 +232,20 @@ export class Matrix4 extends Matrix { return this.check(); } + /** + * Calculates a 4x4 matrix from the given translation and quaternion + * @param translation Vector3 to create matrix from + * @param quaternion Quaternion to create matrix from + * @returns self + */ + fromTranslationQuaternion( + translation: Readonly, + quaternion: Readonly + ): this { + mat4_fromRotationTranslation(this, quaternion, translation); + return this.check(); + } + /** * Generates a frustum matrix with the given bounds * @param view.left - Left bound of the frustum @@ -368,7 +383,9 @@ export class Matrix4 extends Matrix { * @param result * @returns self */ - getScale(result: NumericArray = [-0, -0, -0]): NumericArray { + getScale(): NumericArray; + getScale(result: T): T; + getScale(result = [-0, -0, -0]): NumericArray { // explicit is faster than hypot... result[0] = Math.sqrt(this[0] * this[0] + this[1] * this[1] + this[2] * this[2]); result[1] = Math.sqrt(this[4] * this[4] + this[5] * this[5] + this[6] * this[6]); @@ -384,7 +401,9 @@ export class Matrix4 extends Matrix { * @param result * @returns self */ - getTranslation(result: NumericArray = [-0, -0, -0]): NumericArray { + getTranslation(): NumericArray; + getTranslation(result: T): T; + getTranslation(result = [-0, -0, -0]): NumericArray { result[0] = this[12]; result[1] = this[13]; result[2] = this[14]; @@ -397,8 +416,12 @@ export class Matrix4 extends Matrix { * @param scaleResult * @returns self */ - getRotation(result?: NumericArray, scaleResult?: NumericArray): NumericArray { - result = result || [-0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0]; + getRotation(scaleResult?: NumericArray): NumericArray; + getRotation(result: T, scaleResult?: NumericArray): T; + getRotation( + result = [-0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0], + scaleResult?: NumericArray + ): NumericArray { scaleResult = scaleResult || [-0, -0, -0]; const scale = this.getScale(scaleResult); const inverseScale0 = 1 / scale[0]; @@ -429,8 +452,12 @@ export class Matrix4 extends Matrix { * @param scaleResult * @returns self */ - getRotationMatrix3(result?: NumericArray, scaleResult?: NumericArray): NumericArray { - result = result || [-0, -0, -0, -0, -0, -0, -0, -0, -0]; + getRotationMatrix3(scaleResult?: NumericArray): NumericArray; + getRotationMatrix3(result: T, scaleResult?: NumericArray): T; + getRotationMatrix3( + result = [-0, -0, -0, -0, -0, -0, -0, -0, -0], + scaleResult?: NumericArray + ): NumericArray { scaleResult = scaleResult || [-0, -0, -0]; const scale = this.getScale(scaleResult); const inverseScale0 = 1 / scale[0]; diff --git a/modules/core/src/gl-matrix/quat.ts b/modules/core/src/gl-matrix/quat.ts index 653797be..aa5b757d 100644 --- a/modules/core/src/gl-matrix/quat.ts +++ b/modules/core/src/gl-matrix/quat.ts @@ -354,22 +354,22 @@ export function slerp(out, a, b, t) { * @param {quat} out the receiving quaternion * @returns {quat} out */ -// export function random(out) { -// // Implementation of http://planning.cs.uiuc.edu/node198.html -// // TODO: Calling random 3 times is probably not the fastest solution -// let u1 = glMatrix.RANDOM(); -// let u2 = glMatrix.RANDOM(); -// let u3 = glMatrix.RANDOM(); - -// let sqrt1MinusU1 = Math.sqrt(1 - u1); -// let sqrtU1 = Math.sqrt(u1); - -// out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2); -// out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2); -// out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3); -// out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3); -// return out; -// } +export function random(out) { + // Implementation of http://planning.cs.uiuc.edu/node198.html + // TODO: Calling random 3 times is probably not the fastest solution + let u1 = glMatrix.RANDOM(); + let u2 = glMatrix.RANDOM(); + let u3 = glMatrix.RANDOM(); + + let sqrt1MinusU1 = Math.sqrt(1 - u1); + let sqrtU1 = Math.sqrt(u1); + + out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2); + out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2); + out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3); + out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3); + return out; +} /** * Calculates the inverse of a quat diff --git a/modules/core/test/classes/matrix4.spec.ts b/modules/core/test/classes/matrix4.spec.ts index 68487c81..757b794c 100644 --- a/modules/core/test/classes/matrix4.spec.ts +++ b/modules/core/test/classes/matrix4.spec.ts @@ -2,7 +2,9 @@ // MIT License /* eslint-disable max-statements */ -import {Matrix4, Vector3, config, configure} from '@math.gl/core'; +import {Matrix3, Matrix4, Quaternion, Vector3, config, configure} from '@math.gl/core'; +import {random as vec3_random} from '../../src/gl-matrix/vec3'; +import {random as quat_random} from '../../src/gl-matrix/quat'; import test from 'tape-promise/tape'; import {tapeEquals, tapeEqualsEpsilon} from 'test/utils/tape-assertions'; @@ -42,6 +44,20 @@ test('Matrix4#fromQuaternion', (t) => { t.end(); }); +test('Matrix4#fromTranslationQuaternion', (t) => { + const translation = new Vector3(vec3_random([-0, -0, -0], 100 * Math.random())); + const quaternion = new Quaternion(quat_random([-0, -0, -0, -0])); + + tapeEquals( + t, + new Matrix4().fromTranslationQuaternion(translation, quaternion), + new Matrix4() + .fromQuaternion(quaternion) + .multiplyLeft(new Matrix4().identity().translate(translation)) + ); + t.end(); +}); + test('Matrix4#from', (t) => { tapeEquals(t, new Matrix4().from(INDICES_MATRIX), INDICES_MATRIX); // tapeEquals(t, new Matrix4().from({x: 1, y: 2, z: 3, w: 4}), [1, 2, 3, 4]); @@ -159,6 +175,18 @@ test('Matrix4#getScale', (t) => { t.end(); }); +test('Matrix4#getScaleAsVector3', (t) => { + const INPUT = INDICES_MATRIX; + const RESULT = new Vector3([3.7416573867739413, 10.488088481701515, 17.37814719698276]); + + const scale = new Matrix4(INPUT).getScale(new Vector3()); + + tapeEquals(t, scale instanceof Vector3, true); + tapeEquals(t, scale, RESULT, 'getScale gave the right result'); + + t.end(); +}); + test('Matrix4#getRotation', (t) => { const INPUT = INDICES_MATRIX; const RESULT = [ @@ -173,6 +201,21 @@ test('Matrix4#getRotation', (t) => { t.end(); }); +test('Matrix4#getRotationAsMatrix4', (t) => { + const INPUT = INDICES_MATRIX; + const RESULT = new Matrix4([ + 0.2672612419124244, 0.19069251784911848, 0.17263060129453078, 0, 1.3363062095621219, + 0.5720775535473555, 0.4028047363539052, 0, 2.4053511772118195, 0.9534625892455924, + 0.6329788714132796, 0, 0, 0, 0, 1 + ]); + + const m = new Matrix4(INPUT).getRotation(new Matrix4(), [...INDICES_MATRIX]); + tapeEquals(t, m instanceof Matrix4, true); + tapeEquals(t, m, RESULT, 'getRotation gave the right result'); + + t.end(); +}); + test('Matrix4#getRotationMatrix3', (t) => { const INPUT = INDICES_MATRIX; const RESULT = [ @@ -187,6 +230,21 @@ test('Matrix4#getRotationMatrix3', (t) => { t.end(); }); +test('Matrix4#getRotationMatrix3AsMatrix3', (t) => { + const INPUT = INDICES_MATRIX; + const RESULT = new Matrix3([ + 0.2672612419124244, 0.19069251784911848, 0.17263060129453078, 1.3363062095621219, + 0.5720775535473555, 0.4028047363539052, 2.4053511772118195, 0.9534625892455924, + 0.6329788714132796 + ]); + + const m = new Matrix4(INPUT).getRotationMatrix3(new Matrix3(), [...INDICES_MATRIX.slice(0, 9)]); + tapeEquals(t, m instanceof Matrix3, true); + tapeEquals(t, m, RESULT, 'getRotationMatrix3 gave the right result'); + + t.end(); +}); + test('Matrix4#getTranslation', (t) => { const INPUT = INDICES_MATRIX; const RESULT = [13, 14, 15]; @@ -197,6 +255,17 @@ test('Matrix4#getTranslation', (t) => { t.end(); }); +test('Matrix4#getTranslationAsVector3', (t) => { + const INPUT = INDICES_MATRIX; + const RESULT = new Vector3([13, 14, 15]); + + const m = new Matrix4(INPUT).getTranslation(new Vector3()); + tapeEquals(t, m instanceof Vector3, true); + tapeEquals(t, m, RESULT, 'getTranslation gave the right result'); + + t.end(); +}); + test('Matrix4#perspective#', (t) => { const fovy = Math.PI * 0.5; const result = new Matrix4().perspective({fovy, aspect: 1, near: 0, far: 1});