EntityView.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*global define*/
  2. define([
  3. '../Core/Cartesian3',
  4. '../Core/defaultValue',
  5. '../Core/defined',
  6. '../Core/defineProperties',
  7. '../Core/DeveloperError',
  8. '../Core/Ellipsoid',
  9. '../Core/JulianDate',
  10. '../Core/Math',
  11. '../Core/Matrix3',
  12. '../Core/Transforms',
  13. '../Scene/SceneMode'
  14. ], function(
  15. Cartesian3,
  16. defaultValue,
  17. defined,
  18. defineProperties,
  19. DeveloperError,
  20. Ellipsoid,
  21. JulianDate,
  22. CesiumMath,
  23. Matrix3,
  24. Transforms,
  25. SceneMode) {
  26. "use strict";
  27. var updateTransformMatrix3Scratch1 = new Matrix3();
  28. var updateTransformMatrix3Scratch2 = new Matrix3();
  29. var updateTransformMatrix3Scratch3 = new Matrix3();
  30. var updateTransformCartesian3Scratch1 = new Cartesian3();
  31. var updateTransformCartesian3Scratch2 = new Cartesian3();
  32. var updateTransformCartesian3Scratch3 = new Cartesian3();
  33. var updateTransformCartesian3Scratch4 = new Cartesian3();
  34. var updateTransformCartesian3Scratch5 = new Cartesian3();
  35. var updateTransformCartesian3Scratch6 = new Cartesian3();
  36. var deltaTime = new JulianDate();
  37. var northUpAxisFactor = 1.25; // times ellipsoid's maximum radius
  38. function updateTransform(that, camera, updateLookAt, positionProperty, time, ellipsoid) {
  39. var cartesian = positionProperty.getValue(time, that._lastCartesian);
  40. if (defined(cartesian)) {
  41. var hasBasis = false;
  42. var xBasis;
  43. var yBasis;
  44. var zBasis;
  45. // The time delta was determined based on how fast satellites move compared to vehicles near the surface.
  46. // Slower moving vehicles will most likely default to east-north-up, while faster ones will be VVLH.
  47. deltaTime = JulianDate.addSeconds(time, 0.001, deltaTime);
  48. var deltaCartesian = positionProperty.getValue(deltaTime, updateTransformCartesian3Scratch1);
  49. if (defined(deltaCartesian)) {
  50. var toInertial = Transforms.computeFixedToIcrfMatrix(time, updateTransformMatrix3Scratch1);
  51. var toInertialDelta = Transforms.computeFixedToIcrfMatrix(deltaTime, updateTransformMatrix3Scratch2);
  52. var toFixed;
  53. if (!defined(toInertial) || !defined(toInertialDelta)) {
  54. toFixed = Transforms.computeTemeToPseudoFixedMatrix(time, updateTransformMatrix3Scratch3);
  55. toInertial = Matrix3.transpose(toFixed, updateTransformMatrix3Scratch1);
  56. toInertialDelta = Transforms.computeTemeToPseudoFixedMatrix(deltaTime, updateTransformMatrix3Scratch2);
  57. Matrix3.transpose(toInertialDelta, toInertialDelta);
  58. } else {
  59. toFixed = Matrix3.transpose(toInertial, updateTransformMatrix3Scratch3);
  60. }
  61. var inertialCartesian = Matrix3.multiplyByVector(toInertial, cartesian, updateTransformCartesian3Scratch5);
  62. var inertialDeltaCartesian = Matrix3.multiplyByVector(toInertialDelta, deltaCartesian, updateTransformCartesian3Scratch6);
  63. Cartesian3.subtract(inertialCartesian, inertialDeltaCartesian, updateTransformCartesian3Scratch4);
  64. var inertialVelocity = Cartesian3.magnitude(updateTransformCartesian3Scratch4) * 1000.0; // meters/sec
  65. // http://en.wikipedia.org/wiki/Standard_gravitational_parameter
  66. // Consider adding this to Cesium.Ellipsoid?
  67. var mu = 3.986004418e14; // m^3 / sec^2
  68. var semiMajorAxis = -mu / (inertialVelocity * inertialVelocity - (2 * mu / Cartesian3.magnitude(inertialCartesian)));
  69. if (semiMajorAxis < 0 || semiMajorAxis > northUpAxisFactor * ellipsoid.maximumRadius) {
  70. // North-up viewing from deep space.
  71. // X along the nadir
  72. xBasis = updateTransformCartesian3Scratch2;
  73. Cartesian3.normalize(cartesian, xBasis);
  74. Cartesian3.negate(xBasis, xBasis);
  75. // Z is North
  76. zBasis = Cartesian3.clone(Cartesian3.UNIT_Z, updateTransformCartesian3Scratch3);
  77. // Y is along the cross of z and x (right handed basis / in the direction of motion)
  78. yBasis = Cartesian3.cross(zBasis, xBasis, updateTransformCartesian3Scratch1);
  79. if (Cartesian3.magnitude(yBasis) > CesiumMath.EPSILON7) {
  80. Cartesian3.normalize(xBasis, xBasis);
  81. Cartesian3.normalize(yBasis, yBasis);
  82. zBasis = Cartesian3.cross(xBasis, yBasis, updateTransformCartesian3Scratch3);
  83. Cartesian3.normalize(zBasis, zBasis);
  84. hasBasis = true;
  85. }
  86. } else if (!Cartesian3.equalsEpsilon(cartesian, deltaCartesian, CesiumMath.EPSILON7)) {
  87. // Approximation of VVLH (Vehicle Velocity Local Horizontal) with the Z-axis flipped.
  88. // Z along the position
  89. zBasis = updateTransformCartesian3Scratch2;
  90. Cartesian3.normalize(inertialCartesian, zBasis);
  91. Cartesian3.normalize(inertialDeltaCartesian, inertialDeltaCartesian);
  92. // Y is along the angular momentum vector (e.g. "orbit normal")
  93. yBasis = Cartesian3.cross(zBasis, inertialDeltaCartesian, updateTransformCartesian3Scratch3);
  94. if (!Cartesian3.equalsEpsilon(yBasis, Cartesian3.ZERO, CesiumMath.EPSILON7)) {
  95. // X is along the cross of y and z (right handed basis / in the direction of motion)
  96. xBasis = Cartesian3.cross(yBasis, zBasis, updateTransformCartesian3Scratch1);
  97. Matrix3.multiplyByVector(toFixed, xBasis, xBasis);
  98. Matrix3.multiplyByVector(toFixed, yBasis, yBasis);
  99. Matrix3.multiplyByVector(toFixed, zBasis, zBasis);
  100. Cartesian3.normalize(xBasis, xBasis);
  101. Cartesian3.normalize(yBasis, yBasis);
  102. Cartesian3.normalize(zBasis, zBasis);
  103. hasBasis = true;
  104. }
  105. }
  106. }
  107. if (hasBasis) {
  108. var transform = camera.transform;
  109. transform[0] = xBasis.x;
  110. transform[1] = xBasis.y;
  111. transform[2] = xBasis.z;
  112. transform[3] = 0.0;
  113. transform[4] = yBasis.x;
  114. transform[5] = yBasis.y;
  115. transform[6] = yBasis.z;
  116. transform[7] = 0.0;
  117. transform[8] = zBasis.x;
  118. transform[9] = zBasis.y;
  119. transform[10] = zBasis.z;
  120. transform[11] = 0.0;
  121. transform[12] = cartesian.x;
  122. transform[13] = cartesian.y;
  123. transform[14] = cartesian.z;
  124. transform[15] = 0.0;
  125. } else {
  126. // Stationary or slow-moving, low-altitude objects use East-North-Up.
  127. Transforms.eastNorthUpToFixedFrame(cartesian, ellipsoid, camera.transform);
  128. }
  129. }
  130. if (updateLookAt) {
  131. if (that.scene.mode === SceneMode.SCENE2D) {
  132. camera.lookAt(that._offset2D, Cartesian3.ZERO, that._up2D);
  133. } else {
  134. camera.lookAt(that._offset3D, Cartesian3.ZERO, that._up3D);
  135. }
  136. }
  137. }
  138. var offset3DCrossScratch = new Cartesian3();
  139. /**
  140. * A utility object for tracking an entity with the camera.
  141. * @alias EntityView
  142. * @constructor
  143. *
  144. * @param {Entity} entity The entity to track with the camera.
  145. * @param {Scene} scene The scene to use.
  146. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use for orienting the camera.
  147. */
  148. var EntityView = function(entity, scene, ellipsoid) {
  149. /**
  150. * The entity to track with the camera.
  151. * @type {Entity}
  152. */
  153. this.entity = entity;
  154. /**
  155. * The scene in which to track the object.
  156. * @type {Scene}
  157. */
  158. this.scene = scene;
  159. /**
  160. * The ellipsoid to use for orienting the camera.
  161. * @type {Ellipsoid}
  162. */
  163. this.ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  164. //Shadow copies of the objects so we can detect changes.
  165. this._lastEntity = undefined;
  166. this._mode = undefined;
  167. //Re-usable objects to be used for retrieving position.
  168. this._lastCartesian = new Cartesian3();
  169. this._offset3D = new Cartesian3();
  170. this._up3D = new Cartesian3();
  171. this._offset2D = new Cartesian3();
  172. this._up2D = new Cartesian3();
  173. };
  174. // STATIC properties defined here, not per-instance.
  175. defineProperties(EntityView, {
  176. /**
  177. * Gets or sets a camera offset that will be used to
  178. * initialize subsequent EntityViews.
  179. * @memberof EntityView
  180. * @type {Cartesian3}
  181. */
  182. defaultOffset3D : {
  183. get : function() {
  184. return this._defaultOffset3D;
  185. },
  186. set : function(vector) {
  187. this._defaultOffset3D = Cartesian3.clone(vector, new Cartesian3());
  188. this._defaultUp3D = Cartesian3.cross(this._defaultOffset3D, Cartesian3.cross(Cartesian3.UNIT_Z,
  189. this._defaultOffset3D, offset3DCrossScratch), new Cartesian3());
  190. Cartesian3.normalize(this._defaultUp3D, this._defaultUp3D);
  191. this._defaultOffset2D = new Cartesian3(0.0, 0.0, Cartesian3.magnitude(this._defaultOffset3D));
  192. this._defaultUp2D = Cartesian3.clone(Cartesian3.UNIT_Y);
  193. }
  194. }
  195. });
  196. // Initialize the static property.
  197. EntityView.defaultOffset3D = new Cartesian3(-14000, 3500, 3500);
  198. /**
  199. * Should be called each animation frame to update the camera
  200. * to the latest settings.
  201. * @param {JulianDate} time The current animation time.
  202. *
  203. */
  204. EntityView.prototype.update = function(time) {
  205. var scene = this.scene;
  206. var entity = this.entity;
  207. var ellipsoid = this.ellipsoid;
  208. //>>includeStart('debug', pragmas.debug);
  209. if (!defined(time)) {
  210. throw new DeveloperError('time is required.');
  211. }
  212. if (!defined(scene)) {
  213. throw new DeveloperError('EntityView.scene is required.');
  214. }
  215. if (!defined(entity)) {
  216. throw new DeveloperError('EntityView.entity is required.');
  217. }
  218. if (!defined(ellipsoid)) {
  219. throw new DeveloperError('EntityView.ellipsoid is required.');
  220. }
  221. if (!defined(entity.position)) {
  222. throw new DeveloperError('entity.position is required.');
  223. }
  224. //>>includeEnd('debug');
  225. var positionProperty = entity.position;
  226. var objectChanged = entity !== this._lastEntity;
  227. var sceneModeChanged = scene.mode !== this._mode && scene.mode !== SceneMode.MORPHING;
  228. var offset3D = this._offset3D;
  229. var up3D = this._up3D;
  230. var offset2D = this._offset2D;
  231. var up2D = this._up2D;
  232. var camera = scene.camera;
  233. if (objectChanged) {
  234. var viewFromProperty = entity.viewFrom;
  235. if (!defined(viewFromProperty) || !defined(viewFromProperty.getValue(time, offset3D))) {
  236. Cartesian3.clone(EntityView._defaultOffset2D, offset2D);
  237. Cartesian3.clone(EntityView._defaultUp2D, up2D);
  238. Cartesian3.clone(EntityView._defaultOffset3D, offset3D);
  239. Cartesian3.clone(EntityView._defaultUp3D, up3D);
  240. } else {
  241. Cartesian3.cross(Cartesian3.UNIT_Z, offset3D, up3D);
  242. Cartesian3.cross(offset3D, up3D, up3D);
  243. Cartesian3.normalize(up3D, up3D);
  244. var mag = Cartesian3.magnitude(offset3D);
  245. Cartesian3.fromElements(0.0, 0.0, mag, offset2D);
  246. Cartesian3.clone(this._defaultUp2D, up2D);
  247. }
  248. } else if (!sceneModeChanged && scene.mode !== SceneMode.MORPHING) {
  249. if (this._mode === SceneMode.SCENE2D) {
  250. var distance = Math.max(camera.frustum.right - camera.frustum.left, camera.frustum.top - camera.frustum.bottom);
  251. Cartesian3.fromElements(0.0, 0.0, distance, offset2D);
  252. Cartesian3.clone(camera.up, up2D);
  253. } else if (this._mode === SceneMode.SCENE3D || this._mode === SceneMode.COLUMBUS_VIEW) {
  254. Cartesian3.clone(camera.position, offset3D);
  255. Cartesian3.clone(camera.up, up3D);
  256. }
  257. }
  258. var updateLookAt = objectChanged || sceneModeChanged;
  259. this._lastEntity = entity;
  260. this._mode = scene.mode !== SceneMode.MORPHING ? scene.mode : this._mode;
  261. if (scene.mode !== SceneMode.MORPHING) {
  262. updateTransform(this, camera, updateLookAt, positionProperty, time, ellipsoid);
  263. }
  264. };
  265. return EntityView;
  266. });