1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141 |
- import Cartesian3 from "./Cartesian3.js";
- import Check from "./Check.js";
- import defaultValue from "./defaultValue.js";
- import defined from "./defined.js";
- import FeatureDetection from "./FeatureDetection.js";
- import CesiumMath from "./Math.js";
- import Matrix3 from "./Matrix3.js";
- /**
- * A set of 4-dimensional coordinates used to represent rotation in 3-dimensional space.
- * @alias Quaternion
- * @constructor
- *
- * @param {Number} [x=0.0] The X component.
- * @param {Number} [y=0.0] The Y component.
- * @param {Number} [z=0.0] The Z component.
- * @param {Number} [w=0.0] The W component.
- *
- * @see PackableForInterpolation
- */
- function Quaternion(x, y, z, w) {
- /**
- * The X component.
- * @type {Number}
- * @default 0.0
- */
- this.x = defaultValue(x, 0.0);
- /**
- * The Y component.
- * @type {Number}
- * @default 0.0
- */
- this.y = defaultValue(y, 0.0);
- /**
- * The Z component.
- * @type {Number}
- * @default 0.0
- */
- this.z = defaultValue(z, 0.0);
- /**
- * The W component.
- * @type {Number}
- * @default 0.0
- */
- this.w = defaultValue(w, 0.0);
- }
- let fromAxisAngleScratch = new Cartesian3();
- /**
- * Computes a quaternion representing a rotation around an axis.
- *
- * @param {Cartesian3} axis The axis of rotation.
- * @param {Number} angle The angle in radians to rotate around the axis.
- * @param {Quaternion} [result] The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
- */
- Quaternion.fromAxisAngle = function (axis, angle, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("axis", axis);
- Check.typeOf.number("angle", angle);
- //>>includeEnd('debug');
- const halfAngle = angle / 2.0;
- const s = Math.sin(halfAngle);
- fromAxisAngleScratch = Cartesian3.normalize(axis, fromAxisAngleScratch);
- const x = fromAxisAngleScratch.x * s;
- const y = fromAxisAngleScratch.y * s;
- const z = fromAxisAngleScratch.z * s;
- const w = Math.cos(halfAngle);
- if (!defined(result)) {
- return new Quaternion(x, y, z, w);
- }
- result.x = x;
- result.y = y;
- result.z = z;
- result.w = w;
- return result;
- };
- const fromRotationMatrixNext = [1, 2, 0];
- const fromRotationMatrixQuat = new Array(3);
- /**
- * Computes a Quaternion from the provided Matrix3 instance.
- *
- * @param {Matrix3} matrix The rotation matrix.
- * @param {Quaternion} [result] The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
- *
- * @see Matrix3.fromQuaternion
- */
- Quaternion.fromRotationMatrix = function (matrix, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("matrix", matrix);
- //>>includeEnd('debug');
- let root;
- let x;
- let y;
- let z;
- let w;
- const m00 = matrix[Matrix3.COLUMN0ROW0];
- const m11 = matrix[Matrix3.COLUMN1ROW1];
- const m22 = matrix[Matrix3.COLUMN2ROW2];
- const trace = m00 + m11 + m22;
- if (trace > 0.0) {
- // |w| > 1/2, may as well choose w > 1/2
- root = Math.sqrt(trace + 1.0); // 2w
- w = 0.5 * root;
- root = 0.5 / root; // 1/(4w)
- x = (matrix[Matrix3.COLUMN1ROW2] - matrix[Matrix3.COLUMN2ROW1]) * root;
- y = (matrix[Matrix3.COLUMN2ROW0] - matrix[Matrix3.COLUMN0ROW2]) * root;
- z = (matrix[Matrix3.COLUMN0ROW1] - matrix[Matrix3.COLUMN1ROW0]) * root;
- } else {
- // |w| <= 1/2
- const next = fromRotationMatrixNext;
- let i = 0;
- if (m11 > m00) {
- i = 1;
- }
- if (m22 > m00 && m22 > m11) {
- i = 2;
- }
- const j = next[i];
- const k = next[j];
- root = Math.sqrt(
- matrix[Matrix3.getElementIndex(i, i)] -
- matrix[Matrix3.getElementIndex(j, j)] -
- matrix[Matrix3.getElementIndex(k, k)] +
- 1.0
- );
- const quat = fromRotationMatrixQuat;
- quat[i] = 0.5 * root;
- root = 0.5 / root;
- w =
- (matrix[Matrix3.getElementIndex(k, j)] -
- matrix[Matrix3.getElementIndex(j, k)]) *
- root;
- quat[j] =
- (matrix[Matrix3.getElementIndex(j, i)] +
- matrix[Matrix3.getElementIndex(i, j)]) *
- root;
- quat[k] =
- (matrix[Matrix3.getElementIndex(k, i)] +
- matrix[Matrix3.getElementIndex(i, k)]) *
- root;
- x = -quat[0];
- y = -quat[1];
- z = -quat[2];
- }
- if (!defined(result)) {
- return new Quaternion(x, y, z, w);
- }
- result.x = x;
- result.y = y;
- result.z = z;
- result.w = w;
- return result;
- };
- const scratchHPRQuaternion = new Quaternion();
- let scratchHeadingQuaternion = new Quaternion();
- let scratchPitchQuaternion = new Quaternion();
- let scratchRollQuaternion = new Quaternion();
- /**
- * Computes a rotation from the given heading, pitch and roll angles. Heading is the rotation about the
- * negative z axis. Pitch is the rotation about the negative y axis. Roll is the rotation about
- * the positive x axis.
- *
- * @param {HeadingPitchRoll} headingPitchRoll The rotation expressed as a heading, pitch and roll.
- * @param {Quaternion} [result] The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter or a new Quaternion instance if none was provided.
- */
- Quaternion.fromHeadingPitchRoll = function (headingPitchRoll, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("headingPitchRoll", headingPitchRoll);
- //>>includeEnd('debug');
- scratchRollQuaternion = Quaternion.fromAxisAngle(
- Cartesian3.UNIT_X,
- headingPitchRoll.roll,
- scratchHPRQuaternion
- );
- scratchPitchQuaternion = Quaternion.fromAxisAngle(
- Cartesian3.UNIT_Y,
- -headingPitchRoll.pitch,
- result
- );
- result = Quaternion.multiply(
- scratchPitchQuaternion,
- scratchRollQuaternion,
- scratchPitchQuaternion
- );
- scratchHeadingQuaternion = Quaternion.fromAxisAngle(
- Cartesian3.UNIT_Z,
- -headingPitchRoll.heading,
- scratchHPRQuaternion
- );
- return Quaternion.multiply(scratchHeadingQuaternion, result, result);
- };
- const sampledQuaternionAxis = new Cartesian3();
- const sampledQuaternionRotation = new Cartesian3();
- const sampledQuaternionTempQuaternion = new Quaternion();
- const sampledQuaternionQuaternion0 = new Quaternion();
- const sampledQuaternionQuaternion0Conjugate = new Quaternion();
- /**
- * The number of elements used to pack the object into an array.
- * @type {Number}
- */
- Quaternion.packedLength = 4;
- /**
- * Stores the provided instance into the provided array.
- *
- * @param {Quaternion} value The value to pack.
- * @param {Number[]} array The array to pack into.
- * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
- *
- * @returns {Number[]} The array that was packed into
- */
- Quaternion.pack = function (value, array, startingIndex) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("value", value);
- Check.defined("array", array);
- //>>includeEnd('debug');
- startingIndex = defaultValue(startingIndex, 0);
- array[startingIndex++] = value.x;
- array[startingIndex++] = value.y;
- array[startingIndex++] = value.z;
- array[startingIndex] = value.w;
- return array;
- };
- /**
- * Retrieves an instance from a packed array.
- *
- * @param {Number[]} array The packed array.
- * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
- * @param {Quaternion} [result] The object into which to store the result.
- * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
- */
- Quaternion.unpack = function (array, startingIndex, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined("array", array);
- //>>includeEnd('debug');
- startingIndex = defaultValue(startingIndex, 0);
- if (!defined(result)) {
- result = new Quaternion();
- }
- result.x = array[startingIndex];
- result.y = array[startingIndex + 1];
- result.z = array[startingIndex + 2];
- result.w = array[startingIndex + 3];
- return result;
- };
- /**
- * The number of elements used to store the object into an array in its interpolatable form.
- * @type {Number}
- */
- Quaternion.packedInterpolationLength = 3;
- /**
- * Converts a packed array into a form suitable for interpolation.
- *
- * @param {Number[]} packedArray The packed array.
- * @param {Number} [startingIndex=0] The index of the first element to be converted.
- * @param {Number} [lastIndex=packedArray.length] The index of the last element to be converted.
- * @param {Number[]} [result] The object into which to store the result.
- */
- Quaternion.convertPackedArrayForInterpolation = function (
- packedArray,
- startingIndex,
- lastIndex,
- result
- ) {
- Quaternion.unpack(
- packedArray,
- lastIndex * 4,
- sampledQuaternionQuaternion0Conjugate
- );
- Quaternion.conjugate(
- sampledQuaternionQuaternion0Conjugate,
- sampledQuaternionQuaternion0Conjugate
- );
- for (let i = 0, len = lastIndex - startingIndex + 1; i < len; i++) {
- const offset = i * 3;
- Quaternion.unpack(
- packedArray,
- (startingIndex + i) * 4,
- sampledQuaternionTempQuaternion
- );
- Quaternion.multiply(
- sampledQuaternionTempQuaternion,
- sampledQuaternionQuaternion0Conjugate,
- sampledQuaternionTempQuaternion
- );
- if (sampledQuaternionTempQuaternion.w < 0) {
- Quaternion.negate(
- sampledQuaternionTempQuaternion,
- sampledQuaternionTempQuaternion
- );
- }
- Quaternion.computeAxis(
- sampledQuaternionTempQuaternion,
- sampledQuaternionAxis
- );
- const angle = Quaternion.computeAngle(sampledQuaternionTempQuaternion);
- if (!defined(result)) {
- result = [];
- }
- result[offset] = sampledQuaternionAxis.x * angle;
- result[offset + 1] = sampledQuaternionAxis.y * angle;
- result[offset + 2] = sampledQuaternionAxis.z * angle;
- }
- };
- /**
- * Retrieves an instance from a packed array converted with {@link convertPackedArrayForInterpolation}.
- *
- * @param {Number[]} array The array previously packed for interpolation.
- * @param {Number[]} sourceArray The original packed array.
- * @param {Number} [firstIndex=0] The firstIndex used to convert the array.
- * @param {Number} [lastIndex=packedArray.length] The lastIndex used to convert the array.
- * @param {Quaternion} [result] The object into which to store the result.
- * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
- */
- Quaternion.unpackInterpolationResult = function (
- array,
- sourceArray,
- firstIndex,
- lastIndex,
- result
- ) {
- if (!defined(result)) {
- result = new Quaternion();
- }
- Cartesian3.fromArray(array, 0, sampledQuaternionRotation);
- const magnitude = Cartesian3.magnitude(sampledQuaternionRotation);
- Quaternion.unpack(sourceArray, lastIndex * 4, sampledQuaternionQuaternion0);
- if (magnitude === 0) {
- Quaternion.clone(Quaternion.IDENTITY, sampledQuaternionTempQuaternion);
- } else {
- Quaternion.fromAxisAngle(
- sampledQuaternionRotation,
- magnitude,
- sampledQuaternionTempQuaternion
- );
- }
- return Quaternion.multiply(
- sampledQuaternionTempQuaternion,
- sampledQuaternionQuaternion0,
- result
- );
- };
- /**
- * Duplicates a Quaternion instance.
- *
- * @param {Quaternion} quaternion The quaternion to duplicate.
- * @param {Quaternion} [result] The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided. (Returns undefined if quaternion is undefined)
- */
- Quaternion.clone = function (quaternion, result) {
- if (!defined(quaternion)) {
- return undefined;
- }
- if (!defined(result)) {
- return new Quaternion(
- quaternion.x,
- quaternion.y,
- quaternion.z,
- quaternion.w
- );
- }
- result.x = quaternion.x;
- result.y = quaternion.y;
- result.z = quaternion.z;
- result.w = quaternion.w;
- return result;
- };
- /**
- * Computes the conjugate of the provided quaternion.
- *
- * @param {Quaternion} quaternion The quaternion to conjugate.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- */
- Quaternion.conjugate = function (quaternion, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("quaternion", quaternion);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- result.x = -quaternion.x;
- result.y = -quaternion.y;
- result.z = -quaternion.z;
- result.w = quaternion.w;
- return result;
- };
- /**
- * Computes magnitude squared for the provided quaternion.
- *
- * @param {Quaternion} quaternion The quaternion to conjugate.
- * @returns {Number} The magnitude squared.
- */
- Quaternion.magnitudeSquared = function (quaternion) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("quaternion", quaternion);
- //>>includeEnd('debug');
- return (
- quaternion.x * quaternion.x +
- quaternion.y * quaternion.y +
- quaternion.z * quaternion.z +
- quaternion.w * quaternion.w
- );
- };
- /**
- * Computes magnitude for the provided quaternion.
- *
- * @param {Quaternion} quaternion The quaternion to conjugate.
- * @returns {Number} The magnitude.
- */
- Quaternion.magnitude = function (quaternion) {
- return Math.sqrt(Quaternion.magnitudeSquared(quaternion));
- };
- /**
- * Computes the normalized form of the provided quaternion.
- *
- * @param {Quaternion} quaternion The quaternion to normalize.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- */
- Quaternion.normalize = function (quaternion, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- const inverseMagnitude = 1.0 / Quaternion.magnitude(quaternion);
- const x = quaternion.x * inverseMagnitude;
- const y = quaternion.y * inverseMagnitude;
- const z = quaternion.z * inverseMagnitude;
- const w = quaternion.w * inverseMagnitude;
- result.x = x;
- result.y = y;
- result.z = z;
- result.w = w;
- return result;
- };
- /**
- * Computes the inverse of the provided quaternion.
- *
- * @param {Quaternion} quaternion The quaternion to normalize.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- */
- Quaternion.inverse = function (quaternion, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- const magnitudeSquared = Quaternion.magnitudeSquared(quaternion);
- result = Quaternion.conjugate(quaternion, result);
- return Quaternion.multiplyByScalar(result, 1.0 / magnitudeSquared, result);
- };
- /**
- * Computes the componentwise sum of two quaternions.
- *
- * @param {Quaternion} left The first quaternion.
- * @param {Quaternion} right The second quaternion.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- */
- Quaternion.add = function (left, right, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("left", left);
- Check.typeOf.object("right", right);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- result.x = left.x + right.x;
- result.y = left.y + right.y;
- result.z = left.z + right.z;
- result.w = left.w + right.w;
- return result;
- };
- /**
- * Computes the componentwise difference of two quaternions.
- *
- * @param {Quaternion} left The first quaternion.
- * @param {Quaternion} right The second quaternion.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- */
- Quaternion.subtract = function (left, right, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("left", left);
- Check.typeOf.object("right", right);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- result.x = left.x - right.x;
- result.y = left.y - right.y;
- result.z = left.z - right.z;
- result.w = left.w - right.w;
- return result;
- };
- /**
- * Negates the provided quaternion.
- *
- * @param {Quaternion} quaternion The quaternion to be negated.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- */
- Quaternion.negate = function (quaternion, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("quaternion", quaternion);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- result.x = -quaternion.x;
- result.y = -quaternion.y;
- result.z = -quaternion.z;
- result.w = -quaternion.w;
- return result;
- };
- /**
- * Computes the dot (scalar) product of two quaternions.
- *
- * @param {Quaternion} left The first quaternion.
- * @param {Quaternion} right The second quaternion.
- * @returns {Number} The dot product.
- */
- Quaternion.dot = function (left, right) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("left", left);
- Check.typeOf.object("right", right);
- //>>includeEnd('debug');
- return (
- left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w
- );
- };
- /**
- * Computes the product of two quaternions.
- *
- * @param {Quaternion} left The first quaternion.
- * @param {Quaternion} right The second quaternion.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- */
- Quaternion.multiply = function (left, right, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("left", left);
- Check.typeOf.object("right", right);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- const leftX = left.x;
- const leftY = left.y;
- const leftZ = left.z;
- const leftW = left.w;
- const rightX = right.x;
- const rightY = right.y;
- const rightZ = right.z;
- const rightW = right.w;
- const x = leftW * rightX + leftX * rightW + leftY * rightZ - leftZ * rightY;
- const y = leftW * rightY - leftX * rightZ + leftY * rightW + leftZ * rightX;
- const z = leftW * rightZ + leftX * rightY - leftY * rightX + leftZ * rightW;
- const w = leftW * rightW - leftX * rightX - leftY * rightY - leftZ * rightZ;
- result.x = x;
- result.y = y;
- result.z = z;
- result.w = w;
- return result;
- };
- /**
- * Multiplies the provided quaternion componentwise by the provided scalar.
- *
- * @param {Quaternion} quaternion The quaternion to be scaled.
- * @param {Number} scalar The scalar to multiply with.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- */
- Quaternion.multiplyByScalar = function (quaternion, scalar, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("quaternion", quaternion);
- Check.typeOf.number("scalar", scalar);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- result.x = quaternion.x * scalar;
- result.y = quaternion.y * scalar;
- result.z = quaternion.z * scalar;
- result.w = quaternion.w * scalar;
- return result;
- };
- /**
- * Divides the provided quaternion componentwise by the provided scalar.
- *
- * @param {Quaternion} quaternion The quaternion to be divided.
- * @param {Number} scalar The scalar to divide by.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- */
- Quaternion.divideByScalar = function (quaternion, scalar, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("quaternion", quaternion);
- Check.typeOf.number("scalar", scalar);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- result.x = quaternion.x / scalar;
- result.y = quaternion.y / scalar;
- result.z = quaternion.z / scalar;
- result.w = quaternion.w / scalar;
- return result;
- };
- /**
- * Computes the axis of rotation of the provided quaternion.
- *
- * @param {Quaternion} quaternion The quaternion to use.
- * @param {Cartesian3} result The object onto which to store the result.
- * @returns {Cartesian3} The modified result parameter.
- */
- Quaternion.computeAxis = function (quaternion, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("quaternion", quaternion);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- const w = quaternion.w;
- if (Math.abs(w - 1.0) < CesiumMath.EPSILON6) {
- result.x = result.y = result.z = 0;
- return result;
- }
- const scalar = 1.0 / Math.sqrt(1.0 - w * w);
- result.x = quaternion.x * scalar;
- result.y = quaternion.y * scalar;
- result.z = quaternion.z * scalar;
- return result;
- };
- /**
- * Computes the angle of rotation of the provided quaternion.
- *
- * @param {Quaternion} quaternion The quaternion to use.
- * @returns {Number} The angle of rotation.
- */
- Quaternion.computeAngle = function (quaternion) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("quaternion", quaternion);
- //>>includeEnd('debug');
- if (Math.abs(quaternion.w - 1.0) < CesiumMath.EPSILON6) {
- return 0.0;
- }
- return 2.0 * Math.acos(quaternion.w);
- };
- let lerpScratch = new Quaternion();
- /**
- * Computes the linear interpolation or extrapolation at t using the provided quaternions.
- *
- * @param {Quaternion} start The value corresponding to t at 0.0.
- * @param {Quaternion} end The value corresponding to t at 1.0.
- * @param {Number} t The point along t at which to interpolate.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- */
- Quaternion.lerp = function (start, end, t, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("start", start);
- Check.typeOf.object("end", end);
- Check.typeOf.number("t", t);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- lerpScratch = Quaternion.multiplyByScalar(end, t, lerpScratch);
- result = Quaternion.multiplyByScalar(start, 1.0 - t, result);
- return Quaternion.add(lerpScratch, result, result);
- };
- let slerpEndNegated = new Quaternion();
- let slerpScaledP = new Quaternion();
- let slerpScaledR = new Quaternion();
- /**
- * Computes the spherical linear interpolation or extrapolation at t using the provided quaternions.
- *
- * @param {Quaternion} start The value corresponding to t at 0.0.
- * @param {Quaternion} end The value corresponding to t at 1.0.
- * @param {Number} t The point along t at which to interpolate.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- *
- * @see Quaternion#fastSlerp
- */
- Quaternion.slerp = function (start, end, t, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("start", start);
- Check.typeOf.object("end", end);
- Check.typeOf.number("t", t);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- let dot = Quaternion.dot(start, end);
- // The angle between start must be acute. Since q and -q represent
- // the same rotation, negate q to get the acute angle.
- let r = end;
- if (dot < 0.0) {
- dot = -dot;
- r = slerpEndNegated = Quaternion.negate(end, slerpEndNegated);
- }
- // dot > 0, as the dot product approaches 1, the angle between the
- // quaternions vanishes. use linear interpolation.
- if (1.0 - dot < CesiumMath.EPSILON6) {
- return Quaternion.lerp(start, r, t, result);
- }
- const theta = Math.acos(dot);
- slerpScaledP = Quaternion.multiplyByScalar(
- start,
- Math.sin((1 - t) * theta),
- slerpScaledP
- );
- slerpScaledR = Quaternion.multiplyByScalar(
- r,
- Math.sin(t * theta),
- slerpScaledR
- );
- result = Quaternion.add(slerpScaledP, slerpScaledR, result);
- return Quaternion.multiplyByScalar(result, 1.0 / Math.sin(theta), result);
- };
- /**
- * The logarithmic quaternion function.
- *
- * @param {Quaternion} quaternion The unit quaternion.
- * @param {Cartesian3} result The object onto which to store the result.
- * @returns {Cartesian3} The modified result parameter.
- */
- Quaternion.log = function (quaternion, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("quaternion", quaternion);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- const theta = CesiumMath.acosClamped(quaternion.w);
- let thetaOverSinTheta = 0.0;
- if (theta !== 0.0) {
- thetaOverSinTheta = theta / Math.sin(theta);
- }
- return Cartesian3.multiplyByScalar(quaternion, thetaOverSinTheta, result);
- };
- /**
- * The exponential quaternion function.
- *
- * @param {Cartesian3} cartesian The cartesian.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- */
- Quaternion.exp = function (cartesian, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("cartesian", cartesian);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- const theta = Cartesian3.magnitude(cartesian);
- let sinThetaOverTheta = 0.0;
- if (theta !== 0.0) {
- sinThetaOverTheta = Math.sin(theta) / theta;
- }
- result.x = cartesian.x * sinThetaOverTheta;
- result.y = cartesian.y * sinThetaOverTheta;
- result.z = cartesian.z * sinThetaOverTheta;
- result.w = Math.cos(theta);
- return result;
- };
- const squadScratchCartesian0 = new Cartesian3();
- const squadScratchCartesian1 = new Cartesian3();
- const squadScratchQuaternion0 = new Quaternion();
- const squadScratchQuaternion1 = new Quaternion();
- /**
- * Computes an inner quadrangle point.
- * <p>This will compute quaternions that ensure a squad curve is C<sup>1</sup>.</p>
- *
- * @param {Quaternion} q0 The first quaternion.
- * @param {Quaternion} q1 The second quaternion.
- * @param {Quaternion} q2 The third quaternion.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- *
- * @see Quaternion#squad
- */
- Quaternion.computeInnerQuadrangle = function (q0, q1, q2, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("q0", q0);
- Check.typeOf.object("q1", q1);
- Check.typeOf.object("q2", q2);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- const qInv = Quaternion.conjugate(q1, squadScratchQuaternion0);
- Quaternion.multiply(qInv, q2, squadScratchQuaternion1);
- const cart0 = Quaternion.log(squadScratchQuaternion1, squadScratchCartesian0);
- Quaternion.multiply(qInv, q0, squadScratchQuaternion1);
- const cart1 = Quaternion.log(squadScratchQuaternion1, squadScratchCartesian1);
- Cartesian3.add(cart0, cart1, cart0);
- Cartesian3.multiplyByScalar(cart0, 0.25, cart0);
- Cartesian3.negate(cart0, cart0);
- Quaternion.exp(cart0, squadScratchQuaternion0);
- return Quaternion.multiply(q1, squadScratchQuaternion0, result);
- };
- /**
- * Computes the spherical quadrangle interpolation between quaternions.
- *
- * @param {Quaternion} q0 The first quaternion.
- * @param {Quaternion} q1 The second quaternion.
- * @param {Quaternion} s0 The first inner quadrangle.
- * @param {Quaternion} s1 The second inner quadrangle.
- * @param {Number} t The time in [0,1] used to interpolate.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- *
- *
- * @example
- * // 1. compute the squad interpolation between two quaternions on a curve
- * const s0 = Cesium.Quaternion.computeInnerQuadrangle(quaternions[i - 1], quaternions[i], quaternions[i + 1], new Cesium.Quaternion());
- * const s1 = Cesium.Quaternion.computeInnerQuadrangle(quaternions[i], quaternions[i + 1], quaternions[i + 2], new Cesium.Quaternion());
- * const q = Cesium.Quaternion.squad(quaternions[i], quaternions[i + 1], s0, s1, t, new Cesium.Quaternion());
- *
- * // 2. compute the squad interpolation as above but where the first quaternion is a end point.
- * const s1 = Cesium.Quaternion.computeInnerQuadrangle(quaternions[0], quaternions[1], quaternions[2], new Cesium.Quaternion());
- * const q = Cesium.Quaternion.squad(quaternions[0], quaternions[1], quaternions[0], s1, t, new Cesium.Quaternion());
- *
- * @see Quaternion#computeInnerQuadrangle
- */
- Quaternion.squad = function (q0, q1, s0, s1, t, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("q0", q0);
- Check.typeOf.object("q1", q1);
- Check.typeOf.object("s0", s0);
- Check.typeOf.object("s1", s1);
- Check.typeOf.number("t", t);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- const slerp0 = Quaternion.slerp(q0, q1, t, squadScratchQuaternion0);
- const slerp1 = Quaternion.slerp(s0, s1, t, squadScratchQuaternion1);
- return Quaternion.slerp(slerp0, slerp1, 2.0 * t * (1.0 - t), result);
- };
- const fastSlerpScratchQuaternion = new Quaternion();
- const opmu = 1.90110745351730037;
- const u = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
- const v = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
- const bT = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
- const bD = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
- for (let i = 0; i < 7; ++i) {
- const s = i + 1.0;
- const t = 2.0 * s + 1.0;
- u[i] = 1.0 / (s * t);
- v[i] = s / t;
- }
- u[7] = opmu / (8.0 * 17.0);
- v[7] = (opmu * 8.0) / 17.0;
- /**
- * Computes the spherical linear interpolation or extrapolation at t using the provided quaternions.
- * This implementation is faster than {@link Quaternion#slerp}, but is only accurate up to 10<sup>-6</sup>.
- *
- * @param {Quaternion} start The value corresponding to t at 0.0.
- * @param {Quaternion} end The value corresponding to t at 1.0.
- * @param {Number} t The point along t at which to interpolate.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter.
- *
- * @see Quaternion#slerp
- */
- Quaternion.fastSlerp = function (start, end, t, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("start", start);
- Check.typeOf.object("end", end);
- Check.typeOf.number("t", t);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- let x = Quaternion.dot(start, end);
- let sign;
- if (x >= 0) {
- sign = 1.0;
- } else {
- sign = -1.0;
- x = -x;
- }
- const xm1 = x - 1.0;
- const d = 1.0 - t;
- const sqrT = t * t;
- const sqrD = d * d;
- for (let i = 7; i >= 0; --i) {
- bT[i] = (u[i] * sqrT - v[i]) * xm1;
- bD[i] = (u[i] * sqrD - v[i]) * xm1;
- }
- const cT =
- sign *
- t *
- (1.0 +
- bT[0] *
- (1.0 +
- bT[1] *
- (1.0 +
- bT[2] *
- (1.0 +
- bT[3] *
- (1.0 +
- bT[4] *
- (1.0 + bT[5] * (1.0 + bT[6] * (1.0 + bT[7]))))))));
- const cD =
- d *
- (1.0 +
- bD[0] *
- (1.0 +
- bD[1] *
- (1.0 +
- bD[2] *
- (1.0 +
- bD[3] *
- (1.0 +
- bD[4] *
- (1.0 + bD[5] * (1.0 + bD[6] * (1.0 + bD[7]))))))));
- const temp = Quaternion.multiplyByScalar(
- start,
- cD,
- fastSlerpScratchQuaternion
- );
- Quaternion.multiplyByScalar(end, cT, result);
- return Quaternion.add(temp, result, result);
- };
- /**
- * Computes the spherical quadrangle interpolation between quaternions.
- * An implementation that is faster than {@link Quaternion#squad}, but less accurate.
- *
- * @param {Quaternion} q0 The first quaternion.
- * @param {Quaternion} q1 The second quaternion.
- * @param {Quaternion} s0 The first inner quadrangle.
- * @param {Quaternion} s1 The second inner quadrangle.
- * @param {Number} t The time in [0,1] used to interpolate.
- * @param {Quaternion} result The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter or a new instance if none was provided.
- *
- * @see Quaternion#squad
- */
- Quaternion.fastSquad = function (q0, q1, s0, s1, t, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("q0", q0);
- Check.typeOf.object("q1", q1);
- Check.typeOf.object("s0", s0);
- Check.typeOf.object("s1", s1);
- Check.typeOf.number("t", t);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- const slerp0 = Quaternion.fastSlerp(q0, q1, t, squadScratchQuaternion0);
- const slerp1 = Quaternion.fastSlerp(s0, s1, t, squadScratchQuaternion1);
- return Quaternion.fastSlerp(slerp0, slerp1, 2.0 * t * (1.0 - t), result);
- };
- /**
- * Compares the provided quaternions componentwise and returns
- * <code>true</code> if they are equal, <code>false</code> otherwise.
- *
- * @param {Quaternion} [left] The first quaternion.
- * @param {Quaternion} [right] The second quaternion.
- * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
- */
- Quaternion.equals = function (left, right) {
- return (
- left === right ||
- (defined(left) &&
- defined(right) &&
- left.x === right.x &&
- left.y === right.y &&
- left.z === right.z &&
- left.w === right.w)
- );
- };
- /**
- * Compares the provided quaternions componentwise and returns
- * <code>true</code> if they are within the provided epsilon,
- * <code>false</code> otherwise.
- *
- * @param {Quaternion} [left] The first quaternion.
- * @param {Quaternion} [right] The second quaternion.
- * @param {Number} [epsilon=0] The epsilon to use for equality testing.
- * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
- */
- Quaternion.equalsEpsilon = function (left, right, epsilon) {
- epsilon = defaultValue(epsilon, 0);
- return (
- left === right ||
- (defined(left) &&
- defined(right) &&
- Math.abs(left.x - right.x) <= epsilon &&
- Math.abs(left.y - right.y) <= epsilon &&
- Math.abs(left.z - right.z) <= epsilon &&
- Math.abs(left.w - right.w) <= epsilon)
- );
- };
- /**
- * An immutable Quaternion instance initialized to (0.0, 0.0, 0.0, 0.0).
- *
- * @type {Quaternion}
- * @constant
- */
- Quaternion.ZERO = Object.freeze(new Quaternion(0.0, 0.0, 0.0, 0.0));
- /**
- * An immutable Quaternion instance initialized to (0.0, 0.0, 0.0, 1.0).
- *
- * @type {Quaternion}
- * @constant
- */
- Quaternion.IDENTITY = Object.freeze(new Quaternion(0.0, 0.0, 0.0, 1.0));
- /**
- * Duplicates this Quaternion instance.
- *
- * @param {Quaternion} [result] The object onto which to store the result.
- * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
- */
- Quaternion.prototype.clone = function (result) {
- return Quaternion.clone(this, result);
- };
- /**
- * Compares this and the provided quaternion componentwise and returns
- * <code>true</code> if they are equal, <code>false</code> otherwise.
- *
- * @param {Quaternion} [right] The right hand side quaternion.
- * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
- */
- Quaternion.prototype.equals = function (right) {
- return Quaternion.equals(this, right);
- };
- /**
- * Compares this and the provided quaternion componentwise and returns
- * <code>true</code> if they are within the provided epsilon,
- * <code>false</code> otherwise.
- *
- * @param {Quaternion} [right] The right hand side quaternion.
- * @param {Number} [epsilon=0] The epsilon to use for equality testing.
- * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
- */
- Quaternion.prototype.equalsEpsilon = function (right, epsilon) {
- return Quaternion.equalsEpsilon(this, right, epsilon);
- };
- /**
- * Returns a string representing this quaternion in the format (x, y, z, w).
- *
- * @returns {String} A string representing this Quaternion.
- */
- Quaternion.prototype.toString = function () {
- return `(${this.x}, ${this.y}, ${this.z}, ${this.w})`;
- };
- export default Quaternion;
|