const tests = [
{e: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], args: []},
{e: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], args: [1]},
{e: [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], args: [1, 2]},
{e: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0], args: [1, 2, 3]},
{e: [1, 2, 3, 0, 4, 0, 0, 0, 0, 0, 0], args: [1, 2, 3, 4]},
{e: [1, 2, 3, 0, 4, 5, 0, 0, 0, 0, 0], args: [1, 2, 3, 4, 5]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 0, 0, 0], args: [1, 2, 3, 4, 5, 6]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 7, 0, 0], args: [1, 2, 3, 4, 5, 6, 7]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 0], args: [1, 2, 3, 4, 5, 6, 7, 8]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9], args: [1, 2, 3, 4, 5, 6, 7, 8, 9]},
];
for (const {e, args} of tests) {
const expected = mat3.clone(e);
const m = mat3.create(...args);
assertMat3Equal(m, expected);
}
const expected = [
-0, -1, -2, 0,
-4, -5, -6, 0,
-8, -9, -10, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.negate(m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.add(m, m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.multiplyScalar(m, 2, newDst);
}, expected);
const expected = m;
testMat3WithAndWithoutDest((newDst) => {
const result = mat3.copy(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const genAlmostEqualMat = i => new Array(12).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : utils.EPSILON * 0.5));
const genNotAlmostEqualMat = i => new Array(12).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 9; ++i) {
assertTruthy(mat3.equalsApproximately(
mat3.clone(genAlmostEqualMat(-1)),
mat3.clone(genAlmostEqualMat(i + (i / 3 | 0)))),
`${i}`);
assertFalsy(mat3.equalsApproximately(
mat3.clone(genNotAlmostEqualMat(-1)),
mat3.clone(genNotAlmostEqualMat(i + (i / 3 | 0)))),
`${i}`);
}
const genNotEqualMat = i => new Array(12).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 9; ++i) {
assertTruthy(mat3.equals(
mat3.clone(genNotEqualMat(i + (i / 3 | 0))),
mat3.clone(genNotEqualMat(i + (i / 3 | 0)))),
`${i}`);
assertFalsy(mat3.equals(
mat3.clone(genNotEqualMat(-1)),
mat3.clone(genNotEqualMat(i + (i / 3 | 0)))),
`${i}`);
}
const expected = m;
testMat3WithAndWithoutDest((newDst) => {
const result = mat3.clone(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const expected = [2, 3, 4, 0, 22, 33, 44, 0, 222, 333, 444, 0];
testMat3WithAndWithoutDest((v0, v1, v2, v3, v4, v5, v6, v7, v8, newDst) => {
return mat3.set(v0, v1, v2, v3, v4, v5, v6, v7, v8, newDst);
}, expected, 2, 3, 4, 22, 33, 44, 222, 333, 444);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.identity(newDst);
}, expected);
const expected = [
0, 4, 8, 12,
1, 5, 9, 13,
2, 6, 10, 14,
3, 7, 11, 15,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.transpose(m, newDst);
}, expected);
testMultiply(mat3.multiply);
testMultiply(mat3.mul);
testInverse(mat3.inverse);
testInverse(mat3.invert);
function det(m) {
const m00 = m[0 * 4 + 0];
const m01 = m[0 * 4 + 1];
const m02 = m[0 * 4 + 2];
const m10 = m[1 * 4 + 0];
const m11 = m[1 * 4 + 1];
const m12 = m[1 * 4 + 2];
const m20 = m[2 * 4 + 0];
const m21 = m[2 * 4 + 1];
const m22 = m[2 * 4 + 2];
return m00 * (m11 * m22 - m21 * m12) -
m10 * (m01 * m22 - m21 * m02) +
m20 * (m01 * m12 - m11 * m02);
}
[
[
2, 1, 3, 0,
1, 2, 1, 0,
3, 1, 2, 0,
],
[
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
],
].forEach(v => {
const m = mat3.clone(v);
assertEqual(mat3.determinant(m), det(m));
});
const expected = [
0, 1, 2, 0,
4, 5, 6, 0,
11, 22, 1, 1,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.setTranslation(m, [11, 22], newDst);
}, expected);
const expected = [8, 9];
testV2WithAndWithoutDest((newDst) => {
return mat3.getTranslation(m, newDst);
}, expected);
[
[0, 1],
[4, 5],
].forEach((expected, ndx) => {
testV2WithAndWithoutDest((newDst) => {
return mat3.getAxis(m, ndx, newDst);
}, expected);
});
[
[
11, 22, 2, 0,
4, 5, 6, 0,
8, 9, 10, 0,
],
[
0, 1, 2, 0,
11, 22, 6, 0,
8, 9, 10, 0,
],
].forEach((expected, ndx) => {
testMat3WithAndWithoutDest((newDst) => {
return mat3.setAxis(m, [11, 22], ndx, newDst);
}, expected);
});
const m = [
2, 8, 3, 0,
5, 6, 7, 0,
9, 10, 11, 0,
];
const expected = [
Math.sqrt(2 * 2 + 8 * 8),
Math.sqrt(5 * 5 + 6 * 6),
];
testV2WithAndWithoutDest((newDst) => {
return mat3.getScaling(m, newDst);
}, expected);
const m = [
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16,
];
const expected = [
Math.sqrt(1 * 1 + 2 * 2 + 3 * 3),
Math.sqrt(5 * 5 + 6 * 6 + 7 * 7),
Math.sqrt(9 * 9 + 10 * 10 + 11 * 11),
];
testVec3WithAndWithoutDest((newDst) => {
return mat3.get3DScaling(m, newDst);
}, expected);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
2, 3, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.translation([2, 3], newDst);
}, expected);
const expected = [
0, 1, 2, 0,
4, 5, 6, 0,
8 + 0 * 2 + 4 * 3,
9 + 1 * 2 + 5 * 3,
10 + 2 * 2 + 6 * 3, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.translate(m, [2, 3], newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotation(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotation(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotate(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
1, 0, 0, 0,
0, c, s, 0,
0, -s, c, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotationX(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotationX(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotateX(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, 0, -s, 0,
0, 1, 0, 0,
s, 0, c, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotationY(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotationY(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotateY(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotationZ(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotationZ(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotateZ(m, angle, newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scaling([2, 3], newDst);
}, expected);
const expected = [
0, 2, 4, 0,
12, 15, 18, 0,
8, 9, 10, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scale(m, [2, 3], newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scaling3D([2, 3, 4], newDst);
}, expected);
const expected = [
0, 2, 4, 0,
12, 15, 18, 0,
32, 36, 40, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scale3D(m, [2, 3, 4], newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 2, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScaling(2, newDst);
}, expected);
const expected = [
0, 2, 4, 0,
8, 10, 12, 0,
8, 9, 10, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScale(m, 2, newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 2, 0, 0,
0, 0, 2, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScaling3D(2, newDst);
}, expected);
const expected = [
0, 2, 4, 0,
8, 10, 12, 0,
16, 18, 20, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScale3D(m, 2, newDst);
}, expected);
const expected = [
1, 2, 3, 0,
5, 6, 7, 0,
9, 10, 11, 0,
];
testMat3WithAndWithoutDest((newDst) => {
const m4 = mat4.create(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);
return mat3.fromMat4(m4, newDst);
}, expected);
const tests = [
{ q: quat.fromEuler(Math.PI, 0, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationX(Math.PI)), },
{ q: quat.fromEuler(0, Math.PI, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationY(Math.PI)), },
{ q: quat.fromEuler(0, 0, Math.PI, 'xyz'), expected: mat3.fromMat4(mat4.rotationZ(Math.PI)), },
{ q: quat.fromEuler(Math.PI / 2, 0, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationX(Math.PI / 2)), },
{ q: quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationY(Math.PI / 2)), },
{ q: quat.fromEuler(0, 0, Math.PI / 2, 'xyz'), expected: mat3.fromMat4(mat4.rotationZ(Math.PI / 2)), },
];
for (const {q, expected} of tests) {
testMat3WithAndWithoutDest((newDst) => {
return mat3.fromQuat(q, newDst);
}, expected);
}
const tests = [
{e: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], args: []},
{e: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], args: [1]},
{e: [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], args: [1, 2]},
{e: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0], args: [1, 2, 3]},
{e: [1, 2, 3, 0, 4, 0, 0, 0, 0, 0, 0], args: [1, 2, 3, 4]},
{e: [1, 2, 3, 0, 4, 5, 0, 0, 0, 0, 0], args: [1, 2, 3, 4, 5]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 0, 0, 0], args: [1, 2, 3, 4, 5, 6]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 7, 0, 0], args: [1, 2, 3, 4, 5, 6, 7]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 0], args: [1, 2, 3, 4, 5, 6, 7, 8]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9], args: [1, 2, 3, 4, 5, 6, 7, 8, 9]},
];
for (const {e, args} of tests) {
const expected = mat3.clone(e);
const m = mat3.create(...args);
assertMat3Equal(m, expected);
}
const expected = [
-0, -1, -2, 0,
-4, -5, -6, 0,
-8, -9, -10, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.negate(m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.add(m, m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.multiplyScalar(m, 2, newDst);
}, expected);
const expected = m;
testMat3WithAndWithoutDest((newDst) => {
const result = mat3.copy(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const genAlmostEqualMat = i => new Array(12).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : utils.EPSILON * 0.5));
const genNotAlmostEqualMat = i => new Array(12).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 9; ++i) {
assertTruthy(mat3.equalsApproximately(
mat3.clone(genAlmostEqualMat(-1)),
mat3.clone(genAlmostEqualMat(i + (i / 3 | 0)))),
`${i}`);
assertFalsy(mat3.equalsApproximately(
mat3.clone(genNotAlmostEqualMat(-1)),
mat3.clone(genNotAlmostEqualMat(i + (i / 3 | 0)))),
`${i}`);
}
const genNotEqualMat = i => new Array(12).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 9; ++i) {
assertTruthy(mat3.equals(
mat3.clone(genNotEqualMat(i + (i / 3 | 0))),
mat3.clone(genNotEqualMat(i + (i / 3 | 0)))),
`${i}`);
assertFalsy(mat3.equals(
mat3.clone(genNotEqualMat(-1)),
mat3.clone(genNotEqualMat(i + (i / 3 | 0)))),
`${i}`);
}
const expected = m;
testMat3WithAndWithoutDest((newDst) => {
const result = mat3.clone(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const expected = [2, 3, 4, 0, 22, 33, 44, 0, 222, 333, 444, 0];
testMat3WithAndWithoutDest((v0, v1, v2, v3, v4, v5, v6, v7, v8, newDst) => {
return mat3.set(v0, v1, v2, v3, v4, v5, v6, v7, v8, newDst);
}, expected, 2, 3, 4, 22, 33, 44, 222, 333, 444);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.identity(newDst);
}, expected);
const expected = [
0, 4, 8, 12,
1, 5, 9, 13,
2, 6, 10, 14,
3, 7, 11, 15,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.transpose(m, newDst);
}, expected);
testMultiply(mat3.multiply);
testMultiply(mat3.mul);
testInverse(mat3.inverse);
testInverse(mat3.invert);
function det(m) {
const m00 = m[0 * 4 + 0];
const m01 = m[0 * 4 + 1];
const m02 = m[0 * 4 + 2];
const m10 = m[1 * 4 + 0];
const m11 = m[1 * 4 + 1];
const m12 = m[1 * 4 + 2];
const m20 = m[2 * 4 + 0];
const m21 = m[2 * 4 + 1];
const m22 = m[2 * 4 + 2];
return m00 * (m11 * m22 - m21 * m12) -
m10 * (m01 * m22 - m21 * m02) +
m20 * (m01 * m12 - m11 * m02);
}
[
[
2, 1, 3, 0,
1, 2, 1, 0,
3, 1, 2, 0,
],
[
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
],
].forEach(v => {
const m = mat3.clone(v);
assertEqual(mat3.determinant(m), det(m));
});
const expected = [
0, 1, 2, 0,
4, 5, 6, 0,
11, 22, 1, 1,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.setTranslation(m, [11, 22], newDst);
}, expected);
const expected = [8, 9];
testV2WithAndWithoutDest((newDst) => {
return mat3.getTranslation(m, newDst);
}, expected);
[
[0, 1],
[4, 5],
].forEach((expected, ndx) => {
testV2WithAndWithoutDest((newDst) => {
return mat3.getAxis(m, ndx, newDst);
}, expected);
});
[
[
11, 22, 2, 0,
4, 5, 6, 0,
8, 9, 10, 0,
],
[
0, 1, 2, 0,
11, 22, 6, 0,
8, 9, 10, 0,
],
].forEach((expected, ndx) => {
testMat3WithAndWithoutDest((newDst) => {
return mat3.setAxis(m, [11, 22], ndx, newDst);
}, expected);
});
const m = [
2, 8, 3, 0,
5, 6, 7, 0,
9, 10, 11, 0,
];
const expected = [
Math.sqrt(2 * 2 + 8 * 8),
Math.sqrt(5 * 5 + 6 * 6),
];
testV2WithAndWithoutDest((newDst) => {
return mat3.getScaling(m, newDst);
}, expected);
const m = [
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16,
];
const expected = [
Math.sqrt(1 * 1 + 2 * 2 + 3 * 3),
Math.sqrt(5 * 5 + 6 * 6 + 7 * 7),
Math.sqrt(9 * 9 + 10 * 10 + 11 * 11),
];
testVec3WithAndWithoutDest((newDst) => {
return mat3.get3DScaling(m, newDst);
}, expected);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
2, 3, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.translation([2, 3], newDst);
}, expected);
const expected = [
0, 1, 2, 0,
4, 5, 6, 0,
8 + 0 * 2 + 4 * 3,
9 + 1 * 2 + 5 * 3,
10 + 2 * 2 + 6 * 3, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.translate(m, [2, 3], newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotation(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotation(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotate(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
1, 0, 0, 0,
0, c, s, 0,
0, -s, c, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotationX(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotationX(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotateX(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, 0, -s, 0,
0, 1, 0, 0,
s, 0, c, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotationY(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotationY(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotateY(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotationZ(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotationZ(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotateZ(m, angle, newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scaling([2, 3], newDst);
}, expected);
const expected = [
0, 2, 4, 0,
12, 15, 18, 0,
8, 9, 10, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scale(m, [2, 3], newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scaling3D([2, 3, 4], newDst);
}, expected);
const expected = [
0, 2, 4, 0,
12, 15, 18, 0,
32, 36, 40, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scale3D(m, [2, 3, 4], newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 2, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScaling(2, newDst);
}, expected);
const expected = [
0, 2, 4, 0,
8, 10, 12, 0,
8, 9, 10, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScale(m, 2, newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 2, 0, 0,
0, 0, 2, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScaling3D(2, newDst);
}, expected);
const expected = [
0, 2, 4, 0,
8, 10, 12, 0,
16, 18, 20, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScale3D(m, 2, newDst);
}, expected);
const expected = [
1, 2, 3, 0,
5, 6, 7, 0,
9, 10, 11, 0,
];
testMat3WithAndWithoutDest((newDst) => {
const m4 = mat4.create(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);
return mat3.fromMat4(m4, newDst);
}, expected);
const tests = [
{ q: quat.fromEuler(Math.PI, 0, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationX(Math.PI)), },
{ q: quat.fromEuler(0, Math.PI, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationY(Math.PI)), },
{ q: quat.fromEuler(0, 0, Math.PI, 'xyz'), expected: mat3.fromMat4(mat4.rotationZ(Math.PI)), },
{ q: quat.fromEuler(Math.PI / 2, 0, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationX(Math.PI / 2)), },
{ q: quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationY(Math.PI / 2)), },
{ q: quat.fromEuler(0, 0, Math.PI / 2, 'xyz'), expected: mat3.fromMat4(mat4.rotationZ(Math.PI / 2)), },
];
for (const {q, expected} of tests) {
testMat3WithAndWithoutDest((newDst) => {
return mat3.fromQuat(q, newDst);
}, expected);
}
const tests = [
{e: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], args: []},
{e: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], args: [1]},
{e: [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], args: [1, 2]},
{e: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0], args: [1, 2, 3]},
{e: [1, 2, 3, 0, 4, 0, 0, 0, 0, 0, 0], args: [1, 2, 3, 4]},
{e: [1, 2, 3, 0, 4, 5, 0, 0, 0, 0, 0], args: [1, 2, 3, 4, 5]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 0, 0, 0], args: [1, 2, 3, 4, 5, 6]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 7, 0, 0], args: [1, 2, 3, 4, 5, 6, 7]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 0], args: [1, 2, 3, 4, 5, 6, 7, 8]},
{e: [1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9], args: [1, 2, 3, 4, 5, 6, 7, 8, 9]},
];
for (const {e, args} of tests) {
const expected = mat3.clone(e);
const m = mat3.create(...args);
assertMat3Equal(m, expected);
}
const expected = [
-0, -1, -2, 0,
-4, -5, -6, 0,
-8, -9, -10, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.negate(m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.add(m, m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.multiplyScalar(m, 2, newDst);
}, expected);
const expected = m;
testMat3WithAndWithoutDest((newDst) => {
const result = mat3.copy(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const genAlmostEqualMat = i => new Array(12).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : utils.EPSILON * 0.5));
const genNotAlmostEqualMat = i => new Array(12).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 9; ++i) {
assertTruthy(mat3.equalsApproximately(
mat3.clone(genAlmostEqualMat(-1)),
mat3.clone(genAlmostEqualMat(i + (i / 3 | 0)))),
`${i}`);
assertFalsy(mat3.equalsApproximately(
mat3.clone(genNotAlmostEqualMat(-1)),
mat3.clone(genNotAlmostEqualMat(i + (i / 3 | 0)))),
`${i}`);
}
const genNotEqualMat = i => new Array(12).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 9; ++i) {
assertTruthy(mat3.equals(
mat3.clone(genNotEqualMat(i + (i / 3 | 0))),
mat3.clone(genNotEqualMat(i + (i / 3 | 0)))),
`${i}`);
assertFalsy(mat3.equals(
mat3.clone(genNotEqualMat(-1)),
mat3.clone(genNotEqualMat(i + (i / 3 | 0)))),
`${i}`);
}
const expected = m;
testMat3WithAndWithoutDest((newDst) => {
const result = mat3.clone(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const expected = [2, 3, 4, 0, 22, 33, 44, 0, 222, 333, 444, 0];
testMat3WithAndWithoutDest((v0, v1, v2, v3, v4, v5, v6, v7, v8, newDst) => {
return mat3.set(v0, v1, v2, v3, v4, v5, v6, v7, v8, newDst);
}, expected, 2, 3, 4, 22, 33, 44, 222, 333, 444);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.identity(newDst);
}, expected);
const expected = [
0, 4, 8, 12,
1, 5, 9, 13,
2, 6, 10, 14,
3, 7, 11, 15,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.transpose(m, newDst);
}, expected);
testMultiply(mat3.multiply);
testMultiply(mat3.mul);
testInverse(mat3.inverse);
testInverse(mat3.invert);
function det(m) {
const m00 = m[0 * 4 + 0];
const m01 = m[0 * 4 + 1];
const m02 = m[0 * 4 + 2];
const m10 = m[1 * 4 + 0];
const m11 = m[1 * 4 + 1];
const m12 = m[1 * 4 + 2];
const m20 = m[2 * 4 + 0];
const m21 = m[2 * 4 + 1];
const m22 = m[2 * 4 + 2];
return m00 * (m11 * m22 - m21 * m12) -
m10 * (m01 * m22 - m21 * m02) +
m20 * (m01 * m12 - m11 * m02);
}
[
[
2, 1, 3, 0,
1, 2, 1, 0,
3, 1, 2, 0,
],
[
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
],
].forEach(v => {
const m = mat3.clone(v);
assertEqual(mat3.determinant(m), det(m));
});
const expected = [
0, 1, 2, 0,
4, 5, 6, 0,
11, 22, 1, 1,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.setTranslation(m, [11, 22], newDst);
}, expected);
const expected = [8, 9];
testV2WithAndWithoutDest((newDst) => {
return mat3.getTranslation(m, newDst);
}, expected);
[
[0, 1],
[4, 5],
].forEach((expected, ndx) => {
testV2WithAndWithoutDest((newDst) => {
return mat3.getAxis(m, ndx, newDst);
}, expected);
});
[
[
11, 22, 2, 0,
4, 5, 6, 0,
8, 9, 10, 0,
],
[
0, 1, 2, 0,
11, 22, 6, 0,
8, 9, 10, 0,
],
].forEach((expected, ndx) => {
testMat3WithAndWithoutDest((newDst) => {
return mat3.setAxis(m, [11, 22], ndx, newDst);
}, expected);
});
const m = [
2, 8, 3, 0,
5, 6, 7, 0,
9, 10, 11, 0,
];
const expected = [
Math.sqrt(2 * 2 + 8 * 8),
Math.sqrt(5 * 5 + 6 * 6),
];
testV2WithAndWithoutDest((newDst) => {
return mat3.getScaling(m, newDst);
}, expected);
const m = [
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16,
];
const expected = [
Math.sqrt(1 * 1 + 2 * 2 + 3 * 3),
Math.sqrt(5 * 5 + 6 * 6 + 7 * 7),
Math.sqrt(9 * 9 + 10 * 10 + 11 * 11),
];
testVec3WithAndWithoutDest((newDst) => {
return mat3.get3DScaling(m, newDst);
}, expected);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
2, 3, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.translation([2, 3], newDst);
}, expected);
const expected = [
0, 1, 2, 0,
4, 5, 6, 0,
8 + 0 * 2 + 4 * 3,
9 + 1 * 2 + 5 * 3,
10 + 2 * 2 + 6 * 3, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.translate(m, [2, 3], newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotation(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotation(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotate(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
1, 0, 0, 0,
0, c, s, 0,
0, -s, c, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotationX(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotationX(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotateX(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, 0, -s, 0,
0, 1, 0, 0,
s, 0, c, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotationY(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotationY(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotateY(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotationZ(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat3n.multiply(m, mat3.rotationZ(angle));
testMat3WithAndWithoutDest((newDst) => {
return mat3.rotateZ(m, angle, newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scaling([2, 3], newDst);
}, expected);
const expected = [
0, 2, 4, 0,
12, 15, 18, 0,
8, 9, 10, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scale(m, [2, 3], newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scaling3D([2, 3, 4], newDst);
}, expected);
const expected = [
0, 2, 4, 0,
12, 15, 18, 0,
32, 36, 40, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.scale3D(m, [2, 3, 4], newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 2, 0, 0,
0, 0, 1, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScaling(2, newDst);
}, expected);
const expected = [
0, 2, 4, 0,
8, 10, 12, 0,
8, 9, 10, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScale(m, 2, newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 2, 0, 0,
0, 0, 2, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScaling3D(2, newDst);
}, expected);
const expected = [
0, 2, 4, 0,
8, 10, 12, 0,
16, 18, 20, 0,
];
testMat3WithAndWithoutDest((newDst) => {
return mat3.uniformScale3D(m, 2, newDst);
}, expected);
const expected = [
1, 2, 3, 0,
5, 6, 7, 0,
9, 10, 11, 0,
];
testMat3WithAndWithoutDest((newDst) => {
const m4 = mat4.create(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);
return mat3.fromMat4(m4, newDst);
}, expected);
const tests = [
{ q: quat.fromEuler(Math.PI, 0, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationX(Math.PI)), },
{ q: quat.fromEuler(0, Math.PI, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationY(Math.PI)), },
{ q: quat.fromEuler(0, 0, Math.PI, 'xyz'), expected: mat3.fromMat4(mat4.rotationZ(Math.PI)), },
{ q: quat.fromEuler(Math.PI / 2, 0, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationX(Math.PI / 2)), },
{ q: quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), expected: mat3.fromMat4(mat4.rotationY(Math.PI / 2)), },
{ q: quat.fromEuler(0, 0, Math.PI / 2, 'xyz'), expected: mat3.fromMat4(mat4.rotationZ(Math.PI / 2)), },
];
for (const {q, expected} of tests) {
testMat3WithAndWithoutDest((newDst) => {
return mat3.fromQuat(q, newDst);
}, expected);
}
for (let i = 0; i <= 16; ++i) {
const expected = mat4.clone(new Array(16).fill(0).map((_, ndx) => ndx < i ? ndx + 1 : 0));
const args = new Array(Array.isArray(mat4.identity()) ? 16 : i).fill(0).map((_, ndx) => ndx < i ? ndx + 1 : 0);
const m = mat4.create(...args);
assertEqual(m, expected);
}
const expected = [
-0, -1, -2, -3,
-4, -5, -6, -7,
-8, -9, -10, -11,
-12, -13, -14, -15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.negate(m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
24, 26, 28, 30,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.add(m, m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
24, 26, 28, 30,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.multiplyScalar(m, 2, newDst);
}, expected);
const expected = m;
testMat4WithAndWithoutDest((newDst) => {
const result = mat4.copy(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const genAlmostEqualMat = i => new Array(16).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : utils.EPSILON * 0.5));
const genNotAlmostEqualMat = i => new Array(16).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 16; ++i) {
assertTruthy(mat4.equalsApproximately(
mat4.clone(genAlmostEqualMat(-1)),
mat4.clone(genAlmostEqualMat(i))));
assertFalsy(mat4.equalsApproximately(
mat4.clone(genNotAlmostEqualMat(-1)),
mat4.clone(genNotAlmostEqualMat(i))));
}
const genNotEqualMat = i => new Array(16).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 16; ++i) {
assertTruthy(mat4.equals(
mat4.clone(genNotEqualMat(i)),
mat4.clone(genNotEqualMat(i))));
assertFalsy(mat4.equals(
mat4.clone(genNotEqualMat(-1)),
mat4.clone(genNotEqualMat(i))));
}
const expected = m;
testMat4WithAndWithoutDest((newDst) => {
const result = mat4.clone(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const expected = [2, 3, 4, 5, 22, 33, 44, 55, 222, 333, 444, 555, 2222, 3333, 4444, 5555];
testMat4WithAndWithoutDest((v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, newDst) => {
return mat4.set(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, newDst);
}, expected, 2, 3, 4, 5, 22, 33, 44, 55, 222, 333, 444, 555, 2222, 3333, 4444, 5555);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.identity(newDst);
}, expected);
const expected = [
0, 4, 8, 12,
1, 5, 9, 13,
2, 6, 10, 14,
3, 7, 11, 15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.transpose(m, newDst);
}, expected);
testMultiply(mat4.multiply);
testMultiply(mat4.mul);
testInverse(mat4.inverse);
testInverse(mat4.invert);
function det(m) {
const m00 = m[0 * 4 + 0];
const m01 = m[0 * 4 + 1];
const m02 = m[0 * 4 + 2];
const m03 = m[0 * 4 + 3];
const m10 = m[1 * 4 + 0];
const m11 = m[1 * 4 + 1];
const m12 = m[1 * 4 + 2];
const m13 = m[1 * 4 + 3];
const m20 = m[2 * 4 + 0];
const m21 = m[2 * 4 + 1];
const m22 = m[2 * 4 + 2];
const m23 = m[2 * 4 + 3];
const m30 = m[3 * 4 + 0];
const m31 = m[3 * 4 + 1];
const m32 = m[3 * 4 + 2];
const m33 = m[3 * 4 + 3];
return m03 * m12 * m21 * m30 - m02 * m13 * m21 * m30 - m03 * m11 * m22 * m30 + m01 * m13 * m22 * m30 +
m02 * m11 * m23 * m30 - m01 * m12 * m23 * m30 - m03 * m12 * m20 * m31 + m02 * m13 * m20 * m31 +
m03 * m10 * m22 * m31 - m00 * m13 * m22 * m31 - m02 * m10 * m23 * m31 + m00 * m12 * m23 * m31 +
m03 * m11 * m20 * m32 - m01 * m13 * m20 * m32 - m03 * m10 * m21 * m32 + m00 * m13 * m21 * m32 +
m01 * m10 * m23 * m32 - m00 * m11 * m23 * m32 - m02 * m11 * m20 * m33 + m01 * m12 * m20 * m33 +
m02 * m10 * m21 * m33 - m00 * m12 * m21 * m33 - m01 * m10 * m22 * m33 + m00 * m11 * m22 * m33;
}
[
[
2, 1, 3, 0,
1, 2, 1, 0,
3, 1, 2, 0,
4, 5, 6, 1,
],
[
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
5, 6, 7, 1,
],
mat4.perspective(0.3, 2, 0.1, 100),
mat4.ortho(-10, -2, 10, 40, 0.1, 100),
].forEach(v => {
const m = mat4.clone(v);
assertEqual(mat4.determinant(m), det(m));
});
const expected = [
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
11, 22, 33, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.setTranslation(m, [11, 22, 33], newDst);
}, expected);
const expected = [12, 13, 14];
testVec3WithAndWithoutDest((newDst) => {
return mat4.getTranslation(m, newDst);
}, expected);
[
[0, 1, 2],
[4, 5, 6],
[8, 9, 10],
].forEach((expected, ndx) => {
testVec3WithAndWithoutDest((newDst) => {
return mat4.getAxis(m, ndx, newDst);
}, expected);
});
[
[
11, 22, 33, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
],
[
0, 1, 2, 3,
11, 22, 33, 7,
8, 9, 10, 11,
12, 13, 14, 15,
],
[
0, 1, 2, 3,
4, 5, 6, 7,
11, 22, 33, 11,
12, 13, 14, 15,
],
].forEach((expected, ndx) => {
testMat4WithAndWithoutDest((newDst) => {
return mat4.setAxis(m, [11, 22, 33], ndx, newDst);
}, expected);
});
const m = [
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16,
];
const expected = [
Math.sqrt(1 * 1 + 2 * 2 + 3 * 3),
Math.sqrt(5 * 5 + 6 * 6 + 7 * 7),
Math.sqrt(9 * 9 + 10 * 10 + 11 * 11),
];
testVec3WithAndWithoutDest((newDst) => {
return mat4.getScaling(m, newDst);
}, expected);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = 30;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const rangeInv = 1.0 / (zNear - zFar);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
zFar * rangeInv,
-1,
0,
0,
zNear * zFar * rangeInv,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspective(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = Infinity;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
-1,
-1,
0,
0,
-zNear,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspective(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 0.1;
const zFar = 10.0;
const m = mat4.perspective(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, 0], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, 1], 0.000001);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 10;
const zFar = Number.MAX_VALUE;
const m = mat4.perspective(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000000], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -9], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -5], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 0], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 5], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 9], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, zNear], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1000], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1000000], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1000000000], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, zFar], m), [0, 0, Infinity], 0.000001);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = 20;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const rangeInv = 1 / (zFar - zNear);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
zNear * rangeInv,
-1,
0,
0,
zFar * zNear * rangeInv,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspectiveReverseZ(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 10;
const zFar = 20;
const m = mat4.perspectiveReverseZ(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, 1], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -15], m), [0, 0, 0.3333333432674408], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, 0], 0.000001);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = Infinity;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
0,
-1,
0,
0,
zNear,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspectiveReverseZ(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 10;
const zFar = Infinity;
const m = mat4.perspectiveReverseZ(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, 1], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000], m), [0, 0, 0.009999999776482582], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000], m), [0, 0, 0.000009999999747378752], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000000], m), [0, 0, 9.99999993922529e-9], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, 0], 0.000001);
const left = 2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const expected = [
2 / (right - left),
0,
0,
0,
0,
2 / (top - bottom),
0,
0,
0,
0,
1 / (near - far),
0,
(right + left) / (left - right),
(top + bottom) / (bottom - top),
near / (near - far),
1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.ortho(left, right, bottom, top, near, far, newDst);
}, expected);
const left = -2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const m = mat4.ortho(left, right, bottom, top, near, far);
shouldBeCloseArray(vec3.transformMat4([left, bottom, -near], m), [-1, -1, 0], 0.000001);
shouldBeCloseArray(vec3.transformMat4([right, top, -far], m), [1, 1, 1], 0.000001);
const left = 2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const dx = (right - left);
const dy = (top - bottom);
const dz = (near - far);
const expected = [
2 * near / dx,
0,
0,
0,
0,
2 * near / dy,
0,
0,
(left + right) / dx,
(top + bottom) / dy,
far / dz,
-1,
0,
0,
near * far / dz,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.frustum(left, right, bottom, top, near, far, newDst);
}, expected);
const left = -2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const m = mat4.frustum(left, right, bottom, top, near, far);
shouldBeCloseArray(vec3.transformMat4([left, bottom, -near], m), [-1, -1, 0], 0.000001);
const centerX = (left + right) * 0.5;
const centerY = (top + bottom) * 0.5;
const p = vec3.transformMat4([centerX, centerY, m, -far], m);
//shouldBeCloseArray(p, [1, 1, 1], 0.000001);
assertEqualApproximately(p[2], 1);
const left = 2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const dx = (right - left);
const dy = (top - bottom);
const dz = (far - near);
const expected = [
2 * near / dx,
0,
0,
0,
0,
2 * near / dy,
0,
0,
(left + right) / dx,
(top + bottom) / dy,
near / dz,
-1,
0,
0,
near * far / dz,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.frustumReverseZ(left, right, bottom, top, near, far, newDst);
}, expected);
const left = -2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const m = mat4.frustumReverseZ(left, right, bottom, top, near, far);
shouldBeCloseArray(vec3.transformMat4([left, bottom, -near], m), [-1, -1, 1], 0.000001);
const centerX = (left + right) * 0.5;
const centerY = (top + bottom) * 0.5;
assertEqualApproximately(vec3.transformMat4([centerX, centerY, -near], m)[2], 1);
assertEqualApproximately(vec3.transformMat4([centerX, centerY, -far], m)[2], 0);
const lr = 4;
const tb = 2;
const near = 10;
const far = 20;
const m1 = mat4.frustum(-lr, lr, -tb, tb, near, far);
const fov = Math.atan(tb / near) * 2;
const aspect = lr / tb;
const m2 = mat4.perspective(fov, aspect, near, far);
shouldBeCloseArray(m1, m2);
const eye = [1, 2, 3];
const target = [11, 22, 33];
const up = [-4, -5, -6];
const expected = [
0.40824833512306213,
-0.8728715181350708,
-0.26726123690605164,
0,
-0.8164966106414795,
-0.21821792423725128,
-0.5345224738121033,
0,
0.40824824571609497,
0.4364357888698578,
-0.8017837405204773,
0,
Type === Float32Array ? 1.4901161193847656e-7 : -4.440892098500626e-16,
0,
3.74165740609169,
1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.lookAt(eye, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
2, 3, 4, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.translation([2, 3, 4], newDst);
}, expected);
const expected = [
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12 + 0 * 2 + 4 * 3 + 8 * 4,
13 + 1 * 2 + 5 * 3 + 9 * 4,
14 + 2 * 2 + 6 * 3 + 10 * 4,
15 + 3 * 2 + 7 * 3 + 11 * 4,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.translate(m, [2, 3, 4], newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
1, 0, 0, 0,
0, c, s, 0,
0, -s, c, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotationX(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.rotationX(angle, []));
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotateX(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, 0, -s, 0,
0, 1, 0, 0,
s, 0, c, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotationY(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.rotationY(angle, new Array(16)));
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotateY(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotationZ(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.rotationZ(angle, new Array(16)));
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotateZ(m, angle, newDst);
}, expected);
const axis = [0.5, 0.6, -0.7];
const angle = 1.23;
let x = axis[0];
let y = axis[1];
let z = axis[2];
const n = Math.sqrt(x * x + y * y + z * z);
x /= n;
y /= n;
z /= n;
const xx = x * x;
const yy = y * y;
const zz = z * z;
const c = Math.cos(angle);
const s = Math.sin(angle);
const oneMinusCosine = 1 - c;
const expected = [
xx + (1 - xx) * c,
x * y * oneMinusCosine + z * s,
x * z * oneMinusCosine - y * s,
0,
x * y * oneMinusCosine - z * s,
yy + (1 - yy) * c,
y * z * oneMinusCosine + x * s,
0,
x * z * oneMinusCosine + y * s,
y * z * oneMinusCosine - x * s,
zz + (1 - zz) * c,
0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.axisRotation(axis, angle, newDst);
}, expected);
const axis = [0.5, 0.6, -0.7];
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.axisRotation(axis, angle, new Array(16)));
testMat4WithAndWithoutDest((newDst) => {
return mat4.axisRotate(m, axis, angle, newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.scaling([2, 3, 4], newDst);
}, expected);
const expected = [
0, 2, 4, 6,
12, 15, 18, 21,
32, 36, 40, 44,
12, 13, 14, 15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.scale(m, [2, 3, 4], newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 2, 0, 0,
0, 0, 2, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.uniformScaling(2, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
12, 13, 14, 15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.uniformScale(m, 2, newDst);
}, expected);
const expected = [
1, 2, 3, 0,
4, 5, 6, 0,
7, 8, 9, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
const m3 = mat3.create(1, 2, 3, 4, 5, 6, 7, 8, 9);
return mat4.fromMat3(m3, newDst);
}, expected);
const tests = [
{ q: quat.fromEuler(Math.PI, 0, 0, 'xyz'), expected: mat4.rotationX(Math.PI), },
{ q: quat.fromEuler(0, Math.PI, 0, 'xyz'), expected: mat4.rotationY(Math.PI), },
{ q: quat.fromEuler(0, 0, Math.PI, 'xyz'), expected: mat4.rotationZ(Math.PI), },
{ q: quat.fromEuler(Math.PI / 2, 0, 0, 'xyz'), expected: mat4.rotationX(Math.PI / 2), },
{ q: quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), expected: mat4.rotationY(Math.PI / 2), },
{ q: quat.fromEuler(0, 0, Math.PI / 2, 'xyz'), expected: mat4.rotationZ(Math.PI / 2), },
];
for (const {q, expected} of tests) {
testMat4WithAndWithoutDest((newDst) => {
return mat4.fromQuat(q, newDst);
}, expected);
}
for (let i = 0; i <= 16; ++i) {
const expected = mat4.clone(new Array(16).fill(0).map((_, ndx) => ndx < i ? ndx + 1 : 0));
const args = new Array(Array.isArray(mat4.identity()) ? 16 : i).fill(0).map((_, ndx) => ndx < i ? ndx + 1 : 0);
const m = mat4.create(...args);
assertEqual(m, expected);
}
const expected = [
-0, -1, -2, -3,
-4, -5, -6, -7,
-8, -9, -10, -11,
-12, -13, -14, -15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.negate(m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
24, 26, 28, 30,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.add(m, m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
24, 26, 28, 30,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.multiplyScalar(m, 2, newDst);
}, expected);
const expected = m;
testMat4WithAndWithoutDest((newDst) => {
const result = mat4.copy(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const genAlmostEqualMat = i => new Array(16).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : utils.EPSILON * 0.5));
const genNotAlmostEqualMat = i => new Array(16).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 16; ++i) {
assertTruthy(mat4.equalsApproximately(
mat4.clone(genAlmostEqualMat(-1)),
mat4.clone(genAlmostEqualMat(i))));
assertFalsy(mat4.equalsApproximately(
mat4.clone(genNotAlmostEqualMat(-1)),
mat4.clone(genNotAlmostEqualMat(i))));
}
const genNotEqualMat = i => new Array(16).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 16; ++i) {
assertTruthy(mat4.equals(
mat4.clone(genNotEqualMat(i)),
mat4.clone(genNotEqualMat(i))));
assertFalsy(mat4.equals(
mat4.clone(genNotEqualMat(-1)),
mat4.clone(genNotEqualMat(i))));
}
const expected = m;
testMat4WithAndWithoutDest((newDst) => {
const result = mat4.clone(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const expected = [2, 3, 4, 5, 22, 33, 44, 55, 222, 333, 444, 555, 2222, 3333, 4444, 5555];
testMat4WithAndWithoutDest((v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, newDst) => {
return mat4.set(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, newDst);
}, expected, 2, 3, 4, 5, 22, 33, 44, 55, 222, 333, 444, 555, 2222, 3333, 4444, 5555);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.identity(newDst);
}, expected);
const expected = [
0, 4, 8, 12,
1, 5, 9, 13,
2, 6, 10, 14,
3, 7, 11, 15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.transpose(m, newDst);
}, expected);
testMultiply(mat4.multiply);
testMultiply(mat4.mul);
testInverse(mat4.inverse);
testInverse(mat4.invert);
function det(m) {
const m00 = m[0 * 4 + 0];
const m01 = m[0 * 4 + 1];
const m02 = m[0 * 4 + 2];
const m03 = m[0 * 4 + 3];
const m10 = m[1 * 4 + 0];
const m11 = m[1 * 4 + 1];
const m12 = m[1 * 4 + 2];
const m13 = m[1 * 4 + 3];
const m20 = m[2 * 4 + 0];
const m21 = m[2 * 4 + 1];
const m22 = m[2 * 4 + 2];
const m23 = m[2 * 4 + 3];
const m30 = m[3 * 4 + 0];
const m31 = m[3 * 4 + 1];
const m32 = m[3 * 4 + 2];
const m33 = m[3 * 4 + 3];
return m03 * m12 * m21 * m30 - m02 * m13 * m21 * m30 - m03 * m11 * m22 * m30 + m01 * m13 * m22 * m30 +
m02 * m11 * m23 * m30 - m01 * m12 * m23 * m30 - m03 * m12 * m20 * m31 + m02 * m13 * m20 * m31 +
m03 * m10 * m22 * m31 - m00 * m13 * m22 * m31 - m02 * m10 * m23 * m31 + m00 * m12 * m23 * m31 +
m03 * m11 * m20 * m32 - m01 * m13 * m20 * m32 - m03 * m10 * m21 * m32 + m00 * m13 * m21 * m32 +
m01 * m10 * m23 * m32 - m00 * m11 * m23 * m32 - m02 * m11 * m20 * m33 + m01 * m12 * m20 * m33 +
m02 * m10 * m21 * m33 - m00 * m12 * m21 * m33 - m01 * m10 * m22 * m33 + m00 * m11 * m22 * m33;
}
[
[
2, 1, 3, 0,
1, 2, 1, 0,
3, 1, 2, 0,
4, 5, 6, 1,
],
[
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
5, 6, 7, 1,
],
mat4.perspective(0.3, 2, 0.1, 100),
mat4.ortho(-10, -2, 10, 40, 0.1, 100),
].forEach(v => {
const m = mat4.clone(v);
assertEqual(mat4.determinant(m), det(m));
});
const expected = [
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
11, 22, 33, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.setTranslation(m, [11, 22, 33], newDst);
}, expected);
const expected = [12, 13, 14];
testVec3WithAndWithoutDest((newDst) => {
return mat4.getTranslation(m, newDst);
}, expected);
[
[0, 1, 2],
[4, 5, 6],
[8, 9, 10],
].forEach((expected, ndx) => {
testVec3WithAndWithoutDest((newDst) => {
return mat4.getAxis(m, ndx, newDst);
}, expected);
});
[
[
11, 22, 33, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
],
[
0, 1, 2, 3,
11, 22, 33, 7,
8, 9, 10, 11,
12, 13, 14, 15,
],
[
0, 1, 2, 3,
4, 5, 6, 7,
11, 22, 33, 11,
12, 13, 14, 15,
],
].forEach((expected, ndx) => {
testMat4WithAndWithoutDest((newDst) => {
return mat4.setAxis(m, [11, 22, 33], ndx, newDst);
}, expected);
});
const m = [
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16,
];
const expected = [
Math.sqrt(1 * 1 + 2 * 2 + 3 * 3),
Math.sqrt(5 * 5 + 6 * 6 + 7 * 7),
Math.sqrt(9 * 9 + 10 * 10 + 11 * 11),
];
testVec3WithAndWithoutDest((newDst) => {
return mat4.getScaling(m, newDst);
}, expected);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = 30;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const rangeInv = 1.0 / (zNear - zFar);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
zFar * rangeInv,
-1,
0,
0,
zNear * zFar * rangeInv,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspective(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = Infinity;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
-1,
-1,
0,
0,
-zNear,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspective(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 0.1;
const zFar = 10.0;
const m = mat4.perspective(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, 0], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, 1], 0.000001);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 10;
const zFar = Number.MAX_VALUE;
const m = mat4.perspective(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000000], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -9], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -5], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 0], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 5], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 9], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, zNear], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1000], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1000000], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1000000000], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, zFar], m), [0, 0, Infinity], 0.000001);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = 20;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const rangeInv = 1 / (zFar - zNear);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
zNear * rangeInv,
-1,
0,
0,
zFar * zNear * rangeInv,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspectiveReverseZ(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 10;
const zFar = 20;
const m = mat4.perspectiveReverseZ(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, 1], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -15], m), [0, 0, 0.3333333432674408], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, 0], 0.000001);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = Infinity;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
0,
-1,
0,
0,
zNear,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspectiveReverseZ(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 10;
const zFar = Infinity;
const m = mat4.perspectiveReverseZ(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, 1], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000], m), [0, 0, 0.009999999776482582], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000], m), [0, 0, 0.000009999999747378752], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000000], m), [0, 0, 9.99999993922529e-9], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, 0], 0.000001);
const left = 2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const expected = [
2 / (right - left),
0,
0,
0,
0,
2 / (top - bottom),
0,
0,
0,
0,
1 / (near - far),
0,
(right + left) / (left - right),
(top + bottom) / (bottom - top),
near / (near - far),
1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.ortho(left, right, bottom, top, near, far, newDst);
}, expected);
const left = -2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const m = mat4.ortho(left, right, bottom, top, near, far);
shouldBeCloseArray(vec3.transformMat4([left, bottom, -near], m), [-1, -1, 0], 0.000001);
shouldBeCloseArray(vec3.transformMat4([right, top, -far], m), [1, 1, 1], 0.000001);
const left = 2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const dx = (right - left);
const dy = (top - bottom);
const dz = (near - far);
const expected = [
2 * near / dx,
0,
0,
0,
0,
2 * near / dy,
0,
0,
(left + right) / dx,
(top + bottom) / dy,
far / dz,
-1,
0,
0,
near * far / dz,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.frustum(left, right, bottom, top, near, far, newDst);
}, expected);
const left = -2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const m = mat4.frustum(left, right, bottom, top, near, far);
shouldBeCloseArray(vec3.transformMat4([left, bottom, -near], m), [-1, -1, 0], 0.000001);
const centerX = (left + right) * 0.5;
const centerY = (top + bottom) * 0.5;
const p = vec3.transformMat4([centerX, centerY, m, -far], m);
//shouldBeCloseArray(p, [1, 1, 1], 0.000001);
assertEqualApproximately(p[2], 1);
const left = 2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const dx = (right - left);
const dy = (top - bottom);
const dz = (far - near);
const expected = [
2 * near / dx,
0,
0,
0,
0,
2 * near / dy,
0,
0,
(left + right) / dx,
(top + bottom) / dy,
near / dz,
-1,
0,
0,
near * far / dz,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.frustumReverseZ(left, right, bottom, top, near, far, newDst);
}, expected);
const left = -2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const m = mat4.frustumReverseZ(left, right, bottom, top, near, far);
shouldBeCloseArray(vec3.transformMat4([left, bottom, -near], m), [-1, -1, 1], 0.000001);
const centerX = (left + right) * 0.5;
const centerY = (top + bottom) * 0.5;
assertEqualApproximately(vec3.transformMat4([centerX, centerY, -near], m)[2], 1);
assertEqualApproximately(vec3.transformMat4([centerX, centerY, -far], m)[2], 0);
const lr = 4;
const tb = 2;
const near = 10;
const far = 20;
const m1 = mat4.frustum(-lr, lr, -tb, tb, near, far);
const fov = Math.atan(tb / near) * 2;
const aspect = lr / tb;
const m2 = mat4.perspective(fov, aspect, near, far);
shouldBeCloseArray(m1, m2);
const eye = [1, 2, 3];
const target = [11, 22, 33];
const up = [-4, -5, -6];
const expected = [
0.40824833512306213,
-0.8728715181350708,
-0.26726123690605164,
0,
-0.8164966106414795,
-0.21821792423725128,
-0.5345224738121033,
0,
0.40824824571609497,
0.4364357888698578,
-0.8017837405204773,
0,
Type === Float32Array ? 1.4901161193847656e-7 : -4.440892098500626e-16,
0,
3.74165740609169,
1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.lookAt(eye, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
2, 3, 4, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.translation([2, 3, 4], newDst);
}, expected);
const expected = [
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12 + 0 * 2 + 4 * 3 + 8 * 4,
13 + 1 * 2 + 5 * 3 + 9 * 4,
14 + 2 * 2 + 6 * 3 + 10 * 4,
15 + 3 * 2 + 7 * 3 + 11 * 4,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.translate(m, [2, 3, 4], newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
1, 0, 0, 0,
0, c, s, 0,
0, -s, c, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotationX(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.rotationX(angle, []));
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotateX(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, 0, -s, 0,
0, 1, 0, 0,
s, 0, c, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotationY(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.rotationY(angle, new Array(16)));
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotateY(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotationZ(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.rotationZ(angle, new Array(16)));
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotateZ(m, angle, newDst);
}, expected);
const axis = [0.5, 0.6, -0.7];
const angle = 1.23;
let x = axis[0];
let y = axis[1];
let z = axis[2];
const n = Math.sqrt(x * x + y * y + z * z);
x /= n;
y /= n;
z /= n;
const xx = x * x;
const yy = y * y;
const zz = z * z;
const c = Math.cos(angle);
const s = Math.sin(angle);
const oneMinusCosine = 1 - c;
const expected = [
xx + (1 - xx) * c,
x * y * oneMinusCosine + z * s,
x * z * oneMinusCosine - y * s,
0,
x * y * oneMinusCosine - z * s,
yy + (1 - yy) * c,
y * z * oneMinusCosine + x * s,
0,
x * z * oneMinusCosine + y * s,
y * z * oneMinusCosine - x * s,
zz + (1 - zz) * c,
0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.axisRotation(axis, angle, newDst);
}, expected);
const axis = [0.5, 0.6, -0.7];
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.axisRotation(axis, angle, new Array(16)));
testMat4WithAndWithoutDest((newDst) => {
return mat4.axisRotate(m, axis, angle, newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.scaling([2, 3, 4], newDst);
}, expected);
const expected = [
0, 2, 4, 6,
12, 15, 18, 21,
32, 36, 40, 44,
12, 13, 14, 15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.scale(m, [2, 3, 4], newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 2, 0, 0,
0, 0, 2, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.uniformScaling(2, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
12, 13, 14, 15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.uniformScale(m, 2, newDst);
}, expected);
const expected = [
1, 2, 3, 0,
4, 5, 6, 0,
7, 8, 9, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
const m3 = mat3.create(1, 2, 3, 4, 5, 6, 7, 8, 9);
return mat4.fromMat3(m3, newDst);
}, expected);
const tests = [
{ q: quat.fromEuler(Math.PI, 0, 0, 'xyz'), expected: mat4.rotationX(Math.PI), },
{ q: quat.fromEuler(0, Math.PI, 0, 'xyz'), expected: mat4.rotationY(Math.PI), },
{ q: quat.fromEuler(0, 0, Math.PI, 'xyz'), expected: mat4.rotationZ(Math.PI), },
{ q: quat.fromEuler(Math.PI / 2, 0, 0, 'xyz'), expected: mat4.rotationX(Math.PI / 2), },
{ q: quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), expected: mat4.rotationY(Math.PI / 2), },
{ q: quat.fromEuler(0, 0, Math.PI / 2, 'xyz'), expected: mat4.rotationZ(Math.PI / 2), },
];
for (const {q, expected} of tests) {
testMat4WithAndWithoutDest((newDst) => {
return mat4.fromQuat(q, newDst);
}, expected);
}
for (let i = 0; i <= 16; ++i) {
const expected = mat4.clone(new Array(16).fill(0).map((_, ndx) => ndx < i ? ndx + 1 : 0));
const args = new Array(Array.isArray(mat4.identity()) ? 16 : i).fill(0).map((_, ndx) => ndx < i ? ndx + 1 : 0);
const m = mat4.create(...args);
assertEqual(m, expected);
}
const expected = [
-0, -1, -2, -3,
-4, -5, -6, -7,
-8, -9, -10, -11,
-12, -13, -14, -15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.negate(m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
24, 26, 28, 30,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.add(m, m, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
24, 26, 28, 30,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.multiplyScalar(m, 2, newDst);
}, expected);
const expected = m;
testMat4WithAndWithoutDest((newDst) => {
const result = mat4.copy(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const genAlmostEqualMat = i => new Array(16).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : utils.EPSILON * 0.5));
const genNotAlmostEqualMat = i => new Array(16).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 16; ++i) {
assertTruthy(mat4.equalsApproximately(
mat4.clone(genAlmostEqualMat(-1)),
mat4.clone(genAlmostEqualMat(i))));
assertFalsy(mat4.equalsApproximately(
mat4.clone(genNotAlmostEqualMat(-1)),
mat4.clone(genNotAlmostEqualMat(i))));
}
const genNotEqualMat = i => new Array(16).fill(0).map((_, ndx) => ndx + (ndx === i ? 0 : 1.0001));
for (let i = 0; i < 16; ++i) {
assertTruthy(mat4.equals(
mat4.clone(genNotEqualMat(i)),
mat4.clone(genNotEqualMat(i))));
assertFalsy(mat4.equals(
mat4.clone(genNotEqualMat(-1)),
mat4.clone(genNotEqualMat(i))));
}
const expected = m;
testMat4WithAndWithoutDest((newDst) => {
const result = mat4.clone(m, newDst);
assertStrictNotEqual(result, m);
return result;
}, expected);
const expected = [2, 3, 4, 5, 22, 33, 44, 55, 222, 333, 444, 555, 2222, 3333, 4444, 5555];
testMat4WithAndWithoutDest((v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, newDst) => {
return mat4.set(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, newDst);
}, expected, 2, 3, 4, 5, 22, 33, 44, 55, 222, 333, 444, 555, 2222, 3333, 4444, 5555);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.identity(newDst);
}, expected);
const expected = [
0, 4, 8, 12,
1, 5, 9, 13,
2, 6, 10, 14,
3, 7, 11, 15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.transpose(m, newDst);
}, expected);
testMultiply(mat4.multiply);
testMultiply(mat4.mul);
testInverse(mat4.inverse);
testInverse(mat4.invert);
function det(m) {
const m00 = m[0 * 4 + 0];
const m01 = m[0 * 4 + 1];
const m02 = m[0 * 4 + 2];
const m03 = m[0 * 4 + 3];
const m10 = m[1 * 4 + 0];
const m11 = m[1 * 4 + 1];
const m12 = m[1 * 4 + 2];
const m13 = m[1 * 4 + 3];
const m20 = m[2 * 4 + 0];
const m21 = m[2 * 4 + 1];
const m22 = m[2 * 4 + 2];
const m23 = m[2 * 4 + 3];
const m30 = m[3 * 4 + 0];
const m31 = m[3 * 4 + 1];
const m32 = m[3 * 4 + 2];
const m33 = m[3 * 4 + 3];
return m03 * m12 * m21 * m30 - m02 * m13 * m21 * m30 - m03 * m11 * m22 * m30 + m01 * m13 * m22 * m30 +
m02 * m11 * m23 * m30 - m01 * m12 * m23 * m30 - m03 * m12 * m20 * m31 + m02 * m13 * m20 * m31 +
m03 * m10 * m22 * m31 - m00 * m13 * m22 * m31 - m02 * m10 * m23 * m31 + m00 * m12 * m23 * m31 +
m03 * m11 * m20 * m32 - m01 * m13 * m20 * m32 - m03 * m10 * m21 * m32 + m00 * m13 * m21 * m32 +
m01 * m10 * m23 * m32 - m00 * m11 * m23 * m32 - m02 * m11 * m20 * m33 + m01 * m12 * m20 * m33 +
m02 * m10 * m21 * m33 - m00 * m12 * m21 * m33 - m01 * m10 * m22 * m33 + m00 * m11 * m22 * m33;
}
[
[
2, 1, 3, 0,
1, 2, 1, 0,
3, 1, 2, 0,
4, 5, 6, 1,
],
[
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
5, 6, 7, 1,
],
mat4.perspective(0.3, 2, 0.1, 100),
mat4.ortho(-10, -2, 10, 40, 0.1, 100),
].forEach(v => {
const m = mat4.clone(v);
assertEqual(mat4.determinant(m), det(m));
});
const expected = [
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
11, 22, 33, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.setTranslation(m, [11, 22, 33], newDst);
}, expected);
const expected = [12, 13, 14];
testVec3WithAndWithoutDest((newDst) => {
return mat4.getTranslation(m, newDst);
}, expected);
[
[0, 1, 2],
[4, 5, 6],
[8, 9, 10],
].forEach((expected, ndx) => {
testVec3WithAndWithoutDest((newDst) => {
return mat4.getAxis(m, ndx, newDst);
}, expected);
});
[
[
11, 22, 33, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
],
[
0, 1, 2, 3,
11, 22, 33, 7,
8, 9, 10, 11,
12, 13, 14, 15,
],
[
0, 1, 2, 3,
4, 5, 6, 7,
11, 22, 33, 11,
12, 13, 14, 15,
],
].forEach((expected, ndx) => {
testMat4WithAndWithoutDest((newDst) => {
return mat4.setAxis(m, [11, 22, 33], ndx, newDst);
}, expected);
});
const m = [
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16,
];
const expected = [
Math.sqrt(1 * 1 + 2 * 2 + 3 * 3),
Math.sqrt(5 * 5 + 6 * 6 + 7 * 7),
Math.sqrt(9 * 9 + 10 * 10 + 11 * 11),
];
testVec3WithAndWithoutDest((newDst) => {
return mat4.getScaling(m, newDst);
}, expected);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = 30;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const rangeInv = 1.0 / (zNear - zFar);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
zFar * rangeInv,
-1,
0,
0,
zNear * zFar * rangeInv,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspective(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = Infinity;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
-1,
-1,
0,
0,
-zNear,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspective(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 0.1;
const zFar = 10.0;
const m = mat4.perspective(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, 0], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, 1], 0.000001);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 10;
const zFar = Number.MAX_VALUE;
const m = mat4.perspective(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000000], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -9], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -5], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 0], m), [0, 0, -Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 5], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 9], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, zNear], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1000], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1000000], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, 1000000000], m), [0, 0, Infinity], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, zFar], m), [0, 0, Infinity], 0.000001);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = 20;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const rangeInv = 1 / (zFar - zNear);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
zNear * rangeInv,
-1,
0,
0,
zFar * zNear * rangeInv,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspectiveReverseZ(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 10;
const zFar = 20;
const m = mat4.perspectiveReverseZ(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, 1], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -15], m), [0, 0, 0.3333333432674408], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, 0], 0.000001);
const fov = 2;
const aspect = 4;
const zNear = 10;
const zFar = Infinity;
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const expected = [
f / aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
0,
-1,
0,
0,
zNear,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.perspectiveReverseZ(fov, aspect, zNear, zFar, newDst);
}, expected);
const fov = Math.PI / 4;
const aspect = 2;
const zNear = 10;
const zFar = Infinity;
const m = mat4.perspectiveReverseZ(fov, aspect, zNear, zFar);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zNear], m), [0, 0, 1], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000], m), [0, 0, 0.009999999776482582], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000], m), [0, 0, 0.000009999999747378752], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -1000000000], m), [0, 0, 9.99999993922529e-9], 0.000001);
shouldBeCloseArray(vec3.transformMat4([0, 0, -zFar], m), [0, 0, 0], 0.000001);
const left = 2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const expected = [
2 / (right - left),
0,
0,
0,
0,
2 / (top - bottom),
0,
0,
0,
0,
1 / (near - far),
0,
(right + left) / (left - right),
(top + bottom) / (bottom - top),
near / (near - far),
1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.ortho(left, right, bottom, top, near, far, newDst);
}, expected);
const left = -2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const m = mat4.ortho(left, right, bottom, top, near, far);
shouldBeCloseArray(vec3.transformMat4([left, bottom, -near], m), [-1, -1, 0], 0.000001);
shouldBeCloseArray(vec3.transformMat4([right, top, -far], m), [1, 1, 1], 0.000001);
const left = 2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const dx = (right - left);
const dy = (top - bottom);
const dz = (near - far);
const expected = [
2 * near / dx,
0,
0,
0,
0,
2 * near / dy,
0,
0,
(left + right) / dx,
(top + bottom) / dy,
far / dz,
-1,
0,
0,
near * far / dz,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.frustum(left, right, bottom, top, near, far, newDst);
}, expected);
const left = -2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const m = mat4.frustum(left, right, bottom, top, near, far);
shouldBeCloseArray(vec3.transformMat4([left, bottom, -near], m), [-1, -1, 0], 0.000001);
const centerX = (left + right) * 0.5;
const centerY = (top + bottom) * 0.5;
const p = vec3.transformMat4([centerX, centerY, m, -far], m);
//shouldBeCloseArray(p, [1, 1, 1], 0.000001);
assertEqualApproximately(p[2], 1);
const left = 2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const dx = (right - left);
const dy = (top - bottom);
const dz = (far - near);
const expected = [
2 * near / dx,
0,
0,
0,
0,
2 * near / dy,
0,
0,
(left + right) / dx,
(top + bottom) / dy,
near / dz,
-1,
0,
0,
near * far / dz,
0,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.frustumReverseZ(left, right, bottom, top, near, far, newDst);
}, expected);
const left = -2;
const right = 4;
const top = 10;
const bottom = 30;
const near = 15;
const far = 25;
const m = mat4.frustumReverseZ(left, right, bottom, top, near, far);
shouldBeCloseArray(vec3.transformMat4([left, bottom, -near], m), [-1, -1, 1], 0.000001);
const centerX = (left + right) * 0.5;
const centerY = (top + bottom) * 0.5;
assertEqualApproximately(vec3.transformMat4([centerX, centerY, -near], m)[2], 1);
assertEqualApproximately(vec3.transformMat4([centerX, centerY, -far], m)[2], 0);
const lr = 4;
const tb = 2;
const near = 10;
const far = 20;
const m1 = mat4.frustum(-lr, lr, -tb, tb, near, far);
const fov = Math.atan(tb / near) * 2;
const aspect = lr / tb;
const m2 = mat4.perspective(fov, aspect, near, far);
shouldBeCloseArray(m1, m2);
const eye = [1, 2, 3];
const target = [11, 22, 33];
const up = [-4, -5, -6];
const expected = [
0.40824833512306213,
-0.8728715181350708,
-0.26726123690605164,
0,
-0.8164966106414795,
-0.21821792423725128,
-0.5345224738121033,
0,
0.40824824571609497,
0.4364357888698578,
-0.8017837405204773,
0,
Type === Float32Array ? 1.4901161193847656e-7 : -4.440892098500626e-16,
0,
3.74165740609169,
1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.lookAt(eye, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.aim(position, target, up, newDst);
}, expected);
testMat4WithAndWithoutDest((newDst) => {
return mat4.cameraAim(position, target, up, newDst);
}, camExpected);
const expected = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
2, 3, 4, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.translation([2, 3, 4], newDst);
}, expected);
const expected = [
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12 + 0 * 2 + 4 * 3 + 8 * 4,
13 + 1 * 2 + 5 * 3 + 9 * 4,
14 + 2 * 2 + 6 * 3 + 10 * 4,
15 + 3 * 2 + 7 * 3 + 11 * 4,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.translate(m, [2, 3, 4], newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
1, 0, 0, 0,
0, c, s, 0,
0, -s, c, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotationX(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.rotationX(angle, []));
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotateX(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, 0, -s, 0,
0, 1, 0, 0,
s, 0, c, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotationY(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.rotationY(angle, new Array(16)));
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotateY(m, angle, newDst);
}, expected);
const angle = 1.23;
const c = Math.cos(angle);
const s = Math.sin(angle);
const expected = [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotationZ(angle, newDst);
}, expected);
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.rotationZ(angle, new Array(16)));
testMat4WithAndWithoutDest((newDst) => {
return mat4.rotateZ(m, angle, newDst);
}, expected);
const axis = [0.5, 0.6, -0.7];
const angle = 1.23;
let x = axis[0];
let y = axis[1];
let z = axis[2];
const n = Math.sqrt(x * x + y * y + z * z);
x /= n;
y /= n;
z /= n;
const xx = x * x;
const yy = y * y;
const zz = z * z;
const c = Math.cos(angle);
const s = Math.sin(angle);
const oneMinusCosine = 1 - c;
const expected = [
xx + (1 - xx) * c,
x * y * oneMinusCosine + z * s,
x * z * oneMinusCosine - y * s,
0,
x * y * oneMinusCosine - z * s,
yy + (1 - yy) * c,
y * z * oneMinusCosine + x * s,
0,
x * z * oneMinusCosine + y * s,
y * z * oneMinusCosine - x * s,
zz + (1 - zz) * c,
0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.axisRotation(axis, angle, newDst);
}, expected);
const axis = [0.5, 0.6, -0.7];
const angle = 1.23;
// switch to Array type to keep precision high for expected
const expected = mat4.multiply(m, mat4.axisRotation(axis, angle, new Array(16)));
testMat4WithAndWithoutDest((newDst) => {
return mat4.axisRotate(m, axis, angle, newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 3, 0, 0,
0, 0, 4, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.scaling([2, 3, 4], newDst);
}, expected);
const expected = [
0, 2, 4, 6,
12, 15, 18, 21,
32, 36, 40, 44,
12, 13, 14, 15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.scale(m, [2, 3, 4], newDst);
}, expected);
const expected = [
2, 0, 0, 0,
0, 2, 0, 0,
0, 0, 2, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.uniformScaling(2, newDst);
}, expected);
const expected = [
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
12, 13, 14, 15,
];
testMat4WithAndWithoutDest((newDst) => {
return mat4.uniformScale(m, 2, newDst);
}, expected);
const expected = [
1, 2, 3, 0,
4, 5, 6, 0,
7, 8, 9, 0,
0, 0, 0, 1,
];
testMat4WithAndWithoutDest((newDst) => {
const m3 = mat3.create(1, 2, 3, 4, 5, 6, 7, 8, 9);
return mat4.fromMat3(m3, newDst);
}, expected);
const tests = [
{ q: quat.fromEuler(Math.PI, 0, 0, 'xyz'), expected: mat4.rotationX(Math.PI), },
{ q: quat.fromEuler(0, Math.PI, 0, 'xyz'), expected: mat4.rotationY(Math.PI), },
{ q: quat.fromEuler(0, 0, Math.PI, 'xyz'), expected: mat4.rotationZ(Math.PI), },
{ q: quat.fromEuler(Math.PI / 2, 0, 0, 'xyz'), expected: mat4.rotationX(Math.PI / 2), },
{ q: quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), expected: mat4.rotationY(Math.PI / 2), },
{ q: quat.fromEuler(0, 0, Math.PI / 2, 'xyz'), expected: mat4.rotationZ(Math.PI / 2), },
];
for (const {q, expected} of tests) {
testMat4WithAndWithoutDest((newDst) => {
return mat4.fromQuat(q, newDst);
}, expected);
}
const expected = [3, 5, 7, 9];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.add(a, b, dst);
}, expected, [1, 2, 3, 4], [2, 3, 4, 5]);
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1 + utils.EPSILON * 0.5, 2, 3, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2 + utils.EPSILON * 0.5, 3, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3 + utils.EPSILON * 0.5, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4 + utils.EPSILON * 0.5)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1.0001, 2, 3, 4)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2.0001, 3, 4)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3.0001, 4)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4.0001)));
assertTruthy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1 + utils.EPSILON * 0.5, 2, 3, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2 + utils.EPSILON * 0.5, 3, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2, 3 + utils.EPSILON * 0.5, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4 + utils.EPSILON * 0.5)));
const expected = [-1, -2, -3, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.subtract(a, b, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [-1, -2, -3, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.sub(a, b, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [1.5, 3, 4.5, 6];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.lerp(a, b, 0.5, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [0.5, 1, 1.5, 2];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.lerp(a, b, -0.5, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [2.5, 5, 7.5, 10];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.lerp(a, b, 1.5, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [2, 4, 6, 8];
testQuatWithAndWithoutDest((a, dst) => {
return quat.mulScalar(a, 2, dst);
}, expected, [1, 2, 3, 4]);
const expected = [2, 4, 6, 8];
testQuatWithAndWithoutDest((a, dst) => {
return quat.scale(a, 2, dst);
}, expected, [1, 2, 3, 4]);
const expected = [0.5, 1, 1.5, 2];
testQuatWithAndWithoutDest((a, dst) => {
return quat.divScalar(a, 2, dst);
}, expected, [1, 2, 3, 4]);
const expected = [
-0.021505376344086023,
-0.03225806451612903,
0.043010752688172046,
-0.08602150537634409,
];
testQuatWithAndWithoutDest((a, dst) => {
return quat.inverse(a, dst);
}, expected, [2, 3, -4, -8]);
const expected = 1 * 2 + 2 * 4 + 3 * 6 + 4 * 8;
const value = quat.dot(quat.create(1, 2, 3, 4), quat.create(2, 4, 6, 8));
assertStrictEqual(value, expected);
const expected = Math.sqrt(1 * 1 + 2 * 2 + 3 * 3 + 4 * 4);
const value = quat.length(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const expected = 1 * 1 + 2 * 2 + 3 * 3 + 4 * 4;
const value = quat.lengthSq(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const expected = Math.sqrt(1 * 1 + 2 * 2 + 3 * 3 + 4 * 4);
const value = quat.len(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const expected = 1 * 1 + 2 * 2 + 3 * 3 + 4 * 4;
const value = quat.lenSq(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const length = Math.sqrt(1 * 1 + 2 * 2 + 3 * 3 + 4 * 4);
const expected = [
1 / length,
2 / length,
3 / length,
4 / length,
];
testQuatWithAndWithoutDest((a, dst) => {
return quat.normalize(a, dst);
}, expected, [1, 2, 3, 4]);
const expected = [1, 2, 3, 4];
const v = quat.create(1, 2, 3, 4);
testQuatWithAndWithoutDest((a, dst) => {
const result = quat.copy(a, dst);
assertStrictNotEqual(result, v);
return result;
}, expected, [1, 2, 3, 4]);
const expected = [1, 2, 3, 4];
const v = quat.create(1, 2, 3, 4);
testQuatWithAndWithoutDest((a, dst) => {
const result = quat.clone(a, dst);
assertStrictNotEqual(result, v);
return result;
}, expected, [1, 2, 3, 4]);
const expected = [2, 3, 4, 5];
testQuatWithAndWithoutDest((a, b, c, d, dst) => {
return quat.set(a, b, c, d, dst);
}, expected, 2, 3, 4, 5);
const expected = [-16, -32, -48, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.multiply(a, b, dst);
}, expected, [1, 2, 3, 4], [-2, -4, -6, -8]);
const expected = [-16, -32, -48, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.mul(a, b, dst);
}, expected, [1, 2, 3, 4], [-2, -4, -6, -8]);
const expected = quat.create(1, 2, 3, 4);
const v1 = quat.fromValues(1, 2, 3, 4);
assertEqual(v1, expected);
const axis = [1, 0, 0]; //vec3.normalize([1, 2, 3]);
const angle = 0; //45 * Math.PI / 180;
const expected = [0, 0, 0, 1];
testQuatWithAndWithoutDest((axis, angle, dst) => {
return quat.fromAxisAngle(axis, angle, dst);
}, expected, axis, angle);
const tests = [
{ axis: [1, 0, 0], angle: 0.1 },
{ axis: [0, 1, 0], angle: 0.1 },
{ axis: [0, 0, 1], angle: 0.1 },
{ axis: vec3.normalize([1, 2, 3]), angle: 0.1 },
];
for (const expected of tests) {
const { axis, angle } = expected;
const q = quat.fromAxisAngle(axis, angle);
const actual = quat.toAxisAngle(q);
assertDeepEqualApproximately(actual, expected, 1e6);
}
const tests = [
{ axis: [1, 0, 0], },
{ axis: [0, 1, 0], },
{ axis: [0, 0, 1], },
{ axis: vec3.normalize([1, 2, 3]) },
];
for (const {axis} of tests) {
const q1 = quat.fromAxisAngle(axis, 0.1);
const q2 = quat.fromAxisAngle(axis, 0.4);
const actual = quat.angle(q1, q2);
assertDeepEqualApproximately(actual, 0.3);
}
const tests = [
{ angle: 0, expected: [1, 2, 3, 4], },
{ angle: Math.PI, expected: [4, 3, -2, -1], },
{ angle: -Math.PI, expected: [-4, -3, 2, 1], },
];
for (const {angle, expected} of tests) {
testQuatWithAndWithoutDest((a, dst) => {
return quat.rotateX([1, 2, 3, 4], a, dst);
}, expected, angle);
}
const tests = [
{ angle: 0, expected: [1, 2, 3, 4], },
{ angle: Math.PI, expected: [-3, 4, 1, -2], },
{ angle: -Math.PI, expected: [3, -4, -1, 2], },
];
for (const {angle, expected} of tests) {
testQuatWithAndWithoutDest((a, dst) => {
return quat.rotateY([1, 2, 3, 4], a, dst);
}, expected, angle);
}
const tests = [
{ angle: 0, expected: [1, 2, 3, 4], },
{ angle: Math.PI, expected: [-3, 4, 1, -2], },
{ angle: -Math.PI, expected: [3, -4, -1, 2], },
];
for (const {angle, expected} of tests) {
testQuatWithAndWithoutDest((a, dst) => {
return quat.rotateY([1, 2, 3, 4], a, dst);
}, expected, angle);
}
const a1 = [0, 1, 0, 1];
const b1 = [1, 0, 0, 1];
const a2 = [0, 1, 0, 1];
const b2 = [0, 1, 0, 0.5];
const a3 = quat.fromEuler(0.1, 0.2, 0.3, 'xyz');
const b3 = quat.fromEuler(0.3, 0.2, 0.1, 'xyz');
const tests = [
{ a: a1, b: b1, t: 0, expected: [0, 1, 0, 1], },
{ a: a1, b: b1, t: 1, expected: [1, 0, 0, 1], },
{ a: a1, b: b1, t: 0.5, expected: [0.5, 0.5, 0, 1], },
{ a: a2, b: b2, t: 0.5, expected: [0, 1, 0, 0.75], },
{ a: a3, b: b3, t: 0.5, expected: [0.1089731245591333, 0.09134010671547867, 0.10897312455913327, 0.9838224947381737], },
];
for (const {a, b, t, expected} of tests) {
testQuatWithAndWithoutDest((a, b, t, dst) => {
return quat.slerp(a, b, t, dst);
}, expected, a, b, t);
}
const expected = [-2, -3, -4, 5];
testQuatWithAndWithoutDest((q, dst) => {
return quat.conjugate(q, dst);
}, expected, [2, 3, 4, 5]);
const tests = [
{ expected: [0, 0, 0, 1], mat: mat4.identity(), },
{ expected: [1, 0, 0, 0], mat: mat4.rotationX(Math.PI), },
{ expected: [0, 1, 0, 0], mat: mat4.rotationY(Math.PI), },
{ expected: [0, 0, 1, 0], mat: mat4.rotationZ(Math.PI), },
].map(({expected, mat}) => [
{ expected, mat },
{ expected, mat: mat3.fromMat4(mat), },
]).flat();
for (const {mat, expected} of tests) {
testQuatWithAndWithoutDest((mat, dst) => {
return quat.fromMat(mat, dst);
}, expected, mat);
}
const tests = [
{ args: [0, 0, 0, 'xyz'], expected: [0, 0, 0, 1], },
{ args: [Math.PI, 0, 0, 'xyz'], expected: [1, 0, 0, 0], },
{ args: [0, Math.PI, 0, 'xyz'], expected: [0, 1, 0, 0], },
{ args: [0, 0, Math.PI, 'xyz'], expected: [0, 0, 1, 0], },
{ args: [Math.PI, Math.PI, 0, 'xyz'], expected: [0, 0, 1, 0], },
{ args: [Math.PI, Math.PI, 0, 'yxz'], expected: [0, 0, -1, 0], },
{ args: [0, Math.PI, Math.PI, 'xyz'], expected: [1, 0, 0, 0], },
{ args: [0, Math.PI, Math.PI, 'xzy'], expected: [-1, 0, 0, 0], },
{ args: [Math.PI, 0, Math.PI, 'xyz'], expected: [0, -1, 0, 0], },
{ args: [Math.PI, 0, Math.PI, 'zyx'], expected: [0, 1, 0, 0], },
{ args: [Math.PI, 0, Math.PI, 'zxy'], expected: [0, 1, 0, 0], },
{ args: [0.1, Math.PI, 0, 'zyx'], expected: [0, 0.9987502694129944, -0.04997916892170906, 0 ]},
];
for (const {args, expected} of tests) {
testQuatWithAndWithoutDest((...args) => {
return quat.fromEuler(...args);
}, expected, ...args);
}
const tests = [
{ args: [quat.fromEuler(Math.PI / 2, 0, 0, 'xyz'), quat.fromEuler(0, Math.PI, 0, 'xyz')], expected: [0, 0, 0.5773502588272095, 0.8164966106414795], },
{ args: [quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), quat.fromEuler(0, Math.PI, 0, 'xyz')], expected: [0, 0, 0, 1], },
{ args: [quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), quat.fromEuler(0, 0, Math.PI, 'xyz')], expected: [0.5773502588272095, 0, 0, 0.8164966106414795], },
{ args: [quat.fromEuler(0, 0, Math.PI / 2, 'zyx'), quat.fromEuler(0.1, Math.PI, 0, 'zyx')], expected: [-0.5907140970230103, 0, 0, 0.8068809509277344], },
];
for (const {args, expected} of tests) {
testQuatWithAndWithoutDest((...args) => {
return quat.rotationTo(...args);
}, expected, ...args);
}
const a = quat.fromEuler(Math.PI / 2, 0, 0, 'xyz');
const b = quat.fromEuler(0, Math.PI / 2, 0, 'xyz');
const c = quat.fromEuler(0, 0, Math.PI / 2, 'xyz');
const d = quat.fromEuler(Math.PI, 0, 0, 'xyz');
const tests = [
{ args: [a, b, c, d, 0], expected: a },
{ args: [a, b, c, d, 1], expected: d },
{ args: [a, b, c, d, 0.25], expected: [0.5946745811867614, 0.2612930755130939, 0.095639903470758, 0.7542818306464518] },
{ args: [a, b, c, d, 0.5], expected: [0.5702395788501929, 0.25198018251105747, 0.25198018251105747, 0.7401613323837869] },
{ args: [a, b, c, d, 0.75], expected: [0.7683175218769692, 0.10832581796559188, 0.29595163845345446, 0.5571053135948666] },
];
for (const {args, expected} of tests) {
testQuatWithAndWithoutDest((...args) => {
return quat.sqlerp(...args);
}, expected, ...args);
}
const expected = [3, 5, 7, 9];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.add(a, b, dst);
}, expected, [1, 2, 3, 4], [2, 3, 4, 5]);
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1 + utils.EPSILON * 0.5, 2, 3, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2 + utils.EPSILON * 0.5, 3, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3 + utils.EPSILON * 0.5, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4 + utils.EPSILON * 0.5)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1.0001, 2, 3, 4)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2.0001, 3, 4)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3.0001, 4)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4.0001)));
assertTruthy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1 + utils.EPSILON * 0.5, 2, 3, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2 + utils.EPSILON * 0.5, 3, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2, 3 + utils.EPSILON * 0.5, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4 + utils.EPSILON * 0.5)));
const expected = [-1, -2, -3, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.subtract(a, b, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [-1, -2, -3, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.sub(a, b, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [1.5, 3, 4.5, 6];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.lerp(a, b, 0.5, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [0.5, 1, 1.5, 2];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.lerp(a, b, -0.5, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [2.5, 5, 7.5, 10];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.lerp(a, b, 1.5, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [2, 4, 6, 8];
testQuatWithAndWithoutDest((a, dst) => {
return quat.mulScalar(a, 2, dst);
}, expected, [1, 2, 3, 4]);
const expected = [2, 4, 6, 8];
testQuatWithAndWithoutDest((a, dst) => {
return quat.scale(a, 2, dst);
}, expected, [1, 2, 3, 4]);
const expected = [0.5, 1, 1.5, 2];
testQuatWithAndWithoutDest((a, dst) => {
return quat.divScalar(a, 2, dst);
}, expected, [1, 2, 3, 4]);
const expected = [
-0.021505376344086023,
-0.03225806451612903,
0.043010752688172046,
-0.08602150537634409,
];
testQuatWithAndWithoutDest((a, dst) => {
return quat.inverse(a, dst);
}, expected, [2, 3, -4, -8]);
const expected = 1 * 2 + 2 * 4 + 3 * 6 + 4 * 8;
const value = quat.dot(quat.create(1, 2, 3, 4), quat.create(2, 4, 6, 8));
assertStrictEqual(value, expected);
const expected = Math.sqrt(1 * 1 + 2 * 2 + 3 * 3 + 4 * 4);
const value = quat.length(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const expected = 1 * 1 + 2 * 2 + 3 * 3 + 4 * 4;
const value = quat.lengthSq(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const expected = Math.sqrt(1 * 1 + 2 * 2 + 3 * 3 + 4 * 4);
const value = quat.len(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const expected = 1 * 1 + 2 * 2 + 3 * 3 + 4 * 4;
const value = quat.lenSq(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const length = Math.sqrt(1 * 1 + 2 * 2 + 3 * 3 + 4 * 4);
const expected = [
1 / length,
2 / length,
3 / length,
4 / length,
];
testQuatWithAndWithoutDest((a, dst) => {
return quat.normalize(a, dst);
}, expected, [1, 2, 3, 4]);
const expected = [1, 2, 3, 4];
const v = quat.create(1, 2, 3, 4);
testQuatWithAndWithoutDest((a, dst) => {
const result = quat.copy(a, dst);
assertStrictNotEqual(result, v);
return result;
}, expected, [1, 2, 3, 4]);
const expected = [1, 2, 3, 4];
const v = quat.create(1, 2, 3, 4);
testQuatWithAndWithoutDest((a, dst) => {
const result = quat.clone(a, dst);
assertStrictNotEqual(result, v);
return result;
}, expected, [1, 2, 3, 4]);
const expected = [2, 3, 4, 5];
testQuatWithAndWithoutDest((a, b, c, d, dst) => {
return quat.set(a, b, c, d, dst);
}, expected, 2, 3, 4, 5);
const expected = [-16, -32, -48, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.multiply(a, b, dst);
}, expected, [1, 2, 3, 4], [-2, -4, -6, -8]);
const expected = [-16, -32, -48, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.mul(a, b, dst);
}, expected, [1, 2, 3, 4], [-2, -4, -6, -8]);
const expected = quat.create(1, 2, 3, 4);
const v1 = quat.fromValues(1, 2, 3, 4);
assertEqual(v1, expected);
const axis = [1, 0, 0]; //vec3.normalize([1, 2, 3]);
const angle = 0; //45 * Math.PI / 180;
const expected = [0, 0, 0, 1];
testQuatWithAndWithoutDest((axis, angle, dst) => {
return quat.fromAxisAngle(axis, angle, dst);
}, expected, axis, angle);
const tests = [
{ axis: [1, 0, 0], angle: 0.1 },
{ axis: [0, 1, 0], angle: 0.1 },
{ axis: [0, 0, 1], angle: 0.1 },
{ axis: vec3.normalize([1, 2, 3]), angle: 0.1 },
];
for (const expected of tests) {
const { axis, angle } = expected;
const q = quat.fromAxisAngle(axis, angle);
const actual = quat.toAxisAngle(q);
assertDeepEqualApproximately(actual, expected, 1e6);
}
const tests = [
{ axis: [1, 0, 0], },
{ axis: [0, 1, 0], },
{ axis: [0, 0, 1], },
{ axis: vec3.normalize([1, 2, 3]) },
];
for (const {axis} of tests) {
const q1 = quat.fromAxisAngle(axis, 0.1);
const q2 = quat.fromAxisAngle(axis, 0.4);
const actual = quat.angle(q1, q2);
assertDeepEqualApproximately(actual, 0.3);
}
const tests = [
{ angle: 0, expected: [1, 2, 3, 4], },
{ angle: Math.PI, expected: [4, 3, -2, -1], },
{ angle: -Math.PI, expected: [-4, -3, 2, 1], },
];
for (const {angle, expected} of tests) {
testQuatWithAndWithoutDest((a, dst) => {
return quat.rotateX([1, 2, 3, 4], a, dst);
}, expected, angle);
}
const tests = [
{ angle: 0, expected: [1, 2, 3, 4], },
{ angle: Math.PI, expected: [-3, 4, 1, -2], },
{ angle: -Math.PI, expected: [3, -4, -1, 2], },
];
for (const {angle, expected} of tests) {
testQuatWithAndWithoutDest((a, dst) => {
return quat.rotateY([1, 2, 3, 4], a, dst);
}, expected, angle);
}
const tests = [
{ angle: 0, expected: [1, 2, 3, 4], },
{ angle: Math.PI, expected: [-3, 4, 1, -2], },
{ angle: -Math.PI, expected: [3, -4, -1, 2], },
];
for (const {angle, expected} of tests) {
testQuatWithAndWithoutDest((a, dst) => {
return quat.rotateY([1, 2, 3, 4], a, dst);
}, expected, angle);
}
const a1 = [0, 1, 0, 1];
const b1 = [1, 0, 0, 1];
const a2 = [0, 1, 0, 1];
const b2 = [0, 1, 0, 0.5];
const a3 = quat.fromEuler(0.1, 0.2, 0.3, 'xyz');
const b3 = quat.fromEuler(0.3, 0.2, 0.1, 'xyz');
const tests = [
{ a: a1, b: b1, t: 0, expected: [0, 1, 0, 1], },
{ a: a1, b: b1, t: 1, expected: [1, 0, 0, 1], },
{ a: a1, b: b1, t: 0.5, expected: [0.5, 0.5, 0, 1], },
{ a: a2, b: b2, t: 0.5, expected: [0, 1, 0, 0.75], },
{ a: a3, b: b3, t: 0.5, expected: [0.1089731245591333, 0.09134010671547867, 0.10897312455913327, 0.9838224947381737], },
];
for (const {a, b, t, expected} of tests) {
testQuatWithAndWithoutDest((a, b, t, dst) => {
return quat.slerp(a, b, t, dst);
}, expected, a, b, t);
}
const expected = [-2, -3, -4, 5];
testQuatWithAndWithoutDest((q, dst) => {
return quat.conjugate(q, dst);
}, expected, [2, 3, 4, 5]);
const tests = [
{ expected: [0, 0, 0, 1], mat: mat4.identity(), },
{ expected: [1, 0, 0, 0], mat: mat4.rotationX(Math.PI), },
{ expected: [0, 1, 0, 0], mat: mat4.rotationY(Math.PI), },
{ expected: [0, 0, 1, 0], mat: mat4.rotationZ(Math.PI), },
].map(({expected, mat}) => [
{ expected, mat },
{ expected, mat: mat3.fromMat4(mat), },
]).flat();
for (const {mat, expected} of tests) {
testQuatWithAndWithoutDest((mat, dst) => {
return quat.fromMat(mat, dst);
}, expected, mat);
}
const tests = [
{ args: [0, 0, 0, 'xyz'], expected: [0, 0, 0, 1], },
{ args: [Math.PI, 0, 0, 'xyz'], expected: [1, 0, 0, 0], },
{ args: [0, Math.PI, 0, 'xyz'], expected: [0, 1, 0, 0], },
{ args: [0, 0, Math.PI, 'xyz'], expected: [0, 0, 1, 0], },
{ args: [Math.PI, Math.PI, 0, 'xyz'], expected: [0, 0, 1, 0], },
{ args: [Math.PI, Math.PI, 0, 'yxz'], expected: [0, 0, -1, 0], },
{ args: [0, Math.PI, Math.PI, 'xyz'], expected: [1, 0, 0, 0], },
{ args: [0, Math.PI, Math.PI, 'xzy'], expected: [-1, 0, 0, 0], },
{ args: [Math.PI, 0, Math.PI, 'xyz'], expected: [0, -1, 0, 0], },
{ args: [Math.PI, 0, Math.PI, 'zyx'], expected: [0, 1, 0, 0], },
{ args: [Math.PI, 0, Math.PI, 'zxy'], expected: [0, 1, 0, 0], },
{ args: [0.1, Math.PI, 0, 'zyx'], expected: [0, 0.9987502694129944, -0.04997916892170906, 0 ]},
];
for (const {args, expected} of tests) {
testQuatWithAndWithoutDest((...args) => {
return quat.fromEuler(...args);
}, expected, ...args);
}
const tests = [
{ args: [quat.fromEuler(Math.PI / 2, 0, 0, 'xyz'), quat.fromEuler(0, Math.PI, 0, 'xyz')], expected: [0, 0, 0.5773502588272095, 0.8164966106414795], },
{ args: [quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), quat.fromEuler(0, Math.PI, 0, 'xyz')], expected: [0, 0, 0, 1], },
{ args: [quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), quat.fromEuler(0, 0, Math.PI, 'xyz')], expected: [0.5773502588272095, 0, 0, 0.8164966106414795], },
{ args: [quat.fromEuler(0, 0, Math.PI / 2, 'zyx'), quat.fromEuler(0.1, Math.PI, 0, 'zyx')], expected: [-0.5907140970230103, 0, 0, 0.8068809509277344], },
];
for (const {args, expected} of tests) {
testQuatWithAndWithoutDest((...args) => {
return quat.rotationTo(...args);
}, expected, ...args);
}
const a = quat.fromEuler(Math.PI / 2, 0, 0, 'xyz');
const b = quat.fromEuler(0, Math.PI / 2, 0, 'xyz');
const c = quat.fromEuler(0, 0, Math.PI / 2, 'xyz');
const d = quat.fromEuler(Math.PI, 0, 0, 'xyz');
const tests = [
{ args: [a, b, c, d, 0], expected: a },
{ args: [a, b, c, d, 1], expected: d },
{ args: [a, b, c, d, 0.25], expected: [0.5946745811867614, 0.2612930755130939, 0.095639903470758, 0.7542818306464518] },
{ args: [a, b, c, d, 0.5], expected: [0.5702395788501929, 0.25198018251105747, 0.25198018251105747, 0.7401613323837869] },
{ args: [a, b, c, d, 0.75], expected: [0.7683175218769692, 0.10832581796559188, 0.29595163845345446, 0.5571053135948666] },
];
for (const {args, expected} of tests) {
testQuatWithAndWithoutDest((...args) => {
return quat.sqlerp(...args);
}, expected, ...args);
}
const expected = [3, 5, 7, 9];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.add(a, b, dst);
}, expected, [1, 2, 3, 4], [2, 3, 4, 5]);
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1 + utils.EPSILON * 0.5, 2, 3, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2 + utils.EPSILON * 0.5, 3, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3 + utils.EPSILON * 0.5, 4)));
assertTruthy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4 + utils.EPSILON * 0.5)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1.0001, 2, 3, 4)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2.0001, 3, 4)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3.0001, 4)));
assertFalsy(quat.equalsApproximately(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4.0001)));
assertTruthy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1 + utils.EPSILON * 0.5, 2, 3, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2 + utils.EPSILON * 0.5, 3, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2, 3 + utils.EPSILON * 0.5, 4)));
assertFalsy(quat.equals(quat.create(1, 2, 3, 4), quat.create(1, 2, 3, 4 + utils.EPSILON * 0.5)));
const expected = [-1, -2, -3, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.subtract(a, b, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [-1, -2, -3, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.sub(a, b, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [1.5, 3, 4.5, 6];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.lerp(a, b, 0.5, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [0.5, 1, 1.5, 2];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.lerp(a, b, -0.5, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [2.5, 5, 7.5, 10];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.lerp(a, b, 1.5, dst);
}, expected, [1, 2, 3, 4], [2, 4, 6, 8]);
const expected = [2, 4, 6, 8];
testQuatWithAndWithoutDest((a, dst) => {
return quat.mulScalar(a, 2, dst);
}, expected, [1, 2, 3, 4]);
const expected = [2, 4, 6, 8];
testQuatWithAndWithoutDest((a, dst) => {
return quat.scale(a, 2, dst);
}, expected, [1, 2, 3, 4]);
const expected = [0.5, 1, 1.5, 2];
testQuatWithAndWithoutDest((a, dst) => {
return quat.divScalar(a, 2, dst);
}, expected, [1, 2, 3, 4]);
const expected = [
-0.021505376344086023,
-0.03225806451612903,
0.043010752688172046,
-0.08602150537634409,
];
testQuatWithAndWithoutDest((a, dst) => {
return quat.inverse(a, dst);
}, expected, [2, 3, -4, -8]);
const expected = 1 * 2 + 2 * 4 + 3 * 6 + 4 * 8;
const value = quat.dot(quat.create(1, 2, 3, 4), quat.create(2, 4, 6, 8));
assertStrictEqual(value, expected);
const expected = Math.sqrt(1 * 1 + 2 * 2 + 3 * 3 + 4 * 4);
const value = quat.length(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const expected = 1 * 1 + 2 * 2 + 3 * 3 + 4 * 4;
const value = quat.lengthSq(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const expected = Math.sqrt(1 * 1 + 2 * 2 + 3 * 3 + 4 * 4);
const value = quat.len(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const expected = 1 * 1 + 2 * 2 + 3 * 3 + 4 * 4;
const value = quat.lenSq(quat.create(1, 2, 3, 4));
assertStrictEqual(value, expected);
const length = Math.sqrt(1 * 1 + 2 * 2 + 3 * 3 + 4 * 4);
const expected = [
1 / length,
2 / length,
3 / length,
4 / length,
];
testQuatWithAndWithoutDest((a, dst) => {
return quat.normalize(a, dst);
}, expected, [1, 2, 3, 4]);
const expected = [1, 2, 3, 4];
const v = quat.create(1, 2, 3, 4);
testQuatWithAndWithoutDest((a, dst) => {
const result = quat.copy(a, dst);
assertStrictNotEqual(result, v);
return result;
}, expected, [1, 2, 3, 4]);
const expected = [1, 2, 3, 4];
const v = quat.create(1, 2, 3, 4);
testQuatWithAndWithoutDest((a, dst) => {
const result = quat.clone(a, dst);
assertStrictNotEqual(result, v);
return result;
}, expected, [1, 2, 3, 4]);
const expected = [2, 3, 4, 5];
testQuatWithAndWithoutDest((a, b, c, d, dst) => {
return quat.set(a, b, c, d, dst);
}, expected, 2, 3, 4, 5);
const expected = [-16, -32, -48, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.multiply(a, b, dst);
}, expected, [1, 2, 3, 4], [-2, -4, -6, -8]);
const expected = [-16, -32, -48, -4];
testQuatWithAndWithoutDest((a, b, dst) => {
return quat.mul(a, b, dst);
}, expected, [1, 2, 3, 4], [-2, -4, -6, -8]);
const expected = quat.create(1, 2, 3, 4);
const v1 = quat.fromValues(1, 2, 3, 4);
assertEqual(v1, expected);
const axis = [1, 0, 0]; //vec3.normalize([1, 2, 3]);
const angle = 0; //45 * Math.PI / 180;
const expected = [0, 0, 0, 1];
testQuatWithAndWithoutDest((axis, angle, dst) => {
return quat.fromAxisAngle(axis, angle, dst);
}, expected, axis, angle);
const tests = [
{ axis: [1, 0, 0], angle: 0.1 },
{ axis: [0, 1, 0], angle: 0.1 },
{ axis: [0, 0, 1], angle: 0.1 },
{ axis: vec3.normalize([1, 2, 3]), angle: 0.1 },
];
for (const expected of tests) {
const { axis, angle } = expected;
const q = quat.fromAxisAngle(axis, angle);
const actual = quat.toAxisAngle(q);
assertDeepEqualApproximately(actual, expected, 1e6);
}
const tests = [
{ axis: [1, 0, 0], },
{ axis: [0, 1, 0], },
{ axis: [0, 0, 1], },
{ axis: vec3.normalize([1, 2, 3]) },
];
for (const {axis} of tests) {
const q1 = quat.fromAxisAngle(axis, 0.1);
const q2 = quat.fromAxisAngle(axis, 0.4);
const actual = quat.angle(q1, q2);
assertDeepEqualApproximately(actual, 0.3);
}
const tests = [
{ angle: 0, expected: [1, 2, 3, 4], },
{ angle: Math.PI, expected: [4, 3, -2, -1], },
{ angle: -Math.PI, expected: [-4, -3, 2, 1], },
];
for (const {angle, expected} of tests) {
testQuatWithAndWithoutDest((a, dst) => {
return quat.rotateX([1, 2, 3, 4], a, dst);
}, expected, angle);
}
const tests = [
{ angle: 0, expected: [1, 2, 3, 4], },
{ angle: Math.PI, expected: [-3, 4, 1, -2], },
{ angle: -Math.PI, expected: [3, -4, -1, 2], },
];
for (const {angle, expected} of tests) {
testQuatWithAndWithoutDest((a, dst) => {
return quat.rotateY([1, 2, 3, 4], a, dst);
}, expected, angle);
}
const tests = [
{ angle: 0, expected: [1, 2, 3, 4], },
{ angle: Math.PI, expected: [-3, 4, 1, -2], },
{ angle: -Math.PI, expected: [3, -4, -1, 2], },
];
for (const {angle, expected} of tests) {
testQuatWithAndWithoutDest((a, dst) => {
return quat.rotateY([1, 2, 3, 4], a, dst);
}, expected, angle);
}
const a1 = [0, 1, 0, 1];
const b1 = [1, 0, 0, 1];
const a2 = [0, 1, 0, 1];
const b2 = [0, 1, 0, 0.5];
const a3 = quat.fromEuler(0.1, 0.2, 0.3, 'xyz');
const b3 = quat.fromEuler(0.3, 0.2, 0.1, 'xyz');
const tests = [
{ a: a1, b: b1, t: 0, expected: [0, 1, 0, 1], },
{ a: a1, b: b1, t: 1, expected: [1, 0, 0, 1], },
{ a: a1, b: b1, t: 0.5, expected: [0.5, 0.5, 0, 1], },
{ a: a2, b: b2, t: 0.5, expected: [0, 1, 0, 0.75], },
{ a: a3, b: b3, t: 0.5, expected: [0.1089731245591333, 0.09134010671547867, 0.10897312455913327, 0.9838224947381737], },
];
for (const {a, b, t, expected} of tests) {
testQuatWithAndWithoutDest((a, b, t, dst) => {
return quat.slerp(a, b, t, dst);
}, expected, a, b, t);
}
const expected = [-2, -3, -4, 5];
testQuatWithAndWithoutDest((q, dst) => {
return quat.conjugate(q, dst);
}, expected, [2, 3, 4, 5]);
const tests = [
{ expected: [0, 0, 0, 1], mat: mat4.identity(), },
{ expected: [1, 0, 0, 0], mat: mat4.rotationX(Math.PI), },
{ expected: [0, 1, 0, 0], mat: mat4.rotationY(Math.PI), },
{ expected: [0, 0, 1, 0], mat: mat4.rotationZ(Math.PI), },
].map(({expected, mat}) => [
{ expected, mat },
{ expected, mat: mat3.fromMat4(mat), },
]).flat();
for (const {mat, expected} of tests) {
testQuatWithAndWithoutDest((mat, dst) => {
return quat.fromMat(mat, dst);
}, expected, mat);
}
const tests = [
{ args: [0, 0, 0, 'xyz'], expected: [0, 0, 0, 1], },
{ args: [Math.PI, 0, 0, 'xyz'], expected: [1, 0, 0, 0], },
{ args: [0, Math.PI, 0, 'xyz'], expected: [0, 1, 0, 0], },
{ args: [0, 0, Math.PI, 'xyz'], expected: [0, 0, 1, 0], },
{ args: [Math.PI, Math.PI, 0, 'xyz'], expected: [0, 0, 1, 0], },
{ args: [Math.PI, Math.PI, 0, 'yxz'], expected: [0, 0, -1, 0], },
{ args: [0, Math.PI, Math.PI, 'xyz'], expected: [1, 0, 0, 0], },
{ args: [0, Math.PI, Math.PI, 'xzy'], expected: [-1, 0, 0, 0], },
{ args: [Math.PI, 0, Math.PI, 'xyz'], expected: [0, -1, 0, 0], },
{ args: [Math.PI, 0, Math.PI, 'zyx'], expected: [0, 1, 0, 0], },
{ args: [Math.PI, 0, Math.PI, 'zxy'], expected: [0, 1, 0, 0], },
{ args: [0.1, Math.PI, 0, 'zyx'], expected: [0, 0.9987502694129944, -0.04997916892170906, 0 ]},
];
for (const {args, expected} of tests) {
testQuatWithAndWithoutDest((...args) => {
return quat.fromEuler(...args);
}, expected, ...args);
}
const tests = [
{ args: [quat.fromEuler(Math.PI / 2, 0, 0, 'xyz'), quat.fromEuler(0, Math.PI, 0, 'xyz')], expected: [0, 0, 0.5773502588272095, 0.8164966106414795], },
{ args: [quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), quat.fromEuler(0, Math.PI, 0, 'xyz')], expected: [0, 0, 0, 1], },
{ args: [quat.fromEuler(0, Math.PI / 2, 0, 'xyz'), quat.fromEuler(0, 0, Math.PI, 'xyz')], expected: [0.5773502588272095, 0, 0, 0.8164966106414795], },
{ args: [quat.fromEuler(0, 0, Math.PI / 2, 'zyx'), quat.fromEuler(0.1, Math.PI, 0, 'zyx')], expected: [-0.5907140970230103, 0, 0, 0.8068809509277344], },
];
for (const {args, expected} of tests) {
testQuatWithAndWithoutDest((...args) => {
return quat.rotationTo(...args);
}, expected, ...args);
}
const a = quat.fromEuler(Math.PI / 2, 0, 0, 'xyz');
const b = quat.fromEuler(0, Math.PI / 2, 0, 'xyz');
const c = quat.fromEuler(0, 0, Math.PI / 2, 'xyz');
const d = quat.fromEuler(Math.PI, 0, 0, 'xyz');
const tests = [
{ args: [a, b, c, d, 0], expected: a },
{ args: [a, b, c, d, 1], expected: d },
{ args: [a, b, c, d, 0.25], expected: [0.5946745811867614, 0.2612930755130939, 0.095639903470758, 0.7542818306464518] },
{ args: [a, b, c, d, 0.5], expected: [0.5702395788501929, 0.25198018251105747, 0.25198018251105747, 0.7401613323837869] },
{ args: [a, b, c, d, 0.75], expected: [0.7683175218769692, 0.10832581796559188, 0.29595163845345446, 0.5571053135948666] },
];
for (const {args, expected} of tests) {
testQuatWithAndWithoutDest((...args) => {
return quat.sqlerp(...args);
}, expected, ...args);
}
const expected = [3, 5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.add(a, b, newDst);
}, expected, [1, 2], [2, 3]);
const tests = [
{ a: [1, 0], b: [ 0, 1], expected: Math.PI / 2, },
{ a: [1, 0], b: [-1, 0], expected: Math.PI, },
{ a: [1, 0], b: [ 1, 0], expected: 0, },
{ a: [1, 2], b: [ 4, 5], expected: 0.2110933, },
{ a: [1, 0], b: [ 0, Number.POSITIVE_INFINITY], expected: Math.PI / 2, },
];
for (const {a, b, expected} of tests) {
const av = vec2.create(...a);
const bv = vec2.create(...b);
assertEqualApproximately(vec2.angle(av, bv), expected);
vec2.mulScalar(av, 1000, av);
vec2.mulScalar(bv, 1000, bv);
assertEqualApproximately(vec2.angle(av, bv), expected);
}
const expected = [2, -1];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.ceil(a, newDst);
}, expected, [1.1, -1.1]);
const expected = [1, -2];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.floor(a, newDst);
}, expected, [1.1, -1.1]);
const expected = [1, -1];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.round(a, newDst);
}, expected, [1.1, -1.1]);
{
const expected = [1, 0];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.clamp(a, 0, 1, newDst);
}, expected, [2, -1]);
}
{
const expected = [-10, 5];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.clamp(a, -10, 5, newDst);
}, expected, [-22, 50]);
}
assertTruthy(vec2.equalsApproximately(vec2.create(2, 3), vec2.create(2, 3)));
assertTruthy(vec2.equalsApproximately(vec2.create(2, 3), vec2.create(2 + utils.EPSILON * 0.5, 3)));
assertFalsy(vec2.equalsApproximately(vec2.create(2, 3), vec2.create(2.001, 3)));
assertTruthy(vec2.equals(vec2.create(2, 3), vec2.create(2, 3)));
assertFalsy(vec2.equals(vec2.create(2, 3), vec2.create(2 + utils.EPSILON * 0.5, 3)));
const expected = [-2, -3];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.subtract(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [-2, -3];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.sub(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [3, 4.5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.lerp(a, b, 0.5, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [0.5, 1.5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.lerp(a, b, -0.5, newDst);
}, expected, [1, 3], [2, 6]);
const expected = [2.5, 7.5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.lerp(a, b, 1.5, newDst);
}, expected, [1, 3], [2, 6]);
const expected = [4, 6];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.mulScalar(a, 2, newDst);
}, expected, [2, 3]);
const expected = [4, 6];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.scale(a, 2, newDst);
}, expected, [2, 3]);
const expected = [10, 15];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.addScaled(a, [4, 6], 2, newDst);
}, expected, [2, 3]);
const expected = [0.5, 1.5];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.divScalar(a, 2, newDst);
}, expected, [1, 3]);
const expected = [1 / 3, 1 / -4];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.inverse(a, newDst);
}, expected, [3, -4]);
const expected = [
0,
0,
2 * 5 - 3 * 4,
];
const c = vec2.cross(vec2.create(2, 3), vec2.create(4, 5));
assertArrayEqualApproximately(c, expected);
const d = vec2.cross(vec2.create(3, 2), vec2.create(4, 5), c);
assertStrictEqual(d, c);
const expected2 = [
0,
0,
3 * 5 - 2 * 4,
];
assertArrayEqualApproximately(c, expected2);
const expected = 2 * 4 + 3 * 6;
const value = vec2.dot(vec2.create(2, 3), vec2.create(4, 6));
assertStrictEqual(value, expected);
const expected = Math.sqrt(2 * 2 + 3 * 3);
const value = vec2.length(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = 2 * 2 + 3 * 3;
const value = vec2.lengthSq(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = Math.sqrt(2 * 2 + 3 * 3);
const value = vec2.len(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = 2 * 2 + 3 * 3;
const value = vec2.lenSq(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = Math.sqrt(3 * 3 + 4 * 4);
const value = vec2.distance(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const expected = 3 * 3 + 4 * 4;
const value = vec2.distanceSq(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const expected = Math.sqrt(3 * 3 + 4 * 4);
const value = vec2.dist(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const expected = 3 * 3 + 4 * 4;
const value = vec2.distSq(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const length = Math.sqrt(2 * 2 + 3 * 3);
const expected = [
2 / length,
3 / length,
];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.normalize(a, newDst);
}, expected, [2, 3]);
const expected = [-2, 3];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.negate(a, newDst);
}, expected, [2, -3]);
const expected = [2, 3];
const v = vec2.create(2, 3);
testV2WithAndWithoutDest((a, newDst) => {
const result = vec2.copy(a, newDst);
assertStrictNotEqual(result, v);
return result;
}, expected, [2, 3]);
const expected = [2, 3];
const v = vec2.create(2, 3);
testV2WithAndWithoutDest((a, newDst) => {
const result = vec2.clone(a, newDst);
assertStrictNotEqual(result, v);
return result;
}, expected, [2, 3]);
const expected = [2, 3];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.set(a, b, newDst);
}, expected, 2, 3);
const expected = [8, 18];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.multiply(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [8, 18];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.mul(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [2 / 3, 3 / 4];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.divide(a, b, newDst);
}, expected, [2, 3], [3, 4]);
const expected = [2 / 3, 3 / 4];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.div(a, b, newDst);
}, expected, [2, 3], [3, 4]);
const expected = vec2.create(2, 3);
const v1 = vec2.fromValues(2, 3);
assertEqual(v1, expected);
for (let i = 0; i < 100; ++i) {
const v1 = vec2.random();
assertEqualApproximately(vec2.length(v1), 1);
const v2 = vec2.random(2);
assertEqualApproximately(vec2.length(v2), 2);
const vp5 = vec2.random(0.5);
assertEqualApproximately(vec2.length(vp5), 0.5);
const vd = vec2.create();
const vn = vec2.random(3, vd);
assertStrictEqual(vd, vn);
assertEqualApproximately(vec2.length(3, vd), 3);
}
const expected = [16, 17];
testV2WithAndWithoutDest((a, newDst) => {
const m = [
4, 0, 0, 11,
0, 5, 0, 12,
8, 2, 0, 13,
];
return vec2.transformMat3(a, m, newDst);
}, expected, [2, 3]);
const expected = [6, 11];
testV2WithAndWithoutDest((a, newDst) => {
const m = [
1, 0, 0, 0,
0, 2, 0, 0,
0, 0, 3, 0,
4, 5, 6, 1,
];
return vec2.transformMat4(a, m, newDst);
}, expected, [2, 3]);
const v = vec2.zero();
assertEqual(v, [0, 0]);
const v2 = vec2.create(2, 3);
const vn = vec2.zero(v2);
assertStrictEqual(v2, vn);
assertEqual(v2, [0, 0]);
const expected = [0, -1];
testV2WithAndWithoutDestApprox((a, b, angle, newDst) => {
return vec2.rotate(a, b, angle, newDst);
}, expected, [0, 1], [0, 0], Math.PI);
const expected = [-6, -5];
testV2WithAndWithoutDestApprox((a, b, angle, newDst) => {
return vec2.rotate(a, b, angle, newDst);
}, expected, [6, -5], [0, -5], Math.PI);
const expected = [10.323759005323593, 10.323759005323593];
testV2WithAndWithoutDestApprox(
(a, len, newDst) => vec2.setLength(a, len, newDst),
expected,
[1, 1], 14.6);
const expected = [2.82842712474619, 2.82842712474619];
testV2WithAndWithoutDestApprox(
(a, len, newDst) => vec2.truncate(a, len, newDst),
expected,
[10.323759005323593, 10.323759005323593],
4.0);
const expected = [11, 12];
testV2WithAndWithoutDestApprox(
(a, len, newDst) => vec2.truncate(a, len, newDst),
expected,
[11, 12],
14.6);
const expected = [5, 5];
testV2WithAndWithoutDest(
(a, b, newDst) => vec2.midpoint(a, b, newDst),
expected,
[0, 0], [10, 10]
);
const expected = [10, 10];
testV2WithAndWithoutDest(
(a, b, newDst) => vec2.midpoint(a, b, newDst),
expected,
[-10, -20], [30, 40]);
const expected = [3, 5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.add(a, b, newDst);
}, expected, [1, 2], [2, 3]);
const tests = [
{ a: [1, 0], b: [ 0, 1], expected: Math.PI / 2, },
{ a: [1, 0], b: [-1, 0], expected: Math.PI, },
{ a: [1, 0], b: [ 1, 0], expected: 0, },
{ a: [1, 2], b: [ 4, 5], expected: 0.2110933, },
{ a: [1, 0], b: [ 0, Number.POSITIVE_INFINITY], expected: Math.PI / 2, },
];
for (const {a, b, expected} of tests) {
const av = vec2.create(...a);
const bv = vec2.create(...b);
assertEqualApproximately(vec2.angle(av, bv), expected);
vec2.mulScalar(av, 1000, av);
vec2.mulScalar(bv, 1000, bv);
assertEqualApproximately(vec2.angle(av, bv), expected);
}
const expected = [2, -1];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.ceil(a, newDst);
}, expected, [1.1, -1.1]);
const expected = [1, -2];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.floor(a, newDst);
}, expected, [1.1, -1.1]);
const expected = [1, -1];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.round(a, newDst);
}, expected, [1.1, -1.1]);
{
const expected = [1, 0];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.clamp(a, 0, 1, newDst);
}, expected, [2, -1]);
}
{
const expected = [-10, 5];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.clamp(a, -10, 5, newDst);
}, expected, [-22, 50]);
}
assertTruthy(vec2.equalsApproximately(vec2.create(2, 3), vec2.create(2, 3)));
assertTruthy(vec2.equalsApproximately(vec2.create(2, 3), vec2.create(2 + utils.EPSILON * 0.5, 3)));
assertFalsy(vec2.equalsApproximately(vec2.create(2, 3), vec2.create(2.001, 3)));
assertTruthy(vec2.equals(vec2.create(2, 3), vec2.create(2, 3)));
assertFalsy(vec2.equals(vec2.create(2, 3), vec2.create(2 + utils.EPSILON * 0.5, 3)));
const expected = [-2, -3];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.subtract(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [-2, -3];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.sub(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [3, 4.5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.lerp(a, b, 0.5, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [0.5, 1.5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.lerp(a, b, -0.5, newDst);
}, expected, [1, 3], [2, 6]);
const expected = [2.5, 7.5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.lerp(a, b, 1.5, newDst);
}, expected, [1, 3], [2, 6]);
const expected = [4, 6];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.mulScalar(a, 2, newDst);
}, expected, [2, 3]);
const expected = [4, 6];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.scale(a, 2, newDst);
}, expected, [2, 3]);
const expected = [10, 15];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.addScaled(a, [4, 6], 2, newDst);
}, expected, [2, 3]);
const expected = [0.5, 1.5];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.divScalar(a, 2, newDst);
}, expected, [1, 3]);
const expected = [1 / 3, 1 / -4];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.inverse(a, newDst);
}, expected, [3, -4]);
const expected = [
0,
0,
2 * 5 - 3 * 4,
];
const c = vec2.cross(vec2.create(2, 3), vec2.create(4, 5));
assertArrayEqualApproximately(c, expected);
const d = vec2.cross(vec2.create(3, 2), vec2.create(4, 5), c);
assertStrictEqual(d, c);
const expected2 = [
0,
0,
3 * 5 - 2 * 4,
];
assertArrayEqualApproximately(c, expected2);
const expected = 2 * 4 + 3 * 6;
const value = vec2.dot(vec2.create(2, 3), vec2.create(4, 6));
assertStrictEqual(value, expected);
const expected = Math.sqrt(2 * 2 + 3 * 3);
const value = vec2.length(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = 2 * 2 + 3 * 3;
const value = vec2.lengthSq(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = Math.sqrt(2 * 2 + 3 * 3);
const value = vec2.len(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = 2 * 2 + 3 * 3;
const value = vec2.lenSq(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = Math.sqrt(3 * 3 + 4 * 4);
const value = vec2.distance(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const expected = 3 * 3 + 4 * 4;
const value = vec2.distanceSq(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const expected = Math.sqrt(3 * 3 + 4 * 4);
const value = vec2.dist(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const expected = 3 * 3 + 4 * 4;
const value = vec2.distSq(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const length = Math.sqrt(2 * 2 + 3 * 3);
const expected = [
2 / length,
3 / length,
];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.normalize(a, newDst);
}, expected, [2, 3]);
const expected = [-2, 3];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.negate(a, newDst);
}, expected, [2, -3]);
const expected = [2, 3];
const v = vec2.create(2, 3);
testV2WithAndWithoutDest((a, newDst) => {
const result = vec2.copy(a, newDst);
assertStrictNotEqual(result, v);
return result;
}, expected, [2, 3]);
const expected = [2, 3];
const v = vec2.create(2, 3);
testV2WithAndWithoutDest((a, newDst) => {
const result = vec2.clone(a, newDst);
assertStrictNotEqual(result, v);
return result;
}, expected, [2, 3]);
const expected = [2, 3];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.set(a, b, newDst);
}, expected, 2, 3);
const expected = [8, 18];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.multiply(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [8, 18];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.mul(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [2 / 3, 3 / 4];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.divide(a, b, newDst);
}, expected, [2, 3], [3, 4]);
const expected = [2 / 3, 3 / 4];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.div(a, b, newDst);
}, expected, [2, 3], [3, 4]);
const expected = vec2.create(2, 3);
const v1 = vec2.fromValues(2, 3);
assertEqual(v1, expected);
for (let i = 0; i < 100; ++i) {
const v1 = vec2.random();
assertEqualApproximately(vec2.length(v1), 1);
const v2 = vec2.random(2);
assertEqualApproximately(vec2.length(v2), 2);
const vp5 = vec2.random(0.5);
assertEqualApproximately(vec2.length(vp5), 0.5);
const vd = vec2.create();
const vn = vec2.random(3, vd);
assertStrictEqual(vd, vn);
assertEqualApproximately(vec2.length(3, vd), 3);
}
const expected = [16, 17];
testV2WithAndWithoutDest((a, newDst) => {
const m = [
4, 0, 0, 11,
0, 5, 0, 12,
8, 2, 0, 13,
];
return vec2.transformMat3(a, m, newDst);
}, expected, [2, 3]);
const expected = [6, 11];
testV2WithAndWithoutDest((a, newDst) => {
const m = [
1, 0, 0, 0,
0, 2, 0, 0,
0, 0, 3, 0,
4, 5, 6, 1,
];
return vec2.transformMat4(a, m, newDst);
}, expected, [2, 3]);
const v = vec2.zero();
assertEqual(v, [0, 0]);
const v2 = vec2.create(2, 3);
const vn = vec2.zero(v2);
assertStrictEqual(v2, vn);
assertEqual(v2, [0, 0]);
const expected = [0, -1];
testV2WithAndWithoutDestApprox((a, b, angle, newDst) => {
return vec2.rotate(a, b, angle, newDst);
}, expected, [0, 1], [0, 0], Math.PI);
const expected = [-6, -5];
testV2WithAndWithoutDestApprox((a, b, angle, newDst) => {
return vec2.rotate(a, b, angle, newDst);
}, expected, [6, -5], [0, -5], Math.PI);
const expected = [10.323759005323593, 10.323759005323593];
testV2WithAndWithoutDestApprox(
(a, len, newDst) => vec2.setLength(a, len, newDst),
expected,
[1, 1], 14.6);
const expected = [2.82842712474619, 2.82842712474619];
testV2WithAndWithoutDestApprox(
(a, len, newDst) => vec2.truncate(a, len, newDst),
expected,
[10.323759005323593, 10.323759005323593],
4.0);
const expected = [11, 12];
testV2WithAndWithoutDestApprox(
(a, len, newDst) => vec2.truncate(a, len, newDst),
expected,
[11, 12],
14.6);
const expected = [5, 5];
testV2WithAndWithoutDest(
(a, b, newDst) => vec2.midpoint(a, b, newDst),
expected,
[0, 0], [10, 10]
);
const expected = [10, 10];
testV2WithAndWithoutDest(
(a, b, newDst) => vec2.midpoint(a, b, newDst),
expected,
[-10, -20], [30, 40]);
const expected = [3, 5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.add(a, b, newDst);
}, expected, [1, 2], [2, 3]);
const tests = [
{ a: [1, 0], b: [ 0, 1], expected: Math.PI / 2, },
{ a: [1, 0], b: [-1, 0], expected: Math.PI, },
{ a: [1, 0], b: [ 1, 0], expected: 0, },
{ a: [1, 2], b: [ 4, 5], expected: 0.2110933, },
{ a: [1, 0], b: [ 0, Number.POSITIVE_INFINITY], expected: Math.PI / 2, },
];
for (const {a, b, expected} of tests) {
const av = vec2.create(...a);
const bv = vec2.create(...b);
assertEqualApproximately(vec2.angle(av, bv), expected);
vec2.mulScalar(av, 1000, av);
vec2.mulScalar(bv, 1000, bv);
assertEqualApproximately(vec2.angle(av, bv), expected);
}
const expected = [2, -1];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.ceil(a, newDst);
}, expected, [1.1, -1.1]);
const expected = [1, -2];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.floor(a, newDst);
}, expected, [1.1, -1.1]);
const expected = [1, -1];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.round(a, newDst);
}, expected, [1.1, -1.1]);
{
const expected = [1, 0];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.clamp(a, 0, 1, newDst);
}, expected, [2, -1]);
}
{
const expected = [-10, 5];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.clamp(a, -10, 5, newDst);
}, expected, [-22, 50]);
}
assertTruthy(vec2.equalsApproximately(vec2.create(2, 3), vec2.create(2, 3)));
assertTruthy(vec2.equalsApproximately(vec2.create(2, 3), vec2.create(2 + utils.EPSILON * 0.5, 3)));
assertFalsy(vec2.equalsApproximately(vec2.create(2, 3), vec2.create(2.001, 3)));
assertTruthy(vec2.equals(vec2.create(2, 3), vec2.create(2, 3)));
assertFalsy(vec2.equals(vec2.create(2, 3), vec2.create(2 + utils.EPSILON * 0.5, 3)));
const expected = [-2, -3];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.subtract(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [-2, -3];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.sub(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [3, 4.5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.lerp(a, b, 0.5, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [0.5, 1.5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.lerp(a, b, -0.5, newDst);
}, expected, [1, 3], [2, 6]);
const expected = [2.5, 7.5];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.lerp(a, b, 1.5, newDst);
}, expected, [1, 3], [2, 6]);
const expected = [4, 6];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.mulScalar(a, 2, newDst);
}, expected, [2, 3]);
const expected = [4, 6];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.scale(a, 2, newDst);
}, expected, [2, 3]);
const expected = [10, 15];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.addScaled(a, [4, 6], 2, newDst);
}, expected, [2, 3]);
const expected = [0.5, 1.5];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.divScalar(a, 2, newDst);
}, expected, [1, 3]);
const expected = [1 / 3, 1 / -4];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.inverse(a, newDst);
}, expected, [3, -4]);
const expected = [
0,
0,
2 * 5 - 3 * 4,
];
const c = vec2.cross(vec2.create(2, 3), vec2.create(4, 5));
assertArrayEqualApproximately(c, expected);
const d = vec2.cross(vec2.create(3, 2), vec2.create(4, 5), c);
assertStrictEqual(d, c);
const expected2 = [
0,
0,
3 * 5 - 2 * 4,
];
assertArrayEqualApproximately(c, expected2);
const expected = 2 * 4 + 3 * 6;
const value = vec2.dot(vec2.create(2, 3), vec2.create(4, 6));
assertStrictEqual(value, expected);
const expected = Math.sqrt(2 * 2 + 3 * 3);
const value = vec2.length(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = 2 * 2 + 3 * 3;
const value = vec2.lengthSq(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = Math.sqrt(2 * 2 + 3 * 3);
const value = vec2.len(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = 2 * 2 + 3 * 3;
const value = vec2.lenSq(vec2.create(2, 3));
assertStrictEqual(value, expected);
const expected = Math.sqrt(3 * 3 + 4 * 4);
const value = vec2.distance(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const expected = 3 * 3 + 4 * 4;
const value = vec2.distanceSq(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const expected = Math.sqrt(3 * 3 + 4 * 4);
const value = vec2.dist(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const expected = 3 * 3 + 4 * 4;
const value = vec2.distSq(vec2.create(2, 3), [5, 7]);
assertStrictEqual(value, expected);
const length = Math.sqrt(2 * 2 + 3 * 3);
const expected = [
2 / length,
3 / length,
];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.normalize(a, newDst);
}, expected, [2, 3]);
const expected = [-2, 3];
testV2WithAndWithoutDest((a, newDst) => {
return vec2.negate(a, newDst);
}, expected, [2, -3]);
const expected = [2, 3];
const v = vec2.create(2, 3);
testV2WithAndWithoutDest((a, newDst) => {
const result = vec2.copy(a, newDst);
assertStrictNotEqual(result, v);
return result;
}, expected, [2, 3]);
const expected = [2, 3];
const v = vec2.create(2, 3);
testV2WithAndWithoutDest((a, newDst) => {
const result = vec2.clone(a, newDst);
assertStrictNotEqual(result, v);
return result;
}, expected, [2, 3]);
const expected = [2, 3];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.set(a, b, newDst);
}, expected, 2, 3);
const expected = [8, 18];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.multiply(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [8, 18];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.mul(a, b, newDst);
}, expected, [2, 3], [4, 6]);
const expected = [2 / 3, 3 / 4];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.divide(a, b, newDst);
}, expected, [2, 3], [3, 4]);
const expected = [2 / 3, 3 / 4];
testV2WithAndWithoutDest((a, b, newDst) => {
return vec2.div(a, b, newDst);
}, expected, [2, 3], [3, 4]);
const expected = vec2.create(2, 3);
const v1 = vec2.fromValues(2, 3);
assertEqual(v1, expected);
for (let i = 0; i < 100; ++i) {
const v1 = vec2.random();
assertEqualApproximately(vec2.length(v1), 1);
const v2 = vec2.random(2);
assertEqualApproximately(vec2.length(v2), 2);
const vp5 = vec2.random(0.5);
assertEqualApproximately(vec2.length(vp5), 0.5);
const vd = vec2.create();
const vn = vec2.random(3, vd);
assertStrictEqual(vd, vn);
assertEqualApproximately(vec2.length(3, vd), 3);
}
const expected = [16, 17];
testV2WithAndWithoutDest((a, newDst) => {
const m = [
4, 0, 0, 11,
0, 5, 0, 12,
8, 2, 0, 13,
];
return vec2.transformMat3(a, m, newDst);
}, expected, [2, 3]);
const expected = [6, 11];
testV2WithAndWithoutDest((a, newDst) => {
const m = [
1, 0, 0, 0,
0, 2, 0, 0,
0, 0, 3, 0,
4, 5, 6, 1,
];
return vec2.transformMat4(a, m, newDst);
}, expected, [2, 3]);
const v = vec2.zero();
assertEqual(v, [0, 0]);
const v2 = vec2.create(2, 3);
const vn = vec2.zero(v2);
assertStrictEqual(v2, vn);
assertEqual(v2, [0, 0]);
const expected = [0, -1];
testV2WithAndWithoutDestApprox((a, b, angle, newDst) => {
return vec2.rotate(a, b, angle, newDst);
}, expected, [0, 1], [0, 0], Math.PI);
const expected = [-6, -5];
testV2WithAndWithoutDestApprox((a, b, angle, newDst) => {
return vec2.rotate(a, b, angle, newDst);
}, expected, [6, -5], [0, -5], Math.PI);
const expected = [10.323759005323593, 10.323759005323593];
testV2WithAndWithoutDestApprox(
(a, len, newDst) => vec2.setLength(a, len, newDst),
expected,
[1, 1], 14.6);
const expected = [2.82842712474619, 2.82842712474619];
testV2WithAndWithoutDestApprox(
(a, len, newDst) => vec2.truncate(a, len, newDst),
expected,
[10.323759005323593, 10.323759005323593],
4.0);
const expected = [11, 12];
testV2WithAndWithoutDestApprox(
(a, len, newDst) => vec2.truncate(a, len, newDst),
expected,
[11, 12],
14.6);