Quaternion.js 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  1. import Cartesian3 from './Cartesian3.js';
  2. import Check from './Check.js';
  3. import defaultValue from './defaultValue.js';
  4. import defined from './defined.js';
  5. import FeatureDetection from './FeatureDetection.js';
  6. import freezeObject from './freezeObject.js';
  7. import CesiumMath from './Math.js';
  8. import Matrix3 from './Matrix3.js';
  9. /**
  10. * A set of 4-dimensional coordinates used to represent rotation in 3-dimensional space.
  11. * @alias Quaternion
  12. * @constructor
  13. *
  14. * @param {Number} [x=0.0] The X component.
  15. * @param {Number} [y=0.0] The Y component.
  16. * @param {Number} [z=0.0] The Z component.
  17. * @param {Number} [w=0.0] The W component.
  18. *
  19. * @see PackableForInterpolation
  20. */
  21. function Quaternion(x, y, z, w) {
  22. /**
  23. * The X component.
  24. * @type {Number}
  25. * @default 0.0
  26. */
  27. this.x = defaultValue(x, 0.0);
  28. /**
  29. * The Y component.
  30. * @type {Number}
  31. * @default 0.0
  32. */
  33. this.y = defaultValue(y, 0.0);
  34. /**
  35. * The Z component.
  36. * @type {Number}
  37. * @default 0.0
  38. */
  39. this.z = defaultValue(z, 0.0);
  40. /**
  41. * The W component.
  42. * @type {Number}
  43. * @default 0.0
  44. */
  45. this.w = defaultValue(w, 0.0);
  46. }
  47. var fromAxisAngleScratch = new Cartesian3();
  48. /**
  49. * Computes a quaternion representing a rotation around an axis.
  50. *
  51. * @param {Cartesian3} axis The axis of rotation.
  52. * @param {Number} angle The angle in radians to rotate around the axis.
  53. * @param {Quaternion} [result] The object onto which to store the result.
  54. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
  55. */
  56. Quaternion.fromAxisAngle = function(axis, angle, result) {
  57. //>>includeStart('debug', pragmas.debug);
  58. Check.typeOf.object('axis', axis);
  59. Check.typeOf.number('angle', angle);
  60. //>>includeEnd('debug');
  61. var halfAngle = angle / 2.0;
  62. var s = Math.sin(halfAngle);
  63. fromAxisAngleScratch = Cartesian3.normalize(axis, fromAxisAngleScratch);
  64. var x = fromAxisAngleScratch.x * s;
  65. var y = fromAxisAngleScratch.y * s;
  66. var z = fromAxisAngleScratch.z * s;
  67. var w = Math.cos(halfAngle);
  68. if (!defined(result)) {
  69. return new Quaternion(x, y, z, w);
  70. }
  71. result.x = x;
  72. result.y = y;
  73. result.z = z;
  74. result.w = w;
  75. return result;
  76. };
  77. var fromRotationMatrixNext = [1, 2, 0];
  78. var fromRotationMatrixQuat = new Array(3);
  79. /**
  80. * Computes a Quaternion from the provided Matrix3 instance.
  81. *
  82. * @param {Matrix3} matrix The rotation matrix.
  83. * @param {Quaternion} [result] The object onto which to store the result.
  84. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
  85. *
  86. * @see Matrix3.fromQuaternion
  87. */
  88. Quaternion.fromRotationMatrix = function(matrix, result) {
  89. //>>includeStart('debug', pragmas.debug);
  90. Check.typeOf.object('matrix', matrix);
  91. //>>includeEnd('debug');
  92. var root;
  93. var x;
  94. var y;
  95. var z;
  96. var w;
  97. var m00 = matrix[Matrix3.COLUMN0ROW0];
  98. var m11 = matrix[Matrix3.COLUMN1ROW1];
  99. var m22 = matrix[Matrix3.COLUMN2ROW2];
  100. var trace = m00 + m11 + m22;
  101. if (trace > 0.0) {
  102. // |w| > 1/2, may as well choose w > 1/2
  103. root = Math.sqrt(trace + 1.0); // 2w
  104. w = 0.5 * root;
  105. root = 0.5 / root; // 1/(4w)
  106. x = (matrix[Matrix3.COLUMN1ROW2] - matrix[Matrix3.COLUMN2ROW1]) * root;
  107. y = (matrix[Matrix3.COLUMN2ROW0] - matrix[Matrix3.COLUMN0ROW2]) * root;
  108. z = (matrix[Matrix3.COLUMN0ROW1] - matrix[Matrix3.COLUMN1ROW0]) * root;
  109. } else {
  110. // |w| <= 1/2
  111. var next = fromRotationMatrixNext;
  112. var i = 0;
  113. if (m11 > m00) {
  114. i = 1;
  115. }
  116. if (m22 > m00 && m22 > m11) {
  117. i = 2;
  118. }
  119. var j = next[i];
  120. var k = next[j];
  121. root = Math.sqrt(matrix[Matrix3.getElementIndex(i, i)] - matrix[Matrix3.getElementIndex(j, j)] - matrix[Matrix3.getElementIndex(k, k)] + 1.0);
  122. var quat = fromRotationMatrixQuat;
  123. quat[i] = 0.5 * root;
  124. root = 0.5 / root;
  125. w = (matrix[Matrix3.getElementIndex(k, j)] - matrix[Matrix3.getElementIndex(j, k)]) * root;
  126. quat[j] = (matrix[Matrix3.getElementIndex(j, i)] + matrix[Matrix3.getElementIndex(i, j)]) * root;
  127. quat[k] = (matrix[Matrix3.getElementIndex(k, i)] + matrix[Matrix3.getElementIndex(i, k)]) * root;
  128. x = -quat[0];
  129. y = -quat[1];
  130. z = -quat[2];
  131. }
  132. if (!defined(result)) {
  133. return new Quaternion(x, y, z, w);
  134. }
  135. result.x = x;
  136. result.y = y;
  137. result.z = z;
  138. result.w = w;
  139. return result;
  140. };
  141. var scratchHPRQuaternion = new Quaternion();
  142. var scratchHeadingQuaternion = new Quaternion();
  143. var scratchPitchQuaternion = new Quaternion();
  144. var scratchRollQuaternion = new Quaternion();
  145. /**
  146. * Computes a rotation from the given heading, pitch and roll angles. Heading is the rotation about the
  147. * negative z axis. Pitch is the rotation about the negative y axis. Roll is the rotation about
  148. * the positive x axis.
  149. *
  150. * @param {HeadingPitchRoll} headingPitchRoll The rotation expressed as a heading, pitch and roll.
  151. * @param {Quaternion} [result] The object onto which to store the result.
  152. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if none was provided.
  153. */
  154. Quaternion.fromHeadingPitchRoll = function(headingPitchRoll, result) {
  155. //>>includeStart('debug', pragmas.debug);
  156. Check.typeOf.object('headingPitchRoll', headingPitchRoll);
  157. //>>includeEnd('debug');
  158. scratchRollQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_X, headingPitchRoll.roll, scratchHPRQuaternion);
  159. scratchPitchQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Y, -headingPitchRoll.pitch, result);
  160. result = Quaternion.multiply(scratchPitchQuaternion, scratchRollQuaternion, scratchPitchQuaternion);
  161. scratchHeadingQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Z, -headingPitchRoll.heading, scratchHPRQuaternion);
  162. return Quaternion.multiply(scratchHeadingQuaternion, result, result);
  163. };
  164. var sampledQuaternionAxis = new Cartesian3();
  165. var sampledQuaternionRotation = new Cartesian3();
  166. var sampledQuaternionTempQuaternion = new Quaternion();
  167. var sampledQuaternionQuaternion0 = new Quaternion();
  168. var sampledQuaternionQuaternion0Conjugate = new Quaternion();
  169. /**
  170. * The number of elements used to pack the object into an array.
  171. * @type {Number}
  172. */
  173. Quaternion.packedLength = 4;
  174. /**
  175. * Stores the provided instance into the provided array.
  176. *
  177. * @param {Quaternion} value The value to pack.
  178. * @param {Number[]} array The array to pack into.
  179. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  180. *
  181. * @returns {Number[]} The array that was packed into
  182. */
  183. Quaternion.pack = function(value, array, startingIndex) {
  184. //>>includeStart('debug', pragmas.debug);
  185. Check.typeOf.object('value', value);
  186. Check.defined('array', array);
  187. //>>includeEnd('debug');
  188. startingIndex = defaultValue(startingIndex, 0);
  189. array[startingIndex++] = value.x;
  190. array[startingIndex++] = value.y;
  191. array[startingIndex++] = value.z;
  192. array[startingIndex] = value.w;
  193. return array;
  194. };
  195. /**
  196. * Retrieves an instance from a packed array.
  197. *
  198. * @param {Number[]} array The packed array.
  199. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  200. * @param {Quaternion} [result] The object into which to store the result.
  201. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
  202. */
  203. Quaternion.unpack = function(array, startingIndex, result) {
  204. //>>includeStart('debug', pragmas.debug);
  205. Check.defined('array', array);
  206. //>>includeEnd('debug');
  207. startingIndex = defaultValue(startingIndex, 0);
  208. if (!defined(result)) {
  209. result = new Quaternion();
  210. }
  211. result.x = array[startingIndex];
  212. result.y = array[startingIndex + 1];
  213. result.z = array[startingIndex + 2];
  214. result.w = array[startingIndex + 3];
  215. return result;
  216. };
  217. /**
  218. * The number of elements used to store the object into an array in its interpolatable form.
  219. * @type {Number}
  220. */
  221. Quaternion.packedInterpolationLength = 3;
  222. /**
  223. * Converts a packed array into a form suitable for interpolation.
  224. *
  225. * @param {Number[]} packedArray The packed array.
  226. * @param {Number} [startingIndex=0] The index of the first element to be converted.
  227. * @param {Number} [lastIndex=packedArray.length] The index of the last element to be converted.
  228. * @param {Number[]} result The object into which to store the result.
  229. */
  230. Quaternion.convertPackedArrayForInterpolation = function(packedArray, startingIndex, lastIndex, result) {
  231. Quaternion.unpack(packedArray, lastIndex * 4, sampledQuaternionQuaternion0Conjugate);
  232. Quaternion.conjugate(sampledQuaternionQuaternion0Conjugate, sampledQuaternionQuaternion0Conjugate);
  233. for (var i = 0, len = lastIndex - startingIndex + 1; i < len; i++) {
  234. var offset = i * 3;
  235. Quaternion.unpack(packedArray, (startingIndex + i) * 4, sampledQuaternionTempQuaternion);
  236. Quaternion.multiply(sampledQuaternionTempQuaternion, sampledQuaternionQuaternion0Conjugate, sampledQuaternionTempQuaternion);
  237. if (sampledQuaternionTempQuaternion.w < 0) {
  238. Quaternion.negate(sampledQuaternionTempQuaternion, sampledQuaternionTempQuaternion);
  239. }
  240. Quaternion.computeAxis(sampledQuaternionTempQuaternion, sampledQuaternionAxis);
  241. var angle = Quaternion.computeAngle(sampledQuaternionTempQuaternion);
  242. result[offset] = sampledQuaternionAxis.x * angle;
  243. result[offset + 1] = sampledQuaternionAxis.y * angle;
  244. result[offset + 2] = sampledQuaternionAxis.z * angle;
  245. }
  246. };
  247. /**
  248. * Retrieves an instance from a packed array converted with {@link convertPackedArrayForInterpolation}.
  249. *
  250. * @param {Number[]} array The array previously packed for interpolation.
  251. * @param {Number[]} sourceArray The original packed array.
  252. * @param {Number} [firstIndex=0] The firstIndex used to convert the array.
  253. * @param {Number} [lastIndex=packedArray.length] The lastIndex used to convert the array.
  254. * @param {Quaternion} [result] The object into which to store the result.
  255. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
  256. */
  257. Quaternion.unpackInterpolationResult = function(array, sourceArray, firstIndex, lastIndex, result) {
  258. if (!defined(result)) {
  259. result = new Quaternion();
  260. }
  261. Cartesian3.fromArray(array, 0, sampledQuaternionRotation);
  262. var magnitude = Cartesian3.magnitude(sampledQuaternionRotation);
  263. Quaternion.unpack(sourceArray, lastIndex * 4, sampledQuaternionQuaternion0);
  264. if (magnitude === 0) {
  265. Quaternion.clone(Quaternion.IDENTITY, sampledQuaternionTempQuaternion);
  266. } else {
  267. Quaternion.fromAxisAngle(sampledQuaternionRotation, magnitude, sampledQuaternionTempQuaternion);
  268. }
  269. return Quaternion.multiply(sampledQuaternionTempQuaternion, sampledQuaternionQuaternion0, result);
  270. };
  271. /**
  272. * Duplicates a Quaternion instance.
  273. *
  274. * @param {Quaternion} quaternion The quaternion to duplicate.
  275. * @param {Quaternion} [result] The object onto which to store the result.
  276. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided. (Returns undefined if quaternion is undefined)
  277. */
  278. Quaternion.clone = function(quaternion, result) {
  279. if (!defined(quaternion)) {
  280. return undefined;
  281. }
  282. if (!defined(result)) {
  283. return new Quaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
  284. }
  285. result.x = quaternion.x;
  286. result.y = quaternion.y;
  287. result.z = quaternion.z;
  288. result.w = quaternion.w;
  289. return result;
  290. };
  291. /**
  292. * Computes the conjugate of the provided quaternion.
  293. *
  294. * @param {Quaternion} quaternion The quaternion to conjugate.
  295. * @param {Quaternion} result The object onto which to store the result.
  296. * @returns {Quaternion} The modified result parameter.
  297. */
  298. Quaternion.conjugate = function(quaternion, result) {
  299. //>>includeStart('debug', pragmas.debug);
  300. Check.typeOf.object('quaternion', quaternion);
  301. Check.typeOf.object('result', result);
  302. //>>includeEnd('debug');
  303. result.x = -quaternion.x;
  304. result.y = -quaternion.y;
  305. result.z = -quaternion.z;
  306. result.w = quaternion.w;
  307. return result;
  308. };
  309. /**
  310. * Computes magnitude squared for the provided quaternion.
  311. *
  312. * @param {Quaternion} quaternion The quaternion to conjugate.
  313. * @returns {Number} The magnitude squared.
  314. */
  315. Quaternion.magnitudeSquared = function(quaternion) {
  316. //>>includeStart('debug', pragmas.debug);
  317. Check.typeOf.object('quaternion', quaternion);
  318. //>>includeEnd('debug');
  319. return quaternion.x * quaternion.x + quaternion.y * quaternion.y + quaternion.z * quaternion.z + quaternion.w * quaternion.w;
  320. };
  321. /**
  322. * Computes magnitude for the provided quaternion.
  323. *
  324. * @param {Quaternion} quaternion The quaternion to conjugate.
  325. * @returns {Number} The magnitude.
  326. */
  327. Quaternion.magnitude = function(quaternion) {
  328. return Math.sqrt(Quaternion.magnitudeSquared(quaternion));
  329. };
  330. /**
  331. * Computes the normalized form of the provided quaternion.
  332. *
  333. * @param {Quaternion} quaternion The quaternion to normalize.
  334. * @param {Quaternion} result The object onto which to store the result.
  335. * @returns {Quaternion} The modified result parameter.
  336. */
  337. Quaternion.normalize = function(quaternion, result) {
  338. //>>includeStart('debug', pragmas.debug);
  339. Check.typeOf.object('result', result);
  340. //>>includeEnd('debug');
  341. var inverseMagnitude = 1.0 / Quaternion.magnitude(quaternion);
  342. var x = quaternion.x * inverseMagnitude;
  343. var y = quaternion.y * inverseMagnitude;
  344. var z = quaternion.z * inverseMagnitude;
  345. var w = quaternion.w * inverseMagnitude;
  346. result.x = x;
  347. result.y = y;
  348. result.z = z;
  349. result.w = w;
  350. return result;
  351. };
  352. /**
  353. * Computes the inverse of the provided quaternion.
  354. *
  355. * @param {Quaternion} quaternion The quaternion to normalize.
  356. * @param {Quaternion} result The object onto which to store the result.
  357. * @returns {Quaternion} The modified result parameter.
  358. */
  359. Quaternion.inverse = function(quaternion, result) {
  360. //>>includeStart('debug', pragmas.debug);
  361. Check.typeOf.object('result', result);
  362. //>>includeEnd('debug');
  363. var magnitudeSquared = Quaternion.magnitudeSquared(quaternion);
  364. result = Quaternion.conjugate(quaternion, result);
  365. return Quaternion.multiplyByScalar(result, 1.0 / magnitudeSquared, result);
  366. };
  367. /**
  368. * Computes the componentwise sum of two quaternions.
  369. *
  370. * @param {Quaternion} left The first quaternion.
  371. * @param {Quaternion} right The second quaternion.
  372. * @param {Quaternion} result The object onto which to store the result.
  373. * @returns {Quaternion} The modified result parameter.
  374. */
  375. Quaternion.add = function(left, right, result) {
  376. //>>includeStart('debug', pragmas.debug);
  377. Check.typeOf.object('left', left);
  378. Check.typeOf.object('right', right);
  379. Check.typeOf.object('result', result);
  380. //>>includeEnd('debug');
  381. result.x = left.x + right.x;
  382. result.y = left.y + right.y;
  383. result.z = left.z + right.z;
  384. result.w = left.w + right.w;
  385. return result;
  386. };
  387. /**
  388. * Computes the componentwise difference of two quaternions.
  389. *
  390. * @param {Quaternion} left The first quaternion.
  391. * @param {Quaternion} right The second quaternion.
  392. * @param {Quaternion} result The object onto which to store the result.
  393. * @returns {Quaternion} The modified result parameter.
  394. */
  395. Quaternion.subtract = function(left, right, result) {
  396. //>>includeStart('debug', pragmas.debug);
  397. Check.typeOf.object('left', left);
  398. Check.typeOf.object('right', right);
  399. Check.typeOf.object('result', result);
  400. //>>includeEnd('debug');
  401. result.x = left.x - right.x;
  402. result.y = left.y - right.y;
  403. result.z = left.z - right.z;
  404. result.w = left.w - right.w;
  405. return result;
  406. };
  407. /**
  408. * Negates the provided quaternion.
  409. *
  410. * @param {Quaternion} quaternion The quaternion to be negated.
  411. * @param {Quaternion} result The object onto which to store the result.
  412. * @returns {Quaternion} The modified result parameter.
  413. */
  414. Quaternion.negate = function(quaternion, result) {
  415. //>>includeStart('debug', pragmas.debug);
  416. Check.typeOf.object('quaternion', quaternion);
  417. Check.typeOf.object('result', result);
  418. //>>includeEnd('debug');
  419. result.x = -quaternion.x;
  420. result.y = -quaternion.y;
  421. result.z = -quaternion.z;
  422. result.w = -quaternion.w;
  423. return result;
  424. };
  425. /**
  426. * Computes the dot (scalar) product of two quaternions.
  427. *
  428. * @param {Quaternion} left The first quaternion.
  429. * @param {Quaternion} right The second quaternion.
  430. * @returns {Number} The dot product.
  431. */
  432. Quaternion.dot = function(left, right) {
  433. //>>includeStart('debug', pragmas.debug);
  434. Check.typeOf.object('left', left);
  435. Check.typeOf.object('right', right);
  436. //>>includeEnd('debug');
  437. return left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w;
  438. };
  439. /**
  440. * Computes the product of two quaternions.
  441. *
  442. * @param {Quaternion} left The first quaternion.
  443. * @param {Quaternion} right The second quaternion.
  444. * @param {Quaternion} result The object onto which to store the result.
  445. * @returns {Quaternion} The modified result parameter.
  446. */
  447. Quaternion.multiply = function(left, right, result) {
  448. //>>includeStart('debug', pragmas.debug);
  449. Check.typeOf.object('left', left);
  450. Check.typeOf.object('right', right);
  451. Check.typeOf.object('result', result);
  452. //>>includeEnd('debug');
  453. var leftX = left.x;
  454. var leftY = left.y;
  455. var leftZ = left.z;
  456. var leftW = left.w;
  457. var rightX = right.x;
  458. var rightY = right.y;
  459. var rightZ = right.z;
  460. var rightW = right.w;
  461. var x = leftW * rightX + leftX * rightW + leftY * rightZ - leftZ * rightY;
  462. var y = leftW * rightY - leftX * rightZ + leftY * rightW + leftZ * rightX;
  463. var z = leftW * rightZ + leftX * rightY - leftY * rightX + leftZ * rightW;
  464. var w = leftW * rightW - leftX * rightX - leftY * rightY - leftZ * rightZ;
  465. result.x = x;
  466. result.y = y;
  467. result.z = z;
  468. result.w = w;
  469. return result;
  470. };
  471. /**
  472. * Multiplies the provided quaternion componentwise by the provided scalar.
  473. *
  474. * @param {Quaternion} quaternion The quaternion to be scaled.
  475. * @param {Number} scalar The scalar to multiply with.
  476. * @param {Quaternion} result The object onto which to store the result.
  477. * @returns {Quaternion} The modified result parameter.
  478. */
  479. Quaternion.multiplyByScalar = function(quaternion, scalar, result) {
  480. //>>includeStart('debug', pragmas.debug);
  481. Check.typeOf.object('quaternion', quaternion);
  482. Check.typeOf.number('scalar', scalar);
  483. Check.typeOf.object('result', result);
  484. //>>includeEnd('debug');
  485. result.x = quaternion.x * scalar;
  486. result.y = quaternion.y * scalar;
  487. result.z = quaternion.z * scalar;
  488. result.w = quaternion.w * scalar;
  489. return result;
  490. };
  491. /**
  492. * Divides the provided quaternion componentwise by the provided scalar.
  493. *
  494. * @param {Quaternion} quaternion The quaternion to be divided.
  495. * @param {Number} scalar The scalar to divide by.
  496. * @param {Quaternion} result The object onto which to store the result.
  497. * @returns {Quaternion} The modified result parameter.
  498. */
  499. Quaternion.divideByScalar = function(quaternion, scalar, result) {
  500. //>>includeStart('debug', pragmas.debug);
  501. Check.typeOf.object('quaternion', quaternion);
  502. Check.typeOf.number('scalar', scalar);
  503. Check.typeOf.object('result', result);
  504. //>>includeEnd('debug');
  505. result.x = quaternion.x / scalar;
  506. result.y = quaternion.y / scalar;
  507. result.z = quaternion.z / scalar;
  508. result.w = quaternion.w / scalar;
  509. return result;
  510. };
  511. /**
  512. * Computes the axis of rotation of the provided quaternion.
  513. *
  514. * @param {Quaternion} quaternion The quaternion to use.
  515. * @param {Cartesian3} result The object onto which to store the result.
  516. * @returns {Cartesian3} The modified result parameter.
  517. */
  518. Quaternion.computeAxis = function(quaternion, result) {
  519. //>>includeStart('debug', pragmas.debug);
  520. Check.typeOf.object('quaternion', quaternion);
  521. Check.typeOf.object('result', result);
  522. //>>includeEnd('debug');
  523. var w = quaternion.w;
  524. if (Math.abs(w - 1.0) < CesiumMath.EPSILON6) {
  525. result.x = result.y = result.z = 0;
  526. return result;
  527. }
  528. var scalar = 1.0 / Math.sqrt(1.0 - (w * w));
  529. result.x = quaternion.x * scalar;
  530. result.y = quaternion.y * scalar;
  531. result.z = quaternion.z * scalar;
  532. return result;
  533. };
  534. /**
  535. * Computes the angle of rotation of the provided quaternion.
  536. *
  537. * @param {Quaternion} quaternion The quaternion to use.
  538. * @returns {Number} The angle of rotation.
  539. */
  540. Quaternion.computeAngle = function(quaternion) {
  541. //>>includeStart('debug', pragmas.debug);
  542. Check.typeOf.object('quaternion', quaternion);
  543. //>>includeEnd('debug');
  544. if (Math.abs(quaternion.w - 1.0) < CesiumMath.EPSILON6) {
  545. return 0.0;
  546. }
  547. return 2.0 * Math.acos(quaternion.w);
  548. };
  549. var lerpScratch = new Quaternion();
  550. /**
  551. * Computes the linear interpolation or extrapolation at t using the provided quaternions.
  552. *
  553. * @param {Quaternion} start The value corresponding to t at 0.0.
  554. * @param {Quaternion} end The value corresponding to t at 1.0.
  555. * @param {Number} t The point along t at which to interpolate.
  556. * @param {Quaternion} result The object onto which to store the result.
  557. * @returns {Quaternion} The modified result parameter.
  558. */
  559. Quaternion.lerp = function(start, end, t, result) {
  560. //>>includeStart('debug', pragmas.debug);
  561. Check.typeOf.object('start', start);
  562. Check.typeOf.object('end', end);
  563. Check.typeOf.number('t', t);
  564. Check.typeOf.object('result', result);
  565. //>>includeEnd('debug');
  566. lerpScratch = Quaternion.multiplyByScalar(end, t, lerpScratch);
  567. result = Quaternion.multiplyByScalar(start, 1.0 - t, result);
  568. return Quaternion.add(lerpScratch, result, result);
  569. };
  570. var slerpEndNegated = new Quaternion();
  571. var slerpScaledP = new Quaternion();
  572. var slerpScaledR = new Quaternion();
  573. /**
  574. * Computes the spherical linear interpolation or extrapolation at t using the provided quaternions.
  575. *
  576. * @param {Quaternion} start The value corresponding to t at 0.0.
  577. * @param {Quaternion} end The value corresponding to t at 1.0.
  578. * @param {Number} t The point along t at which to interpolate.
  579. * @param {Quaternion} result The object onto which to store the result.
  580. * @returns {Quaternion} The modified result parameter.
  581. *
  582. * @see Quaternion#fastSlerp
  583. */
  584. Quaternion.slerp = function(start, end, t, result) {
  585. //>>includeStart('debug', pragmas.debug);
  586. Check.typeOf.object('start', start);
  587. Check.typeOf.object('end', end);
  588. Check.typeOf.number('t', t);
  589. Check.typeOf.object('result', result);
  590. //>>includeEnd('debug');
  591. var dot = Quaternion.dot(start, end);
  592. // The angle between start must be acute. Since q and -q represent
  593. // the same rotation, negate q to get the acute angle.
  594. var r = end;
  595. if (dot < 0.0) {
  596. dot = -dot;
  597. r = slerpEndNegated = Quaternion.negate(end, slerpEndNegated);
  598. }
  599. // dot > 0, as the dot product approaches 1, the angle between the
  600. // quaternions vanishes. use linear interpolation.
  601. if (1.0 - dot < CesiumMath.EPSILON6) {
  602. return Quaternion.lerp(start, r, t, result);
  603. }
  604. var theta = Math.acos(dot);
  605. slerpScaledP = Quaternion.multiplyByScalar(start, Math.sin((1 - t) * theta), slerpScaledP);
  606. slerpScaledR = Quaternion.multiplyByScalar(r, Math.sin(t * theta), slerpScaledR);
  607. result = Quaternion.add(slerpScaledP, slerpScaledR, result);
  608. return Quaternion.multiplyByScalar(result, 1.0 / Math.sin(theta), result);
  609. };
  610. /**
  611. * The logarithmic quaternion function.
  612. *
  613. * @param {Quaternion} quaternion The unit quaternion.
  614. * @param {Cartesian3} result The object onto which to store the result.
  615. * @returns {Cartesian3} The modified result parameter.
  616. */
  617. Quaternion.log = function(quaternion, result) {
  618. //>>includeStart('debug', pragmas.debug);
  619. Check.typeOf.object('quaternion', quaternion);
  620. Check.typeOf.object('result', result);
  621. //>>includeEnd('debug');
  622. var theta = CesiumMath.acosClamped(quaternion.w);
  623. var thetaOverSinTheta = 0.0;
  624. if (theta !== 0.0) {
  625. thetaOverSinTheta = theta / Math.sin(theta);
  626. }
  627. return Cartesian3.multiplyByScalar(quaternion, thetaOverSinTheta, result);
  628. };
  629. /**
  630. * The exponential quaternion function.
  631. *
  632. * @param {Cartesian3} cartesian The cartesian.
  633. * @param {Quaternion} result The object onto which to store the result.
  634. * @returns {Quaternion} The modified result parameter.
  635. */
  636. Quaternion.exp = function(cartesian, result) {
  637. //>>includeStart('debug', pragmas.debug);
  638. Check.typeOf.object('cartesian', cartesian);
  639. Check.typeOf.object('result', result);
  640. //>>includeEnd('debug');
  641. var theta = Cartesian3.magnitude(cartesian);
  642. var sinThetaOverTheta = 0.0;
  643. if (theta !== 0.0) {
  644. sinThetaOverTheta = Math.sin(theta) / theta;
  645. }
  646. result.x = cartesian.x * sinThetaOverTheta;
  647. result.y = cartesian.y * sinThetaOverTheta;
  648. result.z = cartesian.z * sinThetaOverTheta;
  649. result.w = Math.cos(theta);
  650. return result;
  651. };
  652. var squadScratchCartesian0 = new Cartesian3();
  653. var squadScratchCartesian1 = new Cartesian3();
  654. var squadScratchQuaternion0 = new Quaternion();
  655. var squadScratchQuaternion1 = new Quaternion();
  656. /**
  657. * Computes an inner quadrangle point.
  658. * <p>This will compute quaternions that ensure a squad curve is C<sup>1</sup>.</p>
  659. *
  660. * @param {Quaternion} q0 The first quaternion.
  661. * @param {Quaternion} q1 The second quaternion.
  662. * @param {Quaternion} q2 The third quaternion.
  663. * @param {Quaternion} result The object onto which to store the result.
  664. * @returns {Quaternion} The modified result parameter.
  665. *
  666. * @see Quaternion#squad
  667. */
  668. Quaternion.computeInnerQuadrangle = function(q0, q1, q2, result) {
  669. //>>includeStart('debug', pragmas.debug);
  670. Check.typeOf.object('q0', q0);
  671. Check.typeOf.object('q1', q1);
  672. Check.typeOf.object('q2', q2);
  673. Check.typeOf.object('result', result);
  674. //>>includeEnd('debug');
  675. var qInv = Quaternion.conjugate(q1, squadScratchQuaternion0);
  676. Quaternion.multiply(qInv, q2, squadScratchQuaternion1);
  677. var cart0 = Quaternion.log(squadScratchQuaternion1, squadScratchCartesian0);
  678. Quaternion.multiply(qInv, q0, squadScratchQuaternion1);
  679. var cart1 = Quaternion.log(squadScratchQuaternion1, squadScratchCartesian1);
  680. Cartesian3.add(cart0, cart1, cart0);
  681. Cartesian3.multiplyByScalar(cart0, 0.25, cart0);
  682. Cartesian3.negate(cart0, cart0);
  683. Quaternion.exp(cart0, squadScratchQuaternion0);
  684. return Quaternion.multiply(q1, squadScratchQuaternion0, result);
  685. };
  686. /**
  687. * Computes the spherical quadrangle interpolation between quaternions.
  688. *
  689. * @param {Quaternion} q0 The first quaternion.
  690. * @param {Quaternion} q1 The second quaternion.
  691. * @param {Quaternion} s0 The first inner quadrangle.
  692. * @param {Quaternion} s1 The second inner quadrangle.
  693. * @param {Number} t The time in [0,1] used to interpolate.
  694. * @param {Quaternion} result The object onto which to store the result.
  695. * @returns {Quaternion} The modified result parameter.
  696. *
  697. *
  698. * @example
  699. * // 1. compute the squad interpolation between two quaternions on a curve
  700. * var s0 = Cesium.Quaternion.computeInnerQuadrangle(quaternions[i - 1], quaternions[i], quaternions[i + 1], new Cesium.Quaternion());
  701. * var s1 = Cesium.Quaternion.computeInnerQuadrangle(quaternions[i], quaternions[i + 1], quaternions[i + 2], new Cesium.Quaternion());
  702. * var q = Cesium.Quaternion.squad(quaternions[i], quaternions[i + 1], s0, s1, t, new Cesium.Quaternion());
  703. *
  704. * // 2. compute the squad interpolation as above but where the first quaternion is a end point.
  705. * var s1 = Cesium.Quaternion.computeInnerQuadrangle(quaternions[0], quaternions[1], quaternions[2], new Cesium.Quaternion());
  706. * var q = Cesium.Quaternion.squad(quaternions[0], quaternions[1], quaternions[0], s1, t, new Cesium.Quaternion());
  707. *
  708. * @see Quaternion#computeInnerQuadrangle
  709. */
  710. Quaternion.squad = function(q0, q1, s0, s1, t, result) {
  711. //>>includeStart('debug', pragmas.debug);
  712. Check.typeOf.object('q0', q0);
  713. Check.typeOf.object('q1', q1);
  714. Check.typeOf.object('s0', s0);
  715. Check.typeOf.object('s1', s1);
  716. Check.typeOf.number('t', t);
  717. Check.typeOf.object('result', result);
  718. //>>includeEnd('debug');
  719. var slerp0 = Quaternion.slerp(q0, q1, t, squadScratchQuaternion0);
  720. var slerp1 = Quaternion.slerp(s0, s1, t, squadScratchQuaternion1);
  721. return Quaternion.slerp(slerp0, slerp1, 2.0 * t * (1.0 - t), result);
  722. };
  723. var fastSlerpScratchQuaternion = new Quaternion();
  724. var opmu = 1.90110745351730037;
  725. var u = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
  726. var v = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
  727. var bT = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
  728. var bD = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
  729. for (var i = 0; i < 7; ++i) {
  730. var s = i + 1.0;
  731. var t = 2.0 * s + 1.0;
  732. u[i] = 1.0 / (s * t);
  733. v[i] = s / t;
  734. }
  735. u[7] = opmu / (8.0 * 17.0);
  736. v[7] = opmu * 8.0 / 17.0;
  737. /**
  738. * Computes the spherical linear interpolation or extrapolation at t using the provided quaternions.
  739. * This implementation is faster than {@link Quaternion#slerp}, but is only accurate up to 10<sup>-6</sup>.
  740. *
  741. * @param {Quaternion} start The value corresponding to t at 0.0.
  742. * @param {Quaternion} end The value corresponding to t at 1.0.
  743. * @param {Number} t The point along t at which to interpolate.
  744. * @param {Quaternion} result The object onto which to store the result.
  745. * @returns {Quaternion} The modified result parameter.
  746. *
  747. * @see Quaternion#slerp
  748. */
  749. Quaternion.fastSlerp = function(start, end, t, result) {
  750. //>>includeStart('debug', pragmas.debug);
  751. Check.typeOf.object('start', start);
  752. Check.typeOf.object('end', end);
  753. Check.typeOf.number('t', t);
  754. Check.typeOf.object('result', result);
  755. //>>includeEnd('debug');
  756. var x = Quaternion.dot(start, end);
  757. var sign;
  758. if (x >= 0) {
  759. sign = 1.0;
  760. } else {
  761. sign = -1.0;
  762. x = -x;
  763. }
  764. var xm1 = x - 1.0;
  765. var d = 1.0 - t;
  766. var sqrT = t * t;
  767. var sqrD = d * d;
  768. for (var i = 7; i >= 0; --i) {
  769. bT[i] = (u[i] * sqrT - v[i]) * xm1;
  770. bD[i] = (u[i] * sqrD - v[i]) * xm1;
  771. }
  772. var cT = sign * t * (
  773. 1.0 + bT[0] * (1.0 + bT[1] * (1.0 + bT[2] * (1.0 + bT[3] * (
  774. 1.0 + bT[4] * (1.0 + bT[5] * (1.0 + bT[6] * (1.0 + bT[7]))))))));
  775. var cD = d * (
  776. 1.0 + bD[0] * (1.0 + bD[1] * (1.0 + bD[2] * (1.0 + bD[3] * (
  777. 1.0 + bD[4] * (1.0 + bD[5] * (1.0 + bD[6] * (1.0 + bD[7]))))))));
  778. var temp = Quaternion.multiplyByScalar(start, cD, fastSlerpScratchQuaternion);
  779. Quaternion.multiplyByScalar(end, cT, result);
  780. return Quaternion.add(temp, result, result);
  781. };
  782. /**
  783. * Computes the spherical quadrangle interpolation between quaternions.
  784. * An implementation that is faster than {@link Quaternion#squad}, but less accurate.
  785. *
  786. * @param {Quaternion} q0 The first quaternion.
  787. * @param {Quaternion} q1 The second quaternion.
  788. * @param {Quaternion} s0 The first inner quadrangle.
  789. * @param {Quaternion} s1 The second inner quadrangle.
  790. * @param {Number} t The time in [0,1] used to interpolate.
  791. * @param {Quaternion} result The object onto which to store the result.
  792. * @returns {Quaternion} The modified result parameter or a new instance if none was provided.
  793. *
  794. * @see Quaternion#squad
  795. */
  796. Quaternion.fastSquad = function(q0, q1, s0, s1, t, result) {
  797. //>>includeStart('debug', pragmas.debug);
  798. Check.typeOf.object('q0', q0);
  799. Check.typeOf.object('q1', q1);
  800. Check.typeOf.object('s0', s0);
  801. Check.typeOf.object('s1', s1);
  802. Check.typeOf.number('t', t);
  803. Check.typeOf.object('result', result);
  804. //>>includeEnd('debug');
  805. var slerp0 = Quaternion.fastSlerp(q0, q1, t, squadScratchQuaternion0);
  806. var slerp1 = Quaternion.fastSlerp(s0, s1, t, squadScratchQuaternion1);
  807. return Quaternion.fastSlerp(slerp0, slerp1, 2.0 * t * (1.0 - t), result);
  808. };
  809. /**
  810. * Compares the provided quaternions componentwise and returns
  811. * <code>true</code> if they are equal, <code>false</code> otherwise.
  812. *
  813. * @param {Quaternion} [left] The first quaternion.
  814. * @param {Quaternion} [right] The second quaternion.
  815. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  816. */
  817. Quaternion.equals = function(left, right) {
  818. return (left === right) ||
  819. ((defined(left)) &&
  820. (defined(right)) &&
  821. (left.x === right.x) &&
  822. (left.y === right.y) &&
  823. (left.z === right.z) &&
  824. (left.w === right.w));
  825. };
  826. /**
  827. * Compares the provided quaternions componentwise and returns
  828. * <code>true</code> if they are within the provided epsilon,
  829. * <code>false</code> otherwise.
  830. *
  831. * @param {Quaternion} [left] The first quaternion.
  832. * @param {Quaternion} [right] The second quaternion.
  833. * @param {Number} epsilon The epsilon to use for equality testing.
  834. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  835. */
  836. Quaternion.equalsEpsilon = function(left, right, epsilon) {
  837. //>>includeStart('debug', pragmas.debug);
  838. Check.typeOf.number('epsilon', epsilon);
  839. //>>includeEnd('debug');
  840. return (left === right) ||
  841. ((defined(left)) &&
  842. (defined(right)) &&
  843. (Math.abs(left.x - right.x) <= epsilon) &&
  844. (Math.abs(left.y - right.y) <= epsilon) &&
  845. (Math.abs(left.z - right.z) <= epsilon) &&
  846. (Math.abs(left.w - right.w) <= epsilon));
  847. };
  848. /**
  849. * An immutable Quaternion instance initialized to (0.0, 0.0, 0.0, 0.0).
  850. *
  851. * @type {Quaternion}
  852. * @constant
  853. */
  854. Quaternion.ZERO = freezeObject(new Quaternion(0.0, 0.0, 0.0, 0.0));
  855. /**
  856. * An immutable Quaternion instance initialized to (0.0, 0.0, 0.0, 1.0).
  857. *
  858. * @type {Quaternion}
  859. * @constant
  860. */
  861. Quaternion.IDENTITY = freezeObject(new Quaternion(0.0, 0.0, 0.0, 1.0));
  862. /**
  863. * Duplicates this Quaternion instance.
  864. *
  865. * @param {Quaternion} [result] The object onto which to store the result.
  866. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
  867. */
  868. Quaternion.prototype.clone = function(result) {
  869. return Quaternion.clone(this, result);
  870. };
  871. /**
  872. * Compares this and the provided quaternion componentwise and returns
  873. * <code>true</code> if they are equal, <code>false</code> otherwise.
  874. *
  875. * @param {Quaternion} [right] The right hand side quaternion.
  876. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  877. */
  878. Quaternion.prototype.equals = function(right) {
  879. return Quaternion.equals(this, right);
  880. };
  881. /**
  882. * Compares this and the provided quaternion componentwise and returns
  883. * <code>true</code> if they are within the provided epsilon,
  884. * <code>false</code> otherwise.
  885. *
  886. * @param {Quaternion} [right] The right hand side quaternion.
  887. * @param {Number} epsilon The epsilon to use for equality testing.
  888. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  889. */
  890. Quaternion.prototype.equalsEpsilon = function(right, epsilon) {
  891. return Quaternion.equalsEpsilon(this, right, epsilon);
  892. };
  893. /**
  894. * Returns a string representing this quaternion in the format (x, y, z, w).
  895. *
  896. * @returns {String} A string representing this Quaternion.
  897. */
  898. Quaternion.prototype.toString = function() {
  899. return '(' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ')';
  900. };
  901. export default Quaternion;