Source: Core/Transforms.js

  1. /*global define*/
  2. define([
  3. '../ThirdParty/when',
  4. './Cartesian2',
  5. './Cartesian3',
  6. './Cartesian4',
  7. './Cartographic',
  8. './defaultValue',
  9. './defined',
  10. './deprecationWarning',
  11. './DeveloperError',
  12. './EarthOrientationParameters',
  13. './EarthOrientationParametersSample',
  14. './Ellipsoid',
  15. './HeadingPitchRoll',
  16. './Iau2006XysData',
  17. './Iau2006XysSample',
  18. './JulianDate',
  19. './Math',
  20. './Matrix3',
  21. './Matrix4',
  22. './Quaternion',
  23. './TimeConstants'
  24. ], function(
  25. when,
  26. Cartesian2,
  27. Cartesian3,
  28. Cartesian4,
  29. Cartographic,
  30. defaultValue,
  31. defined,
  32. deprecationWarning,
  33. DeveloperError,
  34. EarthOrientationParameters,
  35. EarthOrientationParametersSample,
  36. Ellipsoid,
  37. HeadingPitchRoll,
  38. Iau2006XysData,
  39. Iau2006XysSample,
  40. JulianDate,
  41. CesiumMath,
  42. Matrix3,
  43. Matrix4,
  44. Quaternion,
  45. TimeConstants) {
  46. 'use strict';
  47. /**
  48. * Contains functions for transforming positions to various reference frames.
  49. *
  50. * @exports Transforms
  51. */
  52. var Transforms = {};
  53. var eastNorthUpToFixedFrameNormal = new Cartesian3();
  54. var eastNorthUpToFixedFrameTangent = new Cartesian3();
  55. var eastNorthUpToFixedFrameBitangent = new Cartesian3();
  56. /**
  57. * Computes a 4x4 transformation matrix from a reference frame with an east-north-up axes
  58. * centered at the provided origin to the provided ellipsoid's fixed reference frame.
  59. * The local axes are defined as:
  60. * <ul>
  61. * <li>The <code>x</code> axis points in the local east direction.</li>
  62. * <li>The <code>y</code> axis points in the local north direction.</li>
  63. * <li>The <code>z</code> axis points in the direction of the ellipsoid surface normal which passes through the position.</li>
  64. * </ul>
  65. *
  66. * @param {Cartesian3} origin The center point of the local reference frame.
  67. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  68. * @param {Matrix4} [result] The object onto which to store the result.
  69. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
  70. *
  71. * @example
  72. * // Get the transform from local east-north-up at cartographic (0.0, 0.0) to Earth's fixed frame.
  73. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  74. * var transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
  75. */
  76. Transforms.eastNorthUpToFixedFrame = function(origin, ellipsoid, result) {
  77. //>>includeStart('debug', pragmas.debug);
  78. if (!defined(origin)) {
  79. throw new DeveloperError('origin is required.');
  80. }
  81. //>>includeEnd('debug');
  82. // If x and y are zero, assume origin is at a pole, which is a special case.
  83. if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) &&
  84. CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) {
  85. var sign = CesiumMath.sign(origin.z);
  86. if (!defined(result)) {
  87. return new Matrix4(
  88. 0.0, -sign, 0.0, origin.x,
  89. 1.0, 0.0, 0.0, origin.y,
  90. 0.0, 0.0, sign, origin.z,
  91. 0.0, 0.0, 0.0, 1.0);
  92. }
  93. result[0] = 0.0;
  94. result[1] = 1.0;
  95. result[2] = 0.0;
  96. result[3] = 0.0;
  97. result[4] = -sign;
  98. result[5] = 0.0;
  99. result[6] = 0.0;
  100. result[7] = 0.0;
  101. result[8] = 0.0;
  102. result[9] = 0.0;
  103. result[10] = sign;
  104. result[11] = 0.0;
  105. result[12] = origin.x;
  106. result[13] = origin.y;
  107. result[14] = origin.z;
  108. result[15] = 1.0;
  109. return result;
  110. }
  111. var normal = eastNorthUpToFixedFrameNormal;
  112. var tangent = eastNorthUpToFixedFrameTangent;
  113. var bitangent = eastNorthUpToFixedFrameBitangent;
  114. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  115. ellipsoid.geodeticSurfaceNormal(origin, normal);
  116. tangent.x = -origin.y;
  117. tangent.y = origin.x;
  118. tangent.z = 0.0;
  119. Cartesian3.normalize(tangent, tangent);
  120. Cartesian3.cross(normal, tangent, bitangent);
  121. if (!defined(result)) {
  122. return new Matrix4(
  123. tangent.x, bitangent.x, normal.x, origin.x,
  124. tangent.y, bitangent.y, normal.y, origin.y,
  125. tangent.z, bitangent.z, normal.z, origin.z,
  126. 0.0, 0.0, 0.0, 1.0);
  127. }
  128. result[0] = tangent.x;
  129. result[1] = tangent.y;
  130. result[2] = tangent.z;
  131. result[3] = 0.0;
  132. result[4] = bitangent.x;
  133. result[5] = bitangent.y;
  134. result[6] = bitangent.z;
  135. result[7] = 0.0;
  136. result[8] = normal.x;
  137. result[9] = normal.y;
  138. result[10] = normal.z;
  139. result[11] = 0.0;
  140. result[12] = origin.x;
  141. result[13] = origin.y;
  142. result[14] = origin.z;
  143. result[15] = 1.0;
  144. return result;
  145. };
  146. var northEastDownToFixedFrameNormal = new Cartesian3();
  147. var northEastDownToFixedFrameTangent = new Cartesian3();
  148. var northEastDownToFixedFrameBitangent = new Cartesian3();
  149. /**
  150. * Computes a 4x4 transformation matrix from a reference frame with an north-east-down axes
  151. * centered at the provided origin to the provided ellipsoid's fixed reference frame.
  152. * The local axes are defined as:
  153. * <ul>
  154. * <li>The <code>x</code> axis points in the local north direction.</li>
  155. * <li>The <code>y</code> axis points in the local east direction.</li>
  156. * <li>The <code>z</code> axis points in the opposite direction of the ellipsoid surface normal which passes through the position.</li>
  157. * </ul>
  158. *
  159. * @param {Cartesian3} origin The center point of the local reference frame.
  160. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  161. * @param {Matrix4} [result] The object onto which to store the result.
  162. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
  163. *
  164. * @example
  165. * // Get the transform from local north-east-down at cartographic (0.0, 0.0) to Earth's fixed frame.
  166. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  167. * var transform = Cesium.Transforms.northEastDownToFixedFrame(center);
  168. */
  169. Transforms.northEastDownToFixedFrame = function(origin, ellipsoid, result) {
  170. //>>includeStart('debug', pragmas.debug);
  171. if (!defined(origin)) {
  172. throw new DeveloperError('origin is required.');
  173. }
  174. //>>includeEnd('debug');
  175. if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) &&
  176. CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) {
  177. // The poles are special cases. If x and y are zero, assume origin is at a pole.
  178. var sign = CesiumMath.sign(origin.z);
  179. if (!defined(result)) {
  180. return new Matrix4(
  181. -sign, 0.0, 0.0, origin.x,
  182. 0.0, 1.0, 0.0, origin.y,
  183. 0.0, 0.0, -sign, origin.z,
  184. 0.0, 0.0, 0.0, 1.0);
  185. }
  186. result[0] = -sign;
  187. result[1] = 0.0;
  188. result[2] = 0.0;
  189. result[3] = 0.0;
  190. result[4] = 0.0;
  191. result[5] = 1.0;
  192. result[6] = 0.0;
  193. result[7] = 0.0;
  194. result[8] = 0.0;
  195. result[9] = 0.0;
  196. result[10] = -sign;
  197. result[11] = 0.0;
  198. result[12] = origin.x;
  199. result[13] = origin.y;
  200. result[14] = origin.z;
  201. result[15] = 1.0;
  202. return result;
  203. }
  204. var normal = northEastDownToFixedFrameNormal;
  205. var tangent = northEastDownToFixedFrameTangent;
  206. var bitangent = northEastDownToFixedFrameBitangent;
  207. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  208. ellipsoid.geodeticSurfaceNormal(origin, normal);
  209. tangent.x = -origin.y;
  210. tangent.y = origin.x;
  211. tangent.z = 0.0;
  212. Cartesian3.normalize(tangent, tangent);
  213. Cartesian3.cross(normal, tangent, bitangent);
  214. if (!defined(result)) {
  215. return new Matrix4(
  216. bitangent.x, tangent.x, -normal.x, origin.x,
  217. bitangent.y, tangent.y, -normal.y, origin.y,
  218. bitangent.z, tangent.z, -normal.z, origin.z,
  219. 0.0, 0.0, 0.0, 1.0);
  220. }
  221. result[0] = bitangent.x;
  222. result[1] = bitangent.y;
  223. result[2] = bitangent.z;
  224. result[3] = 0.0;
  225. result[4] = tangent.x;
  226. result[5] = tangent.y;
  227. result[6] = tangent.z;
  228. result[7] = 0.0;
  229. result[8] = -normal.x;
  230. result[9] = -normal.y;
  231. result[10] = -normal.z;
  232. result[11] = 0.0;
  233. result[12] = origin.x;
  234. result[13] = origin.y;
  235. result[14] = origin.z;
  236. result[15] = 1.0;
  237. return result;
  238. };
  239. /**
  240. * Computes a 4x4 transformation matrix from a reference frame with an north-up-east axes
  241. * centered at the provided origin to the provided ellipsoid's fixed reference frame.
  242. * The local axes are defined as:
  243. * <ul>
  244. * <li>The <code>x</code> axis points in the local north direction.</li>
  245. * <li>The <code>y</code> axis points in the direction of the ellipsoid surface normal which passes through the position.</li>
  246. * <li>The <code>z</code> axis points in the local east direction.</li>
  247. * </ul>
  248. *
  249. * @param {Cartesian3} origin The center point of the local reference frame.
  250. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  251. * @param {Matrix4} [result] The object onto which to store the result.
  252. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
  253. *
  254. * @example
  255. * // Get the transform from local north-up-east at cartographic (0.0, 0.0) to Earth's fixed frame.
  256. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  257. * var transform = Cesium.Transforms.northUpEastToFixedFrame(center);
  258. */
  259. Transforms.northUpEastToFixedFrame = function(origin, ellipsoid, result) {
  260. //>>includeStart('debug', pragmas.debug);
  261. if (!defined(origin)) {
  262. throw new DeveloperError('origin is required.');
  263. }
  264. //>>includeEnd('debug');
  265. // If x and y are zero, assume origin is at a pole, which is a special case.
  266. if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) &&
  267. CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) {
  268. var sign = CesiumMath.sign(origin.z);
  269. if (!defined(result)) {
  270. return new Matrix4(
  271. -sign, 0.0, 0.0, origin.x,
  272. 0.0, 0.0, 1.0, origin.y,
  273. 0.0, sign, 0.0, origin.z,
  274. 0.0, 0.0, 0.0, 1.0);
  275. }
  276. result[0] = -sign;
  277. result[1] = 0.0;
  278. result[2] = 0.0;
  279. result[3] = 0.0;
  280. result[4] = 0.0;
  281. result[5] = 0.0;
  282. result[6] = sign;
  283. result[7] = 0.0;
  284. result[8] = 0.0;
  285. result[9] = 1.0;
  286. result[10] = 0.0;
  287. result[11] = 0.0;
  288. result[12] = origin.x;
  289. result[13] = origin.y;
  290. result[14] = origin.z;
  291. result[15] = 1.0;
  292. return result;
  293. }
  294. var normal = eastNorthUpToFixedFrameNormal;
  295. var tangent = eastNorthUpToFixedFrameTangent;
  296. var bitangent = eastNorthUpToFixedFrameBitangent;
  297. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  298. ellipsoid.geodeticSurfaceNormal(origin, normal);
  299. tangent.x = -origin.y;
  300. tangent.y = origin.x;
  301. tangent.z = 0.0;
  302. Cartesian3.normalize(tangent, tangent);
  303. Cartesian3.cross(normal, tangent, bitangent);
  304. if (!defined(result)) {
  305. return new Matrix4(
  306. bitangent.x, normal.x, tangent.x, origin.x,
  307. bitangent.y, normal.y, tangent.y, origin.y,
  308. bitangent.z, normal.z, tangent.z, origin.z,
  309. 0.0, 0.0, 0.0, 1.0);
  310. }
  311. result[0] = bitangent.x;
  312. result[1] = bitangent.y;
  313. result[2] = bitangent.z;
  314. result[3] = 0.0;
  315. result[4] = normal.x;
  316. result[5] = normal.y;
  317. result[6] = normal.z;
  318. result[7] = 0.0;
  319. result[8] = tangent.x;
  320. result[9] = tangent.y;
  321. result[10] = tangent.z;
  322. result[11] = 0.0;
  323. result[12] = origin.x;
  324. result[13] = origin.y;
  325. result[14] = origin.z;
  326. result[15] = 1.0;
  327. return result;
  328. };
  329. /**
  330. * Computes a 4x4 transformation matrix from a reference frame with an north-west-up axes
  331. * centered at the provided origin to the provided ellipsoid's fixed reference frame.
  332. * The local axes are defined as:
  333. * <ul>
  334. * <li>The <code>x</code> axis points in the local north direction.</li>
  335. * <li>The <code>y</code> axis points in the local west direction.</li>
  336. * <li>The <code>z</code> axis points in the direction of the ellipsoid surface normal which passes through the position.</li>
  337. * </ul>
  338. *
  339. * @param {Cartesian3} origin The center point of the local reference frame.
  340. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  341. * @param {Matrix4} [result] The object onto which to store the result.
  342. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
  343. *
  344. * @example
  345. * // Get the transform from local north-West-Up at cartographic (0.0, 0.0) to Earth's fixed frame.
  346. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  347. * var transform = Cesium.Transforms.northWestUpToFixedFrame(center);
  348. */
  349. Transforms.northWestUpToFixedFrame = function(origin, ellipsoid, result) {
  350. //>>includeStart('debug', pragmas.debug);
  351. if (!defined(origin)) {
  352. throw new DeveloperError('origin is required.');
  353. }
  354. //>>includeEnd('debug');
  355. // If x and y are zero, assume origin is at a pole, which is a special case.
  356. if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) &&
  357. CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) {
  358. var sign = CesiumMath.sign(origin.z);
  359. if (!defined(result)) {
  360. return new Matrix4(
  361. -sign, 0.0, 0.0, origin.x,
  362. 0.0, -1.0, 0.0, origin.y,
  363. 0.0, 0.0, sign, origin.z,
  364. 0.0, 0.0, 0.0, 1.0);
  365. }
  366. result[0] = -sign;
  367. result[1] = 0.0;
  368. result[2] = 0.0;
  369. result[3] = 0.0;
  370. result[4] = 0.0;
  371. result[5] = -1.0;
  372. result[6] = 0.0;
  373. result[7] = 0.0;
  374. result[8] = 0.0;
  375. result[9] = 0.0;
  376. result[10] = sign;
  377. result[11] = 0.0;
  378. result[12] = origin.x;
  379. result[13] = origin.y;
  380. result[14] = origin.z;
  381. result[15] = 1.0;
  382. return result;
  383. }
  384. var normal = eastNorthUpToFixedFrameNormal;//Up
  385. var tangent = eastNorthUpToFixedFrameTangent;//East
  386. var bitangent = eastNorthUpToFixedFrameBitangent;//North
  387. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  388. ellipsoid.geodeticSurfaceNormal(origin, normal);
  389. tangent.x = -origin.y;
  390. tangent.y = origin.x;
  391. tangent.z = 0.0;
  392. Cartesian3.normalize(tangent, tangent);
  393. Cartesian3.cross(normal, tangent, bitangent);
  394. if (!defined(result)) {
  395. return new Matrix4(
  396. bitangent.x, -tangent.x, normal.x, origin.x,
  397. bitangent.y, -tangent.y, normal.y, origin.y,
  398. bitangent.z, -tangent.z, normal.z, origin.z,
  399. 0.0, 0.0, 0.0, 1.0);
  400. }
  401. result[0] = bitangent.x;
  402. result[1] = bitangent.y;
  403. result[2] = bitangent.z;
  404. result[3] = 0.0;
  405. result[4] = -tangent.x;
  406. result[5] = -tangent.y;
  407. result[6] = -tangent.z;
  408. result[7] = 0.0;
  409. result[8] = normal.x;
  410. result[9] = normal.y;
  411. result[10] = normal.z;
  412. result[11] = 0.0;
  413. result[12] = origin.x;
  414. result[13] = origin.y;
  415. result[14] = origin.z;
  416. result[15] = 1.0;
  417. return result;
  418. };
  419. var scratchHPRQuaternion = new Quaternion();
  420. var scratchScale = new Cartesian3(1.0, 1.0, 1.0);
  421. var scratchHPRMatrix4 = new Matrix4();
  422. /**
  423. * Computes a 4x4 transformation matrix from a reference frame with axes computed from the heading-pitch-roll angles
  424. * centered at the provided origin to the provided ellipsoid's fixed reference frame. Heading is the rotation from the local north
  425. * direction where a positive angle is increasing eastward. Pitch is the rotation from the local east-north plane. Positive pitch angles
  426. * are above the plane. Negative pitch angles are below the plane. Roll is the first rotation applied about the local east axis.
  427. *
  428. * @param {Cartesian3} origin The center point of the local reference frame.
  429. * @param {HeadingPitchRoll} headingPitchRoll The heading, pitch, and roll.
  430. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  431. * @param {Matrix4} [result] The object onto which to store the result.
  432. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
  433. *
  434. * @example
  435. * // Get the transform from local heading-pitch-roll at cartographic (0.0, 0.0) to Earth's fixed frame.
  436. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  437. * var heading = -Cesium.Math.PI_OVER_TWO;
  438. * var pitch = Cesium.Math.PI_OVER_FOUR;
  439. * var roll = 0.0;
  440. * var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
  441. * var transform = Cesium.Transforms.headingPitchRollToFixedFrame(center, hpr);
  442. */
  443. Transforms.headingPitchRollToFixedFrame = function(origin, headingPitchRoll, pitch, roll, ellipsoid, result) {
  444. var heading;
  445. if (typeof headingPitchRoll === 'object') {
  446. // Shift arguments using assignments to encourage JIT optimization.
  447. ellipsoid = pitch;
  448. result = roll;
  449. heading = headingPitchRoll.heading;
  450. pitch = headingPitchRoll.pitch;
  451. roll = headingPitchRoll.roll;
  452. } else {
  453. deprecationWarning('headingPitchRollToFixedFrame', 'headingPitchRollToFixedFrame with separate heading, pitch, and roll arguments was deprecated in 1.27. It will be removed in 1.30. Use a HeadingPitchRoll object.');
  454. heading = headingPitchRoll;
  455. }
  456. // checks for required parameters happen in the called functions
  457. var hprQuaternion = Quaternion.fromHeadingPitchRoll(heading, pitch, roll, scratchHPRQuaternion);
  458. var hprMatrix = Matrix4.fromTranslationQuaternionRotationScale(Cartesian3.ZERO, hprQuaternion, scratchScale, scratchHPRMatrix4);
  459. result = Transforms.eastNorthUpToFixedFrame(origin, ellipsoid, result);
  460. return Matrix4.multiply(result, hprMatrix, result);
  461. };
  462. var scratchHPR = new HeadingPitchRoll();
  463. var scratchENUMatrix4 = new Matrix4();
  464. var scratchHPRMatrix3 = new Matrix3();
  465. /**
  466. * Computes a quaternion from a reference frame with axes computed from the heading-pitch-roll angles
  467. * centered at the provided origin. Heading is the rotation from the local north
  468. * direction where a positive angle is increasing eastward. Pitch is the rotation from the local east-north plane. Positive pitch angles
  469. * are above the plane. Negative pitch angles are below the plane. Roll is the first rotation applied about the local east axis.
  470. *
  471. * @param {Cartesian3} origin The center point of the local reference frame.
  472. * @param {HeadingPitchRoll} headingPitchRoll The heading, pitch, and roll.
  473. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  474. * @param {Quaternion} [result] The object onto which to store the result.
  475. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if none was provided.
  476. *
  477. * @example
  478. * // Get the quaternion from local heading-pitch-roll at cartographic (0.0, 0.0) to Earth's fixed frame.
  479. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  480. * var heading = -Cesium.Math.PI_OVER_TWO;
  481. * var pitch = Cesium.Math.PI_OVER_FOUR;
  482. * var roll = 0.0;
  483. * var hpr = new HeadingPitchRoll(heading, pitch, roll);
  484. * var quaternion = Cesium.Transforms.headingPitchRollQuaternion(center, hpr);
  485. */
  486. Transforms.headingPitchRollQuaternion = function(origin, headingPitchRoll, pitch, roll, ellipsoid, result) {
  487. var hpr;
  488. if (typeof headingPitchRoll === 'object') {
  489. // Shift arguments using assignment to encourage JIT optimization.
  490. hpr = headingPitchRoll;
  491. ellipsoid = pitch;
  492. result = roll;
  493. } else {
  494. deprecationWarning('headingPitchRollQuaternion', 'headingPitchRollQuaternion with separate heading, pitch, and roll arguments was deprecated in 1.27. It will be removed in 1.30. Use a HeadingPitchRoll object.');
  495. scratchHPR.heading = headingPitchRoll;
  496. scratchHPR.pitch = pitch;
  497. scratchHPR.roll = roll;
  498. hpr = scratchHPR;
  499. }
  500. // checks for required parameters happen in the called functions
  501. var transform = Transforms.headingPitchRollToFixedFrame(origin, hpr, ellipsoid, scratchENUMatrix4);
  502. var rotation = Matrix4.getRotation(transform, scratchHPRMatrix3);
  503. return Quaternion.fromRotationMatrix(rotation, result);
  504. };
  505. var gmstConstant0 = 6 * 3600 + 41 * 60 + 50.54841;
  506. var gmstConstant1 = 8640184.812866;
  507. var gmstConstant2 = 0.093104;
  508. var gmstConstant3 = -6.2E-6;
  509. var rateCoef = 1.1772758384668e-19;
  510. var wgs84WRPrecessing = 7.2921158553E-5;
  511. var twoPiOverSecondsInDay = CesiumMath.TWO_PI / 86400.0;
  512. var dateInUtc = new JulianDate();
  513. /**
  514. * Computes a rotation matrix to transform a point or vector from True Equator Mean Equinox (TEME) axes to the
  515. * pseudo-fixed axes at a given time. This method treats the UT1 time standard as equivalent to UTC.
  516. *
  517. * @param {JulianDate} date The time at which to compute the rotation matrix.
  518. * @param {Matrix3} [result] The object onto which to store the result.
  519. * @returns {Matrix3} The modified result parameter or a new Matrix3 instance if none was provided.
  520. *
  521. * @example
  522. * //Set the view to in the inertial frame.
  523. * scene.preRender.addEventListener(function(scene, time) {
  524. * var now = Cesium.JulianDate.now();
  525. * var offset = Cesium.Matrix4.multiplyByPoint(camera.transform, camera.position, new Cesium.Cartesian3());
  526. * var transform = Cesium.Matrix4.fromRotationTranslation(Cesium.Transforms.computeTemeToPseudoFixedMatrix(now));
  527. * var inverseTransform = Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4());
  528. * Cesium.Matrix4.multiplyByPoint(inverseTransform, offset, offset);
  529. * camera.lookAtTransform(transform, offset);
  530. * });
  531. */
  532. Transforms.computeTemeToPseudoFixedMatrix = function (date, result) {
  533. //>>includeStart('debug', pragmas.debug);
  534. if (!defined(date)) {
  535. throw new DeveloperError('date is required.');
  536. }
  537. //>>includeEnd('debug');
  538. // GMST is actually computed using UT1. We're using UTC as an approximation of UT1.
  539. // We do not want to use the function like convertTaiToUtc in JulianDate because
  540. // we explicitly do not want to fail when inside the leap second.
  541. dateInUtc = JulianDate.addSeconds(date, -JulianDate.computeTaiMinusUtc(date), dateInUtc);
  542. var utcDayNumber = dateInUtc.dayNumber;
  543. var utcSecondsIntoDay = dateInUtc.secondsOfDay;
  544. var t;
  545. var diffDays = utcDayNumber - 2451545;
  546. if (utcSecondsIntoDay >= 43200.0) {
  547. t = (diffDays + 0.5) / TimeConstants.DAYS_PER_JULIAN_CENTURY;
  548. } else {
  549. t = (diffDays - 0.5) / TimeConstants.DAYS_PER_JULIAN_CENTURY;
  550. }
  551. var gmst0 = gmstConstant0 + t * (gmstConstant1 + t * (gmstConstant2 + t * gmstConstant3));
  552. var angle = (gmst0 * twoPiOverSecondsInDay) % CesiumMath.TWO_PI;
  553. var ratio = wgs84WRPrecessing + rateCoef * (utcDayNumber - 2451545.5);
  554. var secondsSinceMidnight = (utcSecondsIntoDay + TimeConstants.SECONDS_PER_DAY * 0.5) % TimeConstants.SECONDS_PER_DAY;
  555. var gha = angle + (ratio * secondsSinceMidnight);
  556. var cosGha = Math.cos(gha);
  557. var sinGha = Math.sin(gha);
  558. if (!defined(result)) {
  559. return new Matrix3(cosGha, sinGha, 0.0,
  560. -sinGha, cosGha, 0.0,
  561. 0.0, 0.0, 1.0);
  562. }
  563. result[0] = cosGha;
  564. result[1] = -sinGha;
  565. result[2] = 0.0;
  566. result[3] = sinGha;
  567. result[4] = cosGha;
  568. result[5] = 0.0;
  569. result[6] = 0.0;
  570. result[7] = 0.0;
  571. result[8] = 1.0;
  572. return result;
  573. };
  574. /**
  575. * The source of IAU 2006 XYS data, used for computing the transformation between the
  576. * Fixed and ICRF axes.
  577. * @type {Iau2006XysData}
  578. *
  579. * @see Transforms.computeIcrfToFixedMatrix
  580. * @see Transforms.computeFixedToIcrfMatrix
  581. *
  582. * @private
  583. */
  584. Transforms.iau2006XysData = new Iau2006XysData();
  585. /**
  586. * The source of Earth Orientation Parameters (EOP) data, used for computing the transformation
  587. * between the Fixed and ICRF axes. By default, zero values are used for all EOP values,
  588. * yielding a reasonable but not completely accurate representation of the ICRF axes.
  589. * @type {EarthOrientationParameters}
  590. *
  591. * @see Transforms.computeIcrfToFixedMatrix
  592. * @see Transforms.computeFixedToIcrfMatrix
  593. *
  594. * @private
  595. */
  596. Transforms.earthOrientationParameters = EarthOrientationParameters.NONE;
  597. var ttMinusTai = 32.184;
  598. var j2000ttDays = 2451545.0;
  599. /**
  600. * Preloads the data necessary to transform between the ICRF and Fixed axes, in either
  601. * direction, over a given interval. This function returns a promise that, when resolved,
  602. * indicates that the preload has completed.
  603. *
  604. * @param {TimeInterval} timeInterval The interval to preload.
  605. * @returns {Promise.<undefined>} A promise that, when resolved, indicates that the preload has completed
  606. * and evaluation of the transformation between the fixed and ICRF axes will
  607. * no longer return undefined for a time inside the interval.
  608. *
  609. *
  610. * @example
  611. * var interval = new Cesium.TimeInterval(...);
  612. * when(Cesium.Transforms.preloadIcrfFixed(interval), function() {
  613. * // the data is now loaded
  614. * });
  615. *
  616. * @see Transforms.computeIcrfToFixedMatrix
  617. * @see Transforms.computeFixedToIcrfMatrix
  618. * @see when
  619. */
  620. Transforms.preloadIcrfFixed = function(timeInterval) {
  621. var startDayTT = timeInterval.start.dayNumber;
  622. var startSecondTT = timeInterval.start.secondsOfDay + ttMinusTai;
  623. var stopDayTT = timeInterval.stop.dayNumber;
  624. var stopSecondTT = timeInterval.stop.secondsOfDay + ttMinusTai;
  625. var xysPromise = Transforms.iau2006XysData.preload(startDayTT, startSecondTT, stopDayTT, stopSecondTT);
  626. var eopPromise = Transforms.earthOrientationParameters.getPromiseToLoad();
  627. return when.all([xysPromise, eopPromise]);
  628. };
  629. /**
  630. * Computes a rotation matrix to transform a point or vector from the International Celestial
  631. * Reference Frame (GCRF/ICRF) inertial frame axes to the Earth-Fixed frame axes (ITRF)
  632. * at a given time. This function may return undefined if the data necessary to
  633. * do the transformation is not yet loaded.
  634. *
  635. * @param {JulianDate} date The time at which to compute the rotation matrix.
  636. * @param {Matrix3} [result] The object onto which to store the result. If this parameter is
  637. * not specified, a new instance is created and returned.
  638. * @returns {Matrix3} The rotation matrix, or undefined if the data necessary to do the
  639. * transformation is not yet loaded.
  640. *
  641. *
  642. * @example
  643. * scene.preRender.addEventListener(function(scene, time) {
  644. * var icrfToFixed = Cesium.Transforms.computeIcrfToFixedMatrix(time);
  645. * if (Cesium.defined(icrfToFixed)) {
  646. * var offset = Cesium.Matrix4.multiplyByPoint(camera.transform, camera.position, new Cesium.Cartesian3());
  647. * var transform = Cesium.Matrix4.fromRotationTranslation(icrfToFixed)
  648. * var inverseTransform = Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4());
  649. * Cesium.Matrix4.multiplyByPoint(inverseTransform, offset, offset);
  650. * camera.lookAtTransform(transform, offset);
  651. * }
  652. * });
  653. *
  654. * @see Transforms.preloadIcrfFixed
  655. */
  656. Transforms.computeIcrfToFixedMatrix = function(date, result) {
  657. //>>includeStart('debug', pragmas.debug);
  658. if (!defined(date)) {
  659. throw new DeveloperError('date is required.');
  660. }
  661. //>>includeEnd('debug');
  662. if (!defined(result)) {
  663. result = new Matrix3();
  664. }
  665. var fixedToIcrfMtx = Transforms.computeFixedToIcrfMatrix(date, result);
  666. if (!defined(fixedToIcrfMtx)) {
  667. return undefined;
  668. }
  669. return Matrix3.transpose(fixedToIcrfMtx, result);
  670. };
  671. var xysScratch = new Iau2006XysSample(0.0, 0.0, 0.0);
  672. var eopScratch = new EarthOrientationParametersSample(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
  673. var rotation1Scratch = new Matrix3();
  674. var rotation2Scratch = new Matrix3();
  675. /**
  676. * Computes a rotation matrix to transform a point or vector from the Earth-Fixed frame axes (ITRF)
  677. * to the International Celestial Reference Frame (GCRF/ICRF) inertial frame axes
  678. * at a given time. This function may return undefined if the data necessary to
  679. * do the transformation is not yet loaded.
  680. *
  681. * @param {JulianDate} date The time at which to compute the rotation matrix.
  682. * @param {Matrix3} [result] The object onto which to store the result. If this parameter is
  683. * not specified, a new instance is created and returned.
  684. * @returns {Matrix3} The rotation matrix, or undefined if the data necessary to do the
  685. * transformation is not yet loaded.
  686. *
  687. *
  688. * @example
  689. * // Transform a point from the ICRF axes to the Fixed axes.
  690. * var now = Cesium.JulianDate.now();
  691. * var pointInFixed = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  692. * var fixedToIcrf = Cesium.Transforms.computeIcrfToFixedMatrix(now);
  693. * var pointInInertial = new Cesium.Cartesian3();
  694. * if (Cesium.defined(fixedToIcrf)) {
  695. * pointInInertial = Cesium.Matrix3.multiplyByVector(fixedToIcrf, pointInFixed, pointInInertial);
  696. * }
  697. *
  698. * @see Transforms.preloadIcrfFixed
  699. */
  700. Transforms.computeFixedToIcrfMatrix = function(date, result) {
  701. //>>includeStart('debug', pragmas.debug);
  702. if (!defined(date)) {
  703. throw new DeveloperError('date is required.');
  704. }
  705. //>>includeEnd('debug');
  706. if (!defined(result)) {
  707. result = new Matrix3();
  708. }
  709. // Compute pole wander
  710. var eop = Transforms.earthOrientationParameters.compute(date, eopScratch);
  711. if (!defined(eop)) {
  712. return undefined;
  713. }
  714. // There is no external conversion to Terrestrial Time (TT).
  715. // So use International Atomic Time (TAI) and convert using offsets.
  716. // Here we are assuming that dayTT and secondTT are positive
  717. var dayTT = date.dayNumber;
  718. // It's possible here that secondTT could roll over 86400
  719. // This does not seem to affect the precision (unit tests check for this)
  720. var secondTT = date.secondsOfDay + ttMinusTai;
  721. var xys = Transforms.iau2006XysData.computeXysRadians(dayTT, secondTT, xysScratch);
  722. if (!defined(xys)) {
  723. return undefined;
  724. }
  725. var x = xys.x + eop.xPoleOffset;
  726. var y = xys.y + eop.yPoleOffset;
  727. // Compute XYS rotation
  728. var a = 1.0 / (1.0 + Math.sqrt(1.0 - x * x - y * y));
  729. var rotation1 = rotation1Scratch;
  730. rotation1[0] = 1.0 - a * x * x;
  731. rotation1[3] = -a * x * y;
  732. rotation1[6] = x;
  733. rotation1[1] = -a * x * y;
  734. rotation1[4] = 1 - a * y * y;
  735. rotation1[7] = y;
  736. rotation1[2] = -x;
  737. rotation1[5] = -y;
  738. rotation1[8] = 1 - a * (x * x + y * y);
  739. var rotation2 = Matrix3.fromRotationZ(-xys.s, rotation2Scratch);
  740. var matrixQ = Matrix3.multiply(rotation1, rotation2, rotation1Scratch);
  741. // Similar to TT conversions above
  742. // It's possible here that secondTT could roll over 86400
  743. // This does not seem to affect the precision (unit tests check for this)
  744. var dateUt1day = date.dayNumber;
  745. var dateUt1sec = date.secondsOfDay - JulianDate.computeTaiMinusUtc(date) + eop.ut1MinusUtc;
  746. // Compute Earth rotation angle
  747. // The IERS standard for era is
  748. // era = 0.7790572732640 + 1.00273781191135448 * Tu
  749. // where
  750. // Tu = JulianDateInUt1 - 2451545.0
  751. // However, you get much more precision if you make the following simplification
  752. // era = a + (1 + b) * (JulianDayNumber + FractionOfDay - 2451545)
  753. // era = a + (JulianDayNumber - 2451545) + FractionOfDay + b (JulianDayNumber - 2451545 + FractionOfDay)
  754. // era = a + FractionOfDay + b (JulianDayNumber - 2451545 + FractionOfDay)
  755. // since (JulianDayNumber - 2451545) represents an integer number of revolutions which will be discarded anyway.
  756. var daysSinceJ2000 = dateUt1day - 2451545;
  757. var fractionOfDay = dateUt1sec / TimeConstants.SECONDS_PER_DAY;
  758. var era = 0.7790572732640 + fractionOfDay + 0.00273781191135448 * (daysSinceJ2000 + fractionOfDay);
  759. era = (era % 1.0) * CesiumMath.TWO_PI;
  760. var earthRotation = Matrix3.fromRotationZ(era, rotation2Scratch);
  761. // pseudoFixed to ICRF
  762. var pfToIcrf = Matrix3.multiply(matrixQ, earthRotation, rotation1Scratch);
  763. // Compute pole wander matrix
  764. var cosxp = Math.cos(eop.xPoleWander);
  765. var cosyp = Math.cos(eop.yPoleWander);
  766. var sinxp = Math.sin(eop.xPoleWander);
  767. var sinyp = Math.sin(eop.yPoleWander);
  768. var ttt = (dayTT - j2000ttDays) + secondTT / TimeConstants.SECONDS_PER_DAY;
  769. ttt /= 36525.0;
  770. // approximate sp value in rad
  771. var sp = -47.0e-6 * ttt * CesiumMath.RADIANS_PER_DEGREE / 3600.0;
  772. var cossp = Math.cos(sp);
  773. var sinsp = Math.sin(sp);
  774. var fToPfMtx = rotation2Scratch;
  775. fToPfMtx[0] = cosxp * cossp;
  776. fToPfMtx[1] = cosxp * sinsp;
  777. fToPfMtx[2] = sinxp;
  778. fToPfMtx[3] = -cosyp * sinsp + sinyp * sinxp * cossp;
  779. fToPfMtx[4] = cosyp * cossp + sinyp * sinxp * sinsp;
  780. fToPfMtx[5] = -sinyp * cosxp;
  781. fToPfMtx[6] = -sinyp * sinsp - cosyp * sinxp * cossp;
  782. fToPfMtx[7] = sinyp * cossp - cosyp * sinxp * sinsp;
  783. fToPfMtx[8] = cosyp * cosxp;
  784. return Matrix3.multiply(pfToIcrf, fToPfMtx, result);
  785. };
  786. var pointToWindowCoordinatesTemp = new Cartesian4();
  787. /**
  788. * Transform a point from model coordinates to window coordinates.
  789. *
  790. * @param {Matrix4} modelViewProjectionMatrix The 4x4 model-view-projection matrix.
  791. * @param {Matrix4} viewportTransformation The 4x4 viewport transformation.
  792. * @param {Cartesian3} point The point to transform.
  793. * @param {Cartesian2} [result] The object onto which to store the result.
  794. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if none was provided.
  795. */
  796. Transforms.pointToWindowCoordinates = function (modelViewProjectionMatrix, viewportTransformation, point, result) {
  797. result = Transforms.pointToGLWindowCoordinates(modelViewProjectionMatrix, viewportTransformation, point, result);
  798. result.y = 2.0 * viewportTransformation[5] - result.y;
  799. return result;
  800. };
  801. /**
  802. * @private
  803. */
  804. Transforms.pointToGLWindowCoordinates = function(modelViewProjectionMatrix, viewportTransformation, point, result) {
  805. //>>includeStart('debug', pragmas.debug);
  806. if (!defined(modelViewProjectionMatrix)) {
  807. throw new DeveloperError('modelViewProjectionMatrix is required.');
  808. }
  809. if (!defined(viewportTransformation)) {
  810. throw new DeveloperError('viewportTransformation is required.');
  811. }
  812. if (!defined(point)) {
  813. throw new DeveloperError('point is required.');
  814. }
  815. //>>includeEnd('debug');
  816. if (!defined(result)) {
  817. result = new Cartesian2();
  818. }
  819. var tmp = pointToWindowCoordinatesTemp;
  820. Matrix4.multiplyByVector(modelViewProjectionMatrix, Cartesian4.fromElements(point.x, point.y, point.z, 1, tmp), tmp);
  821. Cartesian4.multiplyByScalar(tmp, 1.0 / tmp.w, tmp);
  822. Matrix4.multiplyByVector(viewportTransformation, tmp, tmp);
  823. return Cartesian2.fromCartesian4(tmp, result);
  824. };
  825. var normalScratch = new Cartesian3();
  826. var rightScratch = new Cartesian3();
  827. var upScratch = new Cartesian3();
  828. /**
  829. * @private
  830. */
  831. Transforms.rotationMatrixFromPositionVelocity = function(position, velocity, ellipsoid, result) {
  832. //>>includeStart('debug', pragmas.debug);
  833. if (!defined(position)) {
  834. throw new DeveloperError('position is required.');
  835. }
  836. if (!defined(velocity)) {
  837. throw new DeveloperError('velocity is required.');
  838. }
  839. //>>includeEnd('debug');
  840. var normal = defaultValue(ellipsoid, Ellipsoid.WGS84).geodeticSurfaceNormal(position, normalScratch);
  841. var right = Cartesian3.cross(velocity, normal, rightScratch);
  842. if (Cartesian3.equalsEpsilon(right, Cartesian3.ZERO, CesiumMath.EPSILON6)) {
  843. right = Cartesian3.clone(Cartesian3.UNIT_X, right);
  844. }
  845. var up = Cartesian3.cross(right, velocity, upScratch);
  846. Cartesian3.cross(velocity, up, right);
  847. Cartesian3.negate(right, right);
  848. if (!defined(result)) {
  849. result = new Matrix3();
  850. }
  851. result[0] = velocity.x;
  852. result[1] = velocity.y;
  853. result[2] = velocity.z;
  854. result[3] = right.x;
  855. result[4] = right.y;
  856. result[5] = right.z;
  857. result[6] = up.x;
  858. result[7] = up.y;
  859. result[8] = up.z;
  860. return result;
  861. };
  862. var scratchCartographic = new Cartographic();
  863. var scratchCartesian3Projection = new Cartesian3();
  864. var scratchCartesian3 = new Cartesian3();
  865. var scratchCartesian4Origin = new Cartesian4();
  866. var scratchCartesian4NewOrigin = new Cartesian4();
  867. var scratchCartesian4NewXAxis = new Cartesian4();
  868. var scratchCartesian4NewYAxis = new Cartesian4();
  869. var scratchCartesian4NewZAxis = new Cartesian4();
  870. var scratchFromENU = new Matrix4();
  871. var scratchToENU = new Matrix4();
  872. /**
  873. * @private
  874. */
  875. Transforms.basisTo2D = function(projection, matrix, result) {
  876. //>>includeStart('debug', pragmas.debug);
  877. if (!defined(projection)) {
  878. throw new DeveloperError('projection is required.');
  879. }
  880. if (!defined(matrix)) {
  881. throw new DeveloperError('matrix is required.');
  882. }
  883. if (!defined(result)) {
  884. throw new DeveloperError('result is required.');
  885. }
  886. //>>includeEnd('debug');
  887. var ellipsoid = projection.ellipsoid;
  888. var origin = Matrix4.getColumn(matrix, 3, scratchCartesian4Origin);
  889. var cartographic = ellipsoid.cartesianToCartographic(origin, scratchCartographic);
  890. var fromENU = Transforms.eastNorthUpToFixedFrame(origin, ellipsoid, scratchFromENU);
  891. var toENU = Matrix4.inverseTransformation(fromENU, scratchToENU);
  892. var projectedPosition = projection.project(cartographic, scratchCartesian3Projection);
  893. var newOrigin = scratchCartesian4NewOrigin;
  894. newOrigin.x = projectedPosition.z;
  895. newOrigin.y = projectedPosition.x;
  896. newOrigin.z = projectedPosition.y;
  897. newOrigin.w = 1.0;
  898. var xAxis = Matrix4.getColumn(matrix, 0, scratchCartesian3);
  899. var xScale = Cartesian3.magnitude(xAxis);
  900. var newXAxis = Matrix4.multiplyByVector(toENU, xAxis, scratchCartesian4NewXAxis);
  901. Cartesian4.fromElements(newXAxis.z, newXAxis.x, newXAxis.y, 0.0, newXAxis);
  902. var yAxis = Matrix4.getColumn(matrix, 1, scratchCartesian3);
  903. var yScale = Cartesian3.magnitude(yAxis);
  904. var newYAxis = Matrix4.multiplyByVector(toENU, yAxis, scratchCartesian4NewYAxis);
  905. Cartesian4.fromElements(newYAxis.z, newYAxis.x, newYAxis.y, 0.0, newYAxis);
  906. var zAxis = Matrix4.getColumn(matrix, 2, scratchCartesian3);
  907. var zScale = Cartesian3.magnitude(zAxis);
  908. var newZAxis = scratchCartesian4NewZAxis;
  909. Cartesian3.cross(newXAxis, newYAxis, newZAxis);
  910. Cartesian3.normalize(newZAxis, newZAxis);
  911. Cartesian3.cross(newYAxis, newZAxis, newXAxis);
  912. Cartesian3.normalize(newXAxis, newXAxis);
  913. Cartesian3.cross(newZAxis, newXAxis, newYAxis);
  914. Cartesian3.normalize(newYAxis, newYAxis);
  915. Cartesian3.multiplyByScalar(newXAxis, xScale, newXAxis);
  916. Cartesian3.multiplyByScalar(newYAxis, yScale, newYAxis);
  917. Cartesian3.multiplyByScalar(newZAxis, zScale, newZAxis);
  918. Matrix4.setColumn(result, 0, newXAxis, result);
  919. Matrix4.setColumn(result, 1, newYAxis, result);
  920. Matrix4.setColumn(result, 2, newZAxis, result);
  921. Matrix4.setColumn(result, 3, newOrigin, result);
  922. return result;
  923. };
  924. return Transforms;
  925. });