import { Cartesian3 } from "../../Source/Cesium.js"; import { HeadingPitchRoll } from "../../Source/Cesium.js"; import { Math as CesiumMath } from "../../Source/Cesium.js"; import { Matrix3 } from "../../Source/Cesium.js"; import { Quaternion } from "../../Source/Cesium.js"; import createPackableSpecs from "../createPackableSpecs.js"; describe("Core/Quaternion", function () { it("construct with default values", function () { var quaternion = new Quaternion(); expect(quaternion.x).toEqual(0.0); expect(quaternion.y).toEqual(0.0); expect(quaternion.z).toEqual(0.0); expect(quaternion.w).toEqual(0.0); }); it("construct with all values", function () { var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); expect(quaternion.x).toEqual(1.0); expect(quaternion.y).toEqual(2.0); expect(quaternion.z).toEqual(3.0); expect(quaternion.w).toEqual(4.0); }); it("fromAxisAngle works without a result parameter", function () { var axis = new Cartesian3(0.0, 0.0, 1.0); var angle = CesiumMath.PI_OVER_TWO; var s = Math.sin(angle / 2.0); var c = Math.cos(angle / 2.0); var a = Cartesian3.multiplyByScalar(axis, s, new Cartesian3()); var expected = new Quaternion(a.x, a.y, a.z, c); var returnedResult = Quaternion.fromAxisAngle(axis, angle); expect(returnedResult).toEqual(expected); }); it("fromAxisAngle works with a result parameter", function () { var axis = new Cartesian3(0.0, 0.0, 1.0); var angle = CesiumMath.PI_OVER_TWO; var s = Math.sin(angle / 2.0); var c = Math.cos(angle / 2.0); var a = Cartesian3.multiplyByScalar(axis, s, new Cartesian3()); var result = new Quaternion(); var expected = new Quaternion(a.x, a.y, a.z, c); var returnedResult = Quaternion.fromAxisAngle(axis, angle, result); expect(result).toBe(returnedResult); expect(returnedResult).toEqual(expected); }); it("fromRotationMatrix works when m22 is max", function () { var q = Quaternion.fromAxisAngle( Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), Math.PI ); var rotation = new Matrix3(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0); expect(Quaternion.fromRotationMatrix(rotation)).toEqualEpsilon( q, CesiumMath.EPSILON15 ); }); it("fromRotationMatrix works when m11 is max", function () { var q = Quaternion.fromAxisAngle( Cartesian3.negate(Cartesian3.UNIT_Y, new Cartesian3()), Math.PI ); var rotation = new Matrix3(-1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0); expect(Quaternion.fromRotationMatrix(rotation)).toEqualEpsilon( q, CesiumMath.EPSILON15 ); }); it("fromRotationMatrix works when m00 is max", function () { var q = Quaternion.fromAxisAngle( Cartesian3.negate(Cartesian3.UNIT_X, new Cartesian3()), Math.PI ); var rotation = new Matrix3(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0); expect(Quaternion.fromRotationMatrix(rotation)).toEqualEpsilon( q, CesiumMath.EPSILON15 ); }); it("fromRotationMatrix works when trace is greater than zero", function () { var rotation = new Matrix3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0); var q = new Quaternion(0.0, 0.0, 0.0, 1.0); expect(Quaternion.fromRotationMatrix(rotation)).toEqualEpsilon( q, CesiumMath.EPSILON15 ); }); it("fromRotationMatrix works with result parameter", function () { var rotation = new Matrix3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0); var q = new Quaternion(0.0, 0.0, 0.0, 1.0); var result = new Quaternion(); var returnedResult = Quaternion.fromRotationMatrix(rotation, result); expect(returnedResult).toEqualEpsilon(q, CesiumMath.EPSILON15); expect(returnedResult).toBe(result); }); it("fromRotationMatrix using a view matrix", function () { var direction = new Cartesian3( -0.2349326833984488, 0.8513513009480378, 0.46904967396353314 ); var up = new Cartesian3( 0.12477198625717335, -0.4521499177166376, 0.8831717858696695 ); var right = new Cartesian3( 0.9639702203483635, 0.26601017702986895, 6.456422901079747e-10 ); var matrix = new Matrix3( right.x, right.y, right.z, up.x, up.y, up.z, -direction.x, -direction.y, -direction.z ); var quaternion = Quaternion.fromRotationMatrix(matrix); expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon( matrix, CesiumMath.EPSILON12 ); }); it("fromHeadingPitchRoll with just heading", function () { var angle = CesiumMath.toRadians(20.0); var hpr = new HeadingPitchRoll(angle, 0.0, 0.0); var quaternion = Quaternion.fromHeadingPitchRoll(hpr); expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon( Matrix3.fromRotationZ(-angle), CesiumMath.EPSILON11 ); }); it("fromHeadingPitchRoll with just pitch", function () { var angle = CesiumMath.toRadians(20.0); var hpr = new HeadingPitchRoll(0.0, angle, 0.0); var quaternion = Quaternion.fromHeadingPitchRoll(hpr); expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon( Matrix3.fromRotationY(-angle), CesiumMath.EPSILON11 ); }); it("fromHeadingPitchRoll with just roll", function () { var angle = CesiumMath.toRadians(20.0); var hpr = new HeadingPitchRoll(0.0, 0.0, angle); var quaternion = Quaternion.fromHeadingPitchRoll(hpr); expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon( Matrix3.fromRotationX(angle), CesiumMath.EPSILON11 ); }); it("fromHeadingPitchRoll with all angles (1)", function () { var angle = CesiumMath.toRadians(20.0); var hpr = new HeadingPitchRoll(angle, angle, angle); var quaternion = Quaternion.fromHeadingPitchRoll(hpr); var expected = Matrix3.fromRotationX(angle); Matrix3.multiply(Matrix3.fromRotationY(-angle), expected, expected); Matrix3.multiply(Matrix3.fromRotationZ(-angle), expected, expected); expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon( expected, CesiumMath.EPSILON11 ); }); it("fromHeadingPitchRoll with all angles (2)", function () { var heading = CesiumMath.toRadians(180.0); var pitch = CesiumMath.toRadians(-45.0); var roll = CesiumMath.toRadians(45.0); var hpr = new HeadingPitchRoll(heading, pitch, roll); var quaternion = Quaternion.fromHeadingPitchRoll(hpr); var expected = Matrix3.fromRotationX(roll); Matrix3.multiply(Matrix3.fromRotationY(-pitch), expected, expected); Matrix3.multiply(Matrix3.fromRotationZ(-heading), expected, expected); expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon( expected, CesiumMath.EPSILON11 ); }); it("fromHeadingPitchRoll works with result parameter", function () { var angle = CesiumMath.toRadians(20.0); var hpr = new HeadingPitchRoll(0.0, 0.0, angle); var result = new Quaternion(); var quaternion = Quaternion.fromHeadingPitchRoll(hpr, result); var expected = Quaternion.fromRotationMatrix(Matrix3.fromRotationX(angle)); expect(quaternion).toBe(result); expect(quaternion).toEqualEpsilon(expected, CesiumMath.EPSILON11); }); it("clone without a result parameter", function () { var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); var result = quaternion.clone(); expect(quaternion).not.toBe(result); expect(quaternion).toEqual(result); }); it("clone with a result parameter", function () { var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); var result = new Quaternion(); var returnedResult = quaternion.clone(result); expect(quaternion).not.toBe(result); expect(result).toBe(returnedResult); expect(quaternion).toEqual(result); }); it("clone works with a result parameter that is an input parameter", function () { var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); var returnedResult = quaternion.clone(quaternion); expect(quaternion).toBe(returnedResult); }); it("conjugate works", function () { var expected = new Quaternion(-1.0, -2.0, -3.0, 4.0); var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); var result = new Quaternion(); var returnedResult = Quaternion.conjugate(quaternion, result); expect(result).toBe(returnedResult); expect(returnedResult).toEqual(expected); }); it("conjugate works with a result parameter that is an input parameter", function () { var expected = new Quaternion(-1.0, -2.0, -3.0, 4.0); var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); var returnedResult = Quaternion.conjugate(quaternion, quaternion); expect(quaternion).toBe(returnedResult); expect(quaternion).toEqual(expected); }); it("magnitudeSquared computes correct result", function () { var expected = 2 * 2 + 3 * 3 + 4 * 4 + 5 * 5; var quaternion = new Quaternion(2.0, 3.0, 4.0, 5.0); var result = Quaternion.magnitudeSquared(quaternion); expect(result).toEqual(expected); }); it("norm computes correct result", function () { var expected = Math.sqrt(2 * 2 + 3 * 3 + 4 * 4 + 5 * 5); var quaternion = new Quaternion(2.0, 3.0, 4.0, 5.0); var result = Quaternion.magnitude(quaternion); expect(result).toEqual(expected); }); it("normalize works", function () { var quaternion = new Quaternion(2.0, 0.0, 0.0, 0.0); var expectedResult = new Quaternion(1.0, 0.0, 0.0, 0.0); var result = new Quaternion(); var returnedResult = Quaternion.normalize(quaternion, result); expect(result).toBe(returnedResult); expect(result).toEqual(expectedResult); }); it("normalize works with a result parameter that is an input parameter", function () { var quaternion = new Quaternion(2.0, 0.0, 0.0, 0.0); var expectedResult = new Quaternion(1.0, 0.0, 0.0, 0.0); var returnedResult = Quaternion.normalize(quaternion, quaternion); expect(quaternion).toBe(returnedResult); expect(quaternion).toEqual(expectedResult); }); it("inverse works", function () { var quaternion = new Quaternion(2.0, 3.0, 4.0, 5.0); var magnitudeSquared = Quaternion.magnitudeSquared(quaternion); var expected = new Quaternion( -2.0 / magnitudeSquared, -3.0 / magnitudeSquared, -4.0 / magnitudeSquared, 5.0 / magnitudeSquared ); var result = new Quaternion(); var returnedResult = Quaternion.inverse(quaternion, result); expect(returnedResult).toEqual(expected); expect(returnedResult).toBe(result); }); it("inverse works with a result parameter that is an input parameter", function () { var quaternion = new Quaternion(2.0, 3.0, 4.0, 5.0); var magnitudeSquared = Quaternion.magnitudeSquared(quaternion); var expected = new Quaternion( -2.0 / magnitudeSquared, -3.0 / magnitudeSquared, -4.0 / magnitudeSquared, 5.0 / magnitudeSquared ); var returnedResult = Quaternion.inverse(quaternion, quaternion); expect(returnedResult).toEqual(expected); expect(returnedResult).toBe(quaternion); }); it("dot", function () { var left = new Quaternion(2.0, 3.0, 6.0, 8.0); var right = new Quaternion(4.0, 5.0, 7.0, 9.0); var expectedResult = 137.0; var result = Quaternion.dot(left, right); expect(result).toEqual(expectedResult); }); it("multiply works", function () { var left = new Quaternion(1.0, 2.0, 3.0, 4.0); var right = new Quaternion(8.0, 7.0, 6.0, 5.0); var expected = new Quaternion(28.0, 56.0, 30.0, -20.0); var result = new Quaternion(); var returnedResult = Quaternion.multiply(left, right, result); expect(returnedResult).toEqual(expected); expect(result).toBe(returnedResult); }); it("multiply works with a result parameter that is an input parameter", function () { var left = new Quaternion(1.0, 2.0, 3.0, 4.0); var right = new Quaternion(8.0, 7.0, 6.0, 5.0); var expected = new Quaternion(28.0, 56.0, 30.0, -20.0); var returnedResult = Quaternion.multiply(left, right, left); expect(returnedResult).toEqual(expected); expect(left).toBe(returnedResult); }); it("add works", function () { var left = new Quaternion(2.0, 3.0, 6.0, 8.0); var right = new Quaternion(4.0, 5.0, 7.0, 9.0); var result = new Quaternion(); var expectedResult = new Quaternion(6.0, 8.0, 13.0, 17.0); var returnedResult = Quaternion.add(left, right, result); expect(result).toBe(returnedResult); expect(result).toEqual(expectedResult); }); it("add works with a result parameter that is an input parameter", function () { var left = new Quaternion(2.0, 3.0, 6.0, 8.0); var right = new Quaternion(4.0, 5.0, 7.0, 9.0); var expectedResult = new Quaternion(6.0, 8.0, 13.0, 17.0); var returnedResult = Quaternion.add(left, right, left); expect(left).toBe(returnedResult); expect(left).toEqual(expectedResult); }); it("subtract works", function () { var left = new Quaternion(2.0, 3.0, 4.0, 8.0); var right = new Quaternion(1.0, 5.0, 7.0, 9.0); var result = new Quaternion(); var expectedResult = new Quaternion(1.0, -2.0, -3.0, -1.0); var returnedResult = Quaternion.subtract(left, right, result); expect(result).toBe(returnedResult); expect(result).toEqual(expectedResult); }); it("subtract works with this result parameter", function () { var left = new Quaternion(2.0, 3.0, 4.0, 8.0); var right = new Quaternion(1.0, 5.0, 7.0, 9.0); var expectedResult = new Quaternion(1.0, -2.0, -3.0, -1.0); var returnedResult = Quaternion.subtract(left, right, left); expect(returnedResult).toBe(left); expect(left).toEqual(expectedResult); }); it("multiplyByScalar works ", function () { var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); var result = new Quaternion(); var scalar = 2; var expectedResult = new Quaternion(2.0, 4.0, 6.0, 8.0); var returnedResult = Quaternion.multiplyByScalar( quaternion, scalar, result ); expect(result).toBe(returnedResult); expect(result).toEqual(expectedResult); }); it("multiplyByScalar works with a result parameter that is an input parameter", function () { var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); var scalar = 2; var expectedResult = new Quaternion(2.0, 4.0, 6.0, 8.0); var returnedResult = Quaternion.multiplyByScalar( quaternion, scalar, quaternion ); expect(quaternion).toBe(returnedResult); expect(quaternion).toEqual(expectedResult); }); it("divideByScalar works", function () { var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); var result = new Quaternion(); var scalar = 2; var expectedResult = new Quaternion(0.5, 1.0, 1.5, 2.0); var returnedResult = Quaternion.divideByScalar(quaternion, scalar, result); expect(result).toBe(returnedResult); expect(result).toEqual(expectedResult); }); it("divideByScalar works with a result parameter that is an input parameter", function () { var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); var scalar = 2; var expectedResult = new Quaternion(0.5, 1.0, 1.5, 2.0); var returnedResult = Quaternion.divideByScalar( quaternion, scalar, quaternion ); expect(quaternion).toBe(returnedResult); expect(quaternion).toEqual(expectedResult); }); it("axis works", function () { // 60 degrees is used here to ensure that the sine and cosine of the half angle are not equal. var angle = Math.PI / 3.0; var cos = Math.cos(angle / 2.0); var sin = Math.sin(angle / 2.0); var expected = Cartesian3.normalize( new Cartesian3(2.0, 3.0, 6.0), new Cartesian3() ); var quaternion = new Quaternion( sin * expected.x, sin * expected.y, sin * expected.z, cos ); var result = new Cartesian3(); var returnedResult = Quaternion.computeAxis(quaternion, result); expect(returnedResult).toEqualEpsilon(expected, CesiumMath.EPSILON15); expect(result).toBe(returnedResult); }); it("axis returns Cartesian3 0 when w equals 1.0", function () { var expected = new Cartesian3(0.0, 0.0, 0.0); var quaternion = new Quaternion(4.0, 2.0, 3.0, 1.0); var result = new Cartesian3(1, 2, 3); var returnedResult = Quaternion.computeAxis(quaternion, result); expect(returnedResult).toEqual(expected); expect(result).toBe(returnedResult); }); it("angle works", function () { // 60 degrees is used here to ensure that the sine and cosine of the half angle are not equal. var angle = Math.PI / 3.0; var cos = Math.cos(angle / 2.0); var sin = Math.sin(angle / 2.0); var axis = Cartesian3.normalize( new Cartesian3(2.0, 3.0, 6.0), new Cartesian3() ); var quaternion = new Quaternion( sin * axis.x, sin * axis.y, sin * axis.z, cos ); var result = Quaternion.computeAngle(quaternion); expect(result).toEqualEpsilon(angle, CesiumMath.EPSILON15); }); it("negate works", function () { var quaternion = new Quaternion(1.0, -2.0, -5.0, 4.0); var result = new Quaternion(); var expectedResult = new Quaternion(-1.0, 2.0, 5.0, -4.0); var returnedResult = Quaternion.negate(quaternion, result); expect(result).toBe(returnedResult); expect(result).toEqual(expectedResult); }); it("negate works with a result parameter that is an input parameter", function () { var quaternion = new Quaternion(1.0, -2.0, -5.0); var expectedResult = new Quaternion(-1.0, 2.0, 5.0); var returnedResult = Quaternion.negate(quaternion, quaternion); expect(quaternion).toBe(returnedResult); expect(quaternion).toEqual(expectedResult); }); it("lerp works", function () { var start = new Quaternion(4.0, 8.0, 10.0, 20.0); var end = new Quaternion(8.0, 20.0, 20.0, 30.0); var t = 0.25; var result = new Quaternion(); var expectedResult = new Quaternion(5.0, 11.0, 12.5, 22.5); var returnedResult = Quaternion.lerp(start, end, t, result); expect(result).toBe(returnedResult); expect(result).toEqual(expectedResult); }); it("lerp works with a result parameter that is an input parameter", function () { var start = new Quaternion(4.0, 8.0, 10.0, 20.0); var end = new Quaternion(8.0, 20.0, 20.0, 30.0); var t = 0.25; var expectedResult = new Quaternion(5.0, 11.0, 12.5, 22.5); var returnedResult = Quaternion.lerp(start, end, t, start); expect(start).toBe(returnedResult); expect(start).toEqual(expectedResult); }); it("lerp extrapolate forward", function () { var start = new Quaternion(4.0, 8.0, 10.0, 20.0); var end = new Quaternion(8.0, 20.0, 20.0, 30.0); var t = 2.0; var expectedResult = new Quaternion(12.0, 32.0, 30.0, 40.0); var result = Quaternion.lerp(start, end, t, new Quaternion()); expect(result).toEqual(expectedResult); }); it("lerp extrapolate backward", function () { var start = new Quaternion(4.0, 8.0, 10.0, 20.0); var end = new Quaternion(8.0, 20.0, 20.0, 30.0); var t = -1.0; var expectedResult = new Quaternion(0.0, -4.0, 0.0, 10.0); var result = Quaternion.lerp(start, end, t, new Quaternion()); expect(result).toEqual(expectedResult); }); it("slerp works", function () { var start = Quaternion.normalize( new Quaternion(0.0, 0.0, 0.0, 1.0), new Quaternion() ); var end = new Quaternion( 0.0, 0.0, Math.sin(CesiumMath.PI_OVER_FOUR), Math.cos(CesiumMath.PI_OVER_FOUR) ); var expected = new Quaternion( 0.0, 0.0, Math.sin(Math.PI / 8.0), Math.cos(Math.PI / 8.0) ); var result = new Quaternion(); var returnedResult = Quaternion.slerp(start, end, 0.5, result); expect(result).toEqualEpsilon(expected, CesiumMath.EPSILON15); expect(result).toBe(returnedResult); }); it("slerp works with a result parameter that is an input parameter", function () { var start = Quaternion.normalize( new Quaternion(0.0, 0.0, 0.0, 1.0), new Quaternion() ); var end = new Quaternion( 0.0, 0.0, Math.sin(CesiumMath.PI_OVER_FOUR), Math.cos(CesiumMath.PI_OVER_FOUR) ); var expected = new Quaternion( 0.0, 0.0, Math.sin(Math.PI / 8.0), Math.cos(Math.PI / 8.0) ); var returnedResult = Quaternion.slerp(start, end, 0.5, start); expect(start).toEqualEpsilon(expected, CesiumMath.EPSILON15); expect(start).toBe(returnedResult); }); it("slerp works with obtuse angles", function () { var start = Quaternion.normalize( new Quaternion(0.0, 0.0, 0.0, -1.0), new Quaternion() ); var end = new Quaternion( 0.0, 0.0, Math.sin(CesiumMath.PI_OVER_FOUR), Math.cos(CesiumMath.PI_OVER_FOUR) ); var expected = new Quaternion( 0.0, 0.0, -Math.sin(Math.PI / 8.0), -Math.cos(Math.PI / 8.0) ); expect(Quaternion.slerp(start, end, 0.5, new Quaternion())).toEqualEpsilon( expected, CesiumMath.EPSILON15 ); }); it("slerp uses lerp when dot product is close to 1", function () { var start = new Quaternion(0.0, 0.0, 0.0, 1.0); var end = new Quaternion(1.0, 2.0, 3.0, 1.0); var expected = new Quaternion(0.5, 1.0, 1.5, 1.0); var result = new Quaternion(); expect(Quaternion.slerp(start, end, 0.0, result)).toEqual(start); expect(Quaternion.slerp(start, end, 1.0, result)).toEqual(end); expect(Quaternion.slerp(start, end, 0.5, result)).toEqual(expected); }); it("slerp uses lerp when dot product is close to 1 and a result parameter", function () { var start = new Quaternion(0.0, 0.0, 0.0, 1.0); var end = new Quaternion(1.0, 2.0, 3.0, 1.0); var result = new Quaternion(); var actual = Quaternion.slerp(start, end, 0.0, result); expect(actual).toBe(result); expect(result).toEqual(start); }); it("log works", function () { var axis = Cartesian3.normalize( new Cartesian3(1.0, -1.0, 1.0), new Cartesian3() ); var angle = CesiumMath.PI_OVER_FOUR; var quat = Quaternion.fromAxisAngle(axis, angle); var result = new Cartesian3(); var log = Quaternion.log(quat, result); var expected = Cartesian3.multiplyByScalar( axis, angle * 0.5, new Cartesian3() ); expect(log).toBe(result); expect(log).toEqualEpsilon(expected, CesiumMath.EPSILON15); }); it("exp works", function () { var axis = Cartesian3.normalize( new Cartesian3(1.0, -1.0, 1.0), new Cartesian3() ); var angle = CesiumMath.PI_OVER_FOUR; var cartesian = Cartesian3.multiplyByScalar( axis, angle * 0.5, new Cartesian3() ); var result = new Quaternion(); var exp = Quaternion.exp(cartesian, result); var expected = Quaternion.fromAxisAngle(axis, angle); expect(exp).toBe(result); expect(exp).toEqualEpsilon(expected, CesiumMath.EPSILON15); }); it("squad and computeInnerQuadrangle work", function () { var q0 = Quaternion.fromAxisAngle(Cartesian3.UNIT_X, 0.0); var q1 = Quaternion.fromAxisAngle( Cartesian3.UNIT_X, CesiumMath.PI_OVER_FOUR ); var q2 = Quaternion.fromAxisAngle( Cartesian3.UNIT_Z, CesiumMath.PI_OVER_FOUR ); var q3 = Quaternion.fromAxisAngle( Cartesian3.UNIT_X, -CesiumMath.PI_OVER_FOUR ); var s1Result = new Quaternion(); var s1 = Quaternion.computeInnerQuadrangle(q0, q1, q2, s1Result); expect(s1).toBe(s1Result); var s2 = Quaternion.computeInnerQuadrangle(q1, q2, q3, new Quaternion()); var squadResult = new Quaternion(); var squad = Quaternion.squad(q1, q2, s1, s2, 0.0, squadResult); expect(squad).toBe(squadResult); expect(squad).toEqualEpsilon(q1, CesiumMath.EPSILON15); }); it("fastSlerp works", function () { var start = Quaternion.normalize( new Quaternion(0.0, 0.0, 0.0, 1.0), new Quaternion() ); var end = new Quaternion( 0.0, 0.0, Math.sin(CesiumMath.PI_OVER_FOUR), Math.cos(CesiumMath.PI_OVER_FOUR) ); var expected = new Quaternion( 0.0, 0.0, Math.sin(Math.PI / 8.0), Math.cos(Math.PI / 8.0) ); var result = new Quaternion(); var returnedResult = Quaternion.fastSlerp(start, end, 0.5, result); expect(result).toEqualEpsilon(expected, CesiumMath.EPSILON6); expect(result).toBe(returnedResult); }); it("fastSlerp works with a result parameter that is an input parameter", function () { var start = Quaternion.normalize( new Quaternion(0.0, 0.0, 0.0, 1.0), new Quaternion() ); var end = new Quaternion( 0.0, 0.0, Math.sin(CesiumMath.PI_OVER_FOUR), Math.cos(CesiumMath.PI_OVER_FOUR) ); var expected = new Quaternion( 0.0, 0.0, Math.sin(Math.PI / 8.0), Math.cos(Math.PI / 8.0) ); var returnedResult = Quaternion.fastSlerp(start, end, 0.5, start); expect(start).toEqualEpsilon(expected, CesiumMath.EPSILON6); expect(start).toBe(returnedResult); }); it("fastSlerp works with obtuse angles", function () { var start = Quaternion.normalize( new Quaternion(0.0, 0.0, 0.0, -1.0), new Quaternion() ); var end = new Quaternion( 0.0, 0.0, Math.sin(CesiumMath.PI_OVER_FOUR), Math.cos(CesiumMath.PI_OVER_FOUR) ); var expected = new Quaternion( 0.0, 0.0, -Math.sin(Math.PI / 8.0), -Math.cos(Math.PI / 8.0) ); expect( Quaternion.fastSlerp(start, end, 0.5, new Quaternion()) ).toEqualEpsilon(expected, CesiumMath.EPSILON6); }); it("fastSlerp vs slerp", function () { var start = Quaternion.normalize( new Quaternion(0.0, 0.0, 0.0, 1.0), new Quaternion() ); var end = new Quaternion( 0.0, 0.0, Math.sin(CesiumMath.PI_OVER_FOUR), Math.cos(CesiumMath.PI_OVER_FOUR) ); var expected = Quaternion.slerp(start, end, 0.25, new Quaternion()); var actual = Quaternion.fastSlerp(start, end, 0.25, new Quaternion()); expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON6); expected = Quaternion.slerp(start, end, 0.5, new Quaternion()); actual = Quaternion.fastSlerp(start, end, 0.5, new Quaternion()); expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON6); expected = Quaternion.slerp(start, end, 0.75, new Quaternion()); actual = Quaternion.fastSlerp(start, end, 0.75, new Quaternion()); expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON6); }); it("fastSquad works", function () { var q0 = Quaternion.fromAxisAngle(Cartesian3.UNIT_X, 0.0); var q1 = Quaternion.fromAxisAngle( Cartesian3.UNIT_X, CesiumMath.PI_OVER_FOUR ); var q2 = Quaternion.fromAxisAngle( Cartesian3.UNIT_Z, CesiumMath.PI_OVER_FOUR ); var q3 = Quaternion.fromAxisAngle( Cartesian3.UNIT_X, -CesiumMath.PI_OVER_FOUR ); var s1 = Quaternion.computeInnerQuadrangle(q0, q1, q2, new Quaternion()); var s2 = Quaternion.computeInnerQuadrangle(q1, q2, q3, new Quaternion()); var squadResult = new Quaternion(); var squad = Quaternion.fastSquad(q1, q2, s1, s2, 0.0, squadResult); expect(squad).toBe(squadResult); expect(squad).toEqualEpsilon(q1, CesiumMath.EPSILON6); }); it("fastSquad vs squad", function () { var q0 = Quaternion.fromAxisAngle(Cartesian3.UNIT_X, 0.0); var q1 = Quaternion.fromAxisAngle( Cartesian3.UNIT_X, CesiumMath.PI_OVER_FOUR ); var q2 = Quaternion.fromAxisAngle( Cartesian3.UNIT_Z, CesiumMath.PI_OVER_FOUR ); var q3 = Quaternion.fromAxisAngle( Cartesian3.UNIT_X, -CesiumMath.PI_OVER_FOUR ); var s1 = Quaternion.computeInnerQuadrangle(q0, q1, q2, new Quaternion()); var s2 = Quaternion.computeInnerQuadrangle(q1, q2, q3, new Quaternion()); var actual = Quaternion.fastSquad(q1, q2, s1, s2, 0.25, new Quaternion()); var expected = Quaternion.squad(q1, q2, s1, s2, 0.25, new Quaternion()); expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON6); actual = Quaternion.fastSquad(q1, q2, s1, s2, 0.5, new Quaternion()); expected = Quaternion.squad(q1, q2, s1, s2, 0.5, new Quaternion()); expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON6); actual = Quaternion.fastSquad(q1, q2, s1, s2, 0.75, new Quaternion()); expected = Quaternion.squad(q1, q2, s1, s2, 0.75, new Quaternion()); expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON6); }); it("equals", function () { var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); expect( Quaternion.equals(quaternion, new Quaternion(1.0, 2.0, 3.0, 4.0)) ).toEqual(true); expect( Quaternion.equals(quaternion, new Quaternion(2.0, 2.0, 3.0, 4.0)) ).toEqual(false); expect( Quaternion.equals(quaternion, new Quaternion(2.0, 1.0, 3.0, 4.0)) ).toEqual(false); expect( Quaternion.equals(quaternion, new Quaternion(1.0, 2.0, 4.0, 4.0)) ).toEqual(false); expect( Quaternion.equals(quaternion, new Quaternion(1.0, 2.0, 3.0, 5.0)) ).toEqual(false); expect(Quaternion.equals(quaternion, undefined)).toEqual(false); }); it("equalsEpsilon", function () { var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); expect( Quaternion.equalsEpsilon( quaternion, new Quaternion(1.0, 2.0, 3.0, 4.0), 0.0 ) ).toEqual(true); expect( Quaternion.equalsEpsilon( quaternion, new Quaternion(1.0, 2.0, 3.0, 4.0), 1.0 ) ).toEqual(true); expect( Quaternion.equalsEpsilon( quaternion, new Quaternion(2.0, 2.0, 3.0, 4.0), 1.0 ) ).toEqual(true); expect( Quaternion.equalsEpsilon( quaternion, new Quaternion(1.0, 3.0, 3.0, 4.0), 1.0 ) ).toEqual(true); expect( Quaternion.equalsEpsilon( quaternion, new Quaternion(1.0, 2.0, 4.0, 4.0), 1.0 ) ).toEqual(true); expect( Quaternion.equalsEpsilon( quaternion, new Quaternion(1.0, 2.0, 3.0, 5.0), 1.0 ) ).toEqual(true); expect( Quaternion.equalsEpsilon( quaternion, new Quaternion(2.0, 2.0, 3.0, 4.0), 0.99999 ) ).toEqual(false); expect( Quaternion.equalsEpsilon( quaternion, new Quaternion(1.0, 3.0, 3.0, 4.0), 0.99999 ) ).toEqual(false); expect( Quaternion.equalsEpsilon( quaternion, new Quaternion(1.0, 2.0, 4.0, 4.0), 0.99999 ) ).toEqual(false); expect( Quaternion.equalsEpsilon( quaternion, new Quaternion(1.0, 2.0, 3.0, 5.0), 0.99999 ) ).toEqual(false); expect(Quaternion.equalsEpsilon(quaternion, undefined, 1)).toEqual(false); }); it("toString", function () { var quaternion = new Quaternion(1.123, 2.345, 6.789, 6.123); expect(quaternion.toString()).toEqual("(1.123, 2.345, 6.789, 6.123)"); }); it("fromAxisAngle throws with undefined axis", function () { expect(function () { Quaternion.fromAxisAngle(undefined, 1.0); }).toThrowDeveloperError(); }); it("fromAxisAngle throws with non-numeric angle", function () { expect(function () { Quaternion.fromAxisAngle(Cartesian3.UNIT_X, {}); }).toThrowDeveloperError(); }); it("fromRotationMatrix throws with undefined matrix", function () { expect(function () { Quaternion.fromRotationMatrix(undefined); }).toThrowDeveloperError(); }); it("clone returns undefined with no parameter", function () { expect(Quaternion.clone()).toBeUndefined(); }); it("conjugate throws with no parameter", function () { expect(function () { Quaternion.conjugate(); }).toThrowDeveloperError(); }); it("magnitudeSquared throws with no parameter", function () { expect(function () { Quaternion.magnitudeSquared(); }).toThrowDeveloperError(); }); it("magnitude throws with no parameter", function () { expect(function () { Quaternion.magnitude(); }).toThrowDeveloperError(); }); it("normalize throws with no parameter", function () { expect(function () { Quaternion.normalize(); }).toThrowDeveloperError(); }); it("inverse throws with no parameter", function () { expect(function () { Quaternion.inverse(); }).toThrowDeveloperError(); }); it("dot throws with no left parameter", function () { expect(function () { Quaternion.dot(undefined, new Quaternion()); }).toThrowDeveloperError(); }); it("dot throws with no right parameter", function () { expect(function () { Quaternion.dot(new Quaternion(), undefined); }).toThrowDeveloperError(); }); it("multiply throws with no right parameter", function () { expect(function () { Quaternion.multiply(new Quaternion(), undefined); }).toThrowDeveloperError(); }); it("multiply throws with no left parameter", function () { expect(function () { Quaternion.multiply(undefined, new Quaternion()); }).toThrowDeveloperError(); }); it("add throws with no left parameter", function () { expect(function () { Quaternion.add(undefined, new Quaternion()); }).toThrowDeveloperError(); }); it("add throws with no right parameter", function () { expect(function () { Quaternion.add(new Quaternion(), undefined); }).toThrowDeveloperError(); }); it("subtract throws with no left parameter", function () { expect(function () { Quaternion.subtract(undefined, new Quaternion()); }).toThrowDeveloperError(); }); it("subtract throws with no right parameter", function () { expect(function () { Quaternion.subtract(new Quaternion(), undefined); }).toThrowDeveloperError(); }); it("multiplyByScalar throws with no quaternion parameter", function () { expect(function () { Quaternion.multiplyByScalar(undefined, 2.0); }).toThrowDeveloperError(); }); it("multiplyByScalar throws with no scalar parameter", function () { expect(function () { Quaternion.multiplyByScalar(new Quaternion(), undefined); }).toThrowDeveloperError(); }); it("divideByScalar throws with no quaternion parameter", function () { expect(function () { Quaternion.divideByScalar(undefined, 2.0); }).toThrowDeveloperError(); }); it("divideByScalar throws with no scalar parameter", function () { expect(function () { Quaternion.divideByScalar(new Quaternion(), undefined); }).toThrowDeveloperError(); }); it("axis throws with no parameter", function () { expect(function () { Quaternion.computeAxis(undefined); }).toThrowDeveloperError(); }); it("angle throws with no parameter", function () { expect(function () { Quaternion.computeAngle(undefined); }).toThrowDeveloperError(); }); it("negate throws with no quaternion parameter", function () { expect(function () { Quaternion.negate(undefined); }).toThrowDeveloperError(); }); it("lerp throws with no start parameter", function () { var end = new Quaternion(8.0, 20.0, 6.0); var t = 0.25; expect(function () { Quaternion.lerp(undefined, end, t); }).toThrowDeveloperError(); }); it("lerp throws with no end parameter", function () { var start = new Quaternion(4.0, 8.0, 6.0); var t = 0.25; expect(function () { Quaternion.lerp(start, undefined, t); }).toThrowDeveloperError(); }); it("lerp throws with no t parameter", function () { var start = new Quaternion(4.0, 8.0, 6.0, 7.0); var end = new Quaternion(8.0, 20.0, 6.0, 7.0); expect(function () { Quaternion.lerp(start, end, undefined); }).toThrowDeveloperError(); }); it("slerp throws with no start parameter", function () { var end = new Quaternion(8.0, 20.0, 6.0); var t = 0.25; expect(function () { Quaternion.slerp(undefined, end, t); }).toThrowDeveloperError(); }); it("slerp throws with no end parameter", function () { var start = new Quaternion(4.0, 8.0, 6.0); var t = 0.25; expect(function () { Quaternion.slerp(start, undefined, t); }).toThrowDeveloperError(); }); it("slerp throws with no t parameter", function () { var start = new Quaternion(4.0, 8.0, 6.0, 7.0); var end = new Quaternion(8.0, 20.0, 6.0, 7.0); expect(function () { Quaternion.slerp(start, end, undefined); }).toThrowDeveloperError(); }); it("log throws with no quaternion parameter", function () { expect(function () { Quaternion.log(); }).toThrowDeveloperError(); }); it("exp throws with no cartesian parameter", function () { expect(function () { Quaternion.exp(); }).toThrowDeveloperError(); }); it("computeInnerQuadrangle throws without q0, q1, or q2 parameter", function () { expect(function () { Quaternion.computeInnerQuadrangle(); }).toThrowDeveloperError(); }); it("squad throws without q0, q1, s0, or s1 parameter", function () { expect(function () { Quaternion.squad(); }).toThrowDeveloperError(); }); it("squad throws without t parameter", function () { expect(function () { Quaternion.squad( new Quaternion(), new Quaternion(), new Quaternion(), new Quaternion() ); }).toThrowDeveloperError(); }); it("conjugate throws with no result", function () { expect(function () { Quaternion.conjugate(new Quaternion()); }).toThrowDeveloperError(); }); it("add throws with no result", function () { expect(function () { Quaternion.add(new Quaternion(), new Quaternion()); }).toThrowDeveloperError(); }); it("subtract throws with no result", function () { expect(function () { Quaternion.subtract(new Quaternion(), new Quaternion()); }).toThrowDeveloperError(); }); it("negate throws with no result", function () { expect(function () { Quaternion.negate(new Quaternion()); }).toThrowDeveloperError(); }); it("multiply throws with no result", function () { expect(function () { Quaternion.multiply(new Quaternion(), new Quaternion()); }).toThrowDeveloperError(); }); it("multiplyByScalar throws with no result", function () { expect(function () { Quaternion.multiplyByScalar(new Quaternion(), 3); }).toThrowDeveloperError(); }); it("divideByScalar throws with no result", function () { expect(function () { Quaternion.divideByScalar(new Quaternion(), 3); }).toThrowDeveloperError(); }); it("axis throws with no result", function () { expect(function () { Quaternion.computeAxis(new Quaternion()); }).toThrowDeveloperError(); }); it("lerp throws with no result", function () { expect(function () { Quaternion.lerp(new Quaternion(), new Quaternion(), 2); }).toThrowDeveloperError(); }); it("slerp throws with no result", function () { expect(function () { Quaternion.slerp(new Quaternion(), new Quaternion(), 2); }).toThrowDeveloperError(); }); it("log throws with no result", function () { expect(function () { Quaternion.log(new Quaternion()); }).toThrowDeveloperError(); }); it("exp throws with no result", function () { expect(function () { Quaternion.exp(new Cartesian3()); }).toThrowDeveloperError(); }); it("computeInnerQuadrangle throws with no result", function () { expect(function () { Quaternion.computeInnerQuadrangle( new Quaternion(), new Quaternion(), new Quaternion() ); }).toThrowDeveloperError(); }); it("squad throws with no result", function () { expect(function () { Quaternion.squad( new Quaternion(), new Quaternion(), new Quaternion(), new Quaternion(), 3 ); }).toThrowDeveloperError(); }); it("fastSlerp throws with no start", function () { expect(function () { Quaternion.fastSlerp(); }).toThrowDeveloperError(); }); it("fastSlerp throws with no end", function () { expect(function () { Quaternion.fastSlerp(new Quaternion()); }).toThrowDeveloperError(); }); it("fastSlerp throws with no t", function () { expect(function () { Quaternion.fastSlerp(new Quaternion(), new Quaternion()); }).toThrowDeveloperError(); }); it("fastSlerp throws with no result", function () { expect(function () { Quaternion.fastSlerp(new Quaternion(), new Quaternion(), 2); }).toThrowDeveloperError(); }); it("fastSquad throws with no q0", function () { expect(function () { Quaternion.fastSquad(); }).toThrowDeveloperError(); }); it("fastSquad throws with no q1", function () { expect(function () { Quaternion.fastSquad(new Quaternion()); }).toThrowDeveloperError(); }); it("fastSquad throws with no s0", function () { expect(function () { Quaternion.fastSquad(new Quaternion(), new Quaternion()); }).toThrowDeveloperError(); }); it("fastSquad throws with no s1", function () { expect(function () { Quaternion.fastSquad( new Quaternion(), new Quaternion(), new Quaternion() ); }).toThrowDeveloperError(); }); it("fastSquad throws with no t", function () { expect(function () { Quaternion.fastSquad( new Quaternion(), new Quaternion(), new Quaternion(), new Quaternion() ); }).toThrowDeveloperError(); }); it("fastSquad throws with no result", function () { expect(function () { Quaternion.fastSquad( new Quaternion(), new Quaternion(), new Quaternion(), new Quaternion(), 3 ); }).toThrowDeveloperError(); }); var q = new Quaternion(1, 2, 3, 4); Quaternion.normalize(q, q); createPackableSpecs(Quaternion, q, [q.x, q.y, q.z, q.w]); });