SceneTransforms.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*global define*/
  2. define([
  3. '../Core/BoundingRectangle',
  4. '../Core/Cartesian2',
  5. '../Core/Cartesian3',
  6. '../Core/Cartesian4',
  7. '../Core/Cartographic',
  8. '../Core/defined',
  9. '../Core/DeveloperError',
  10. '../Core/Math',
  11. '../Core/Matrix4',
  12. './SceneMode'
  13. ], function(
  14. BoundingRectangle,
  15. Cartesian2,
  16. Cartesian3,
  17. Cartesian4,
  18. Cartographic,
  19. defined,
  20. DeveloperError,
  21. CesiumMath,
  22. Matrix4,
  23. SceneMode) {
  24. "use strict";
  25. /**
  26. * Functions that do scene-dependent transforms between rendering-related coordinate systems.
  27. *
  28. * @namespace
  29. * @alias SceneTransforms
  30. */
  31. var SceneTransforms = {};
  32. var actualPositionScratch = new Cartesian4(0, 0, 0, 1);
  33. var positionCC = new Cartesian4();
  34. var viewProjectionScratch = new Matrix4();
  35. /**
  36. * Transforms a position in WGS84 coordinates to window coordinates. This is commonly used to place an
  37. * HTML element at the same screen position as an object in the scene.
  38. *
  39. * @param {Scene} scene The scene.
  40. * @param {Cartesian3} position The position in WGS84 (world) coordinates.
  41. * @param {Cartesian2} [result] An optional object to return the input position transformed to window coordinates.
  42. * @returns {Cartesian2} The modified result parameter or a new Cartesian3 instance if one was not provided. This may be <code>undefined</code> if the input position is near the center of the ellipsoid.
  43. *
  44. * @example
  45. * // Output the window position of longitude/latitude (0, 0) every time the mouse moves.
  46. * var scene = widget.scene;
  47. * var ellipsoid = scene.globe.ellipsoid;
  48. * var position = Cesium.Cartesian3.fromDegrees(0.0, 0.0));
  49. * var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
  50. * handler.setInputAction(function(movement) {
  51. * console.log(Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, position));
  52. * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  53. */
  54. SceneTransforms.wgs84ToWindowCoordinates = function(scene, position, result) {
  55. //>>includeStart('debug', pragmas.debug);
  56. if (!defined(scene)) {
  57. throw new DeveloperError('scene is required.');
  58. }
  59. if (!defined(position)) {
  60. throw new DeveloperError('position is required.');
  61. }
  62. //>>includeEnd('debug');
  63. // Transform for 3D, 2D, or Columbus view
  64. var actualPosition = SceneTransforms.computeActualWgs84Position(scene.frameState, position, actualPositionScratch);
  65. if (!defined(actualPosition)) {
  66. return undefined;
  67. }
  68. // View-projection matrix to transform from world coordinates to clip coordinates
  69. var camera = scene.camera;
  70. var viewProjection = Matrix4.multiply(camera.frustum.projectionMatrix, camera.viewMatrix, viewProjectionScratch);
  71. Matrix4.multiplyByVector(viewProjection, Cartesian4.fromElements(actualPosition.x, actualPosition.y, actualPosition.z, 1, positionCC), positionCC);
  72. if ((positionCC.z < 0) && (scene.mode !== SceneMode.SCENE2D)) {
  73. return undefined;
  74. }
  75. result = SceneTransforms.clipToGLWindowCoordinates(scene, positionCC, result);
  76. result.y = scene.canvas.clientHeight - result.y;
  77. return result;
  78. };
  79. /**
  80. * Transforms a position in WGS84 coordinates to drawing buffer coordinates. This may produce different
  81. * results from SceneTransforms.wgs84ToWindowCoordinates when the browser zoom is not 100%, or on high-DPI displays.
  82. *
  83. * @param {Scene} scene The scene.
  84. * @param {Cartesian3} position The position in WGS84 (world) coordinates.
  85. * @param {Cartesian2} [result] An optional object to return the input position transformed to window coordinates.
  86. * @returns {Cartesian2} The modified result parameter or a new Cartesian3 instance if one was not provided. This may be <code>undefined</code> if the input position is near the center of the ellipsoid.
  87. *
  88. * @example
  89. * // Output the window position of longitude/latitude (0, 0) every time the mouse moves.
  90. * var scene = widget.scene;
  91. * var ellipsoid = scene.globe.ellipsoid;
  92. * var position = Cesium.Cartesian3.fromDegrees(0.0, 0.0));
  93. * var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
  94. * handler.setInputAction(function(movement) {
  95. * console.log(Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, position));
  96. * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  97. */
  98. SceneTransforms.wgs84ToDrawingBufferCoordinates = function(scene, position, result) {
  99. //>>includeStart('debug', pragmas.debug);
  100. if (!defined(scene)) {
  101. throw new DeveloperError('scene is required.');
  102. }
  103. if (!defined(position)) {
  104. throw new DeveloperError('position is required.');
  105. }
  106. //>>includeEnd('debug');
  107. // Transform for 3D, 2D, or Columbus view
  108. var actualPosition = SceneTransforms.computeActualWgs84Position(scene.frameState, position, actualPositionScratch);
  109. if (!defined(actualPosition)) {
  110. return undefined;
  111. }
  112. // View-projection matrix to transform from world coordinates to clip coordinates
  113. var camera = scene.camera;
  114. var viewProjection = Matrix4.multiply(camera.frustum.projectionMatrix, camera.viewMatrix, viewProjectionScratch);
  115. Matrix4.multiplyByVector(viewProjection, Cartesian4.fromElements(actualPosition.x, actualPosition.y, actualPosition.z, 1, positionCC), positionCC);
  116. if ((positionCC.z < 0) && (scene.mode !== SceneMode.SCENE2D)) {
  117. return undefined;
  118. }
  119. return SceneTransforms.clipToDrawingBufferCoordinates(scene, positionCC, result);
  120. };
  121. var projectedPosition = new Cartesian3();
  122. var positionInCartographic = new Cartographic();
  123. /**
  124. * @private
  125. */
  126. SceneTransforms.computeActualWgs84Position = function(frameState, position, result) {
  127. var mode = frameState.mode;
  128. if (mode === SceneMode.SCENE3D) {
  129. return Cartesian3.clone(position, result);
  130. }
  131. var projection = frameState.mapProjection;
  132. var cartographic = projection.ellipsoid.cartesianToCartographic(position, positionInCartographic);
  133. if (!defined(cartographic)) {
  134. return undefined;
  135. }
  136. projection.project(cartographic, projectedPosition);
  137. if (mode === SceneMode.COLUMBUS_VIEW) {
  138. return Cartesian3.fromElements(projectedPosition.z, projectedPosition.x, projectedPosition.y, result);
  139. }
  140. if (mode === SceneMode.SCENE2D) {
  141. return Cartesian3.fromElements(0.0, projectedPosition.x, projectedPosition.y, result);
  142. }
  143. // mode === SceneMode.MORPHING
  144. var morphTime = frameState.morphTime;
  145. return Cartesian3.fromElements(
  146. CesiumMath.lerp(projectedPosition.z, position.x, morphTime),
  147. CesiumMath.lerp(projectedPosition.x, position.y, morphTime),
  148. CesiumMath.lerp(projectedPosition.y, position.z, morphTime),
  149. result);
  150. };
  151. var positionNDC = new Cartesian3();
  152. var positionWC = new Cartesian3();
  153. var viewport = new BoundingRectangle();
  154. var viewportTransform = new Matrix4();
  155. /**
  156. * @private
  157. */
  158. SceneTransforms.clipToGLWindowCoordinates = function(scene, position, result) {
  159. var canvas = scene.canvas;
  160. // Perspective divide to transform from clip coordinates to normalized device coordinates
  161. Cartesian3.divideByScalar(position, position.w, positionNDC);
  162. // Assuming viewport takes up the entire canvas...
  163. viewport.width = canvas.clientWidth;
  164. viewport.height = canvas.clientHeight;
  165. Matrix4.computeViewportTransformation(viewport, 0.0, 1.0, viewportTransform);
  166. // Viewport transform to transform from clip coordinates to window coordinates
  167. Matrix4.multiplyByPoint(viewportTransform, positionNDC, positionWC);
  168. return Cartesian2.fromCartesian3(positionWC, result);
  169. };
  170. /**
  171. * @private
  172. */
  173. SceneTransforms.clipToDrawingBufferCoordinates = function(scene, position, result) {
  174. // Perspective divide to transform from clip coordinates to normalized device coordinates
  175. Cartesian3.divideByScalar(position, position.w, positionNDC);
  176. // Assuming viewport takes up the entire canvas...
  177. viewport.width = scene.drawingBufferWidth;
  178. viewport.height = scene.drawingBufferHeight;
  179. Matrix4.computeViewportTransformation(viewport, 0.0, 1.0, viewportTransform);
  180. // Viewport transform to transform from clip coordinates to drawing buffer coordinates
  181. Matrix4.multiplyByPoint(viewportTransform, positionNDC, positionWC);
  182. return Cartesian2.fromCartesian3(positionWC, result);
  183. };
  184. /**
  185. * @private
  186. */
  187. SceneTransforms.transformWindowToDrawingBuffer = function(scene, windowPosition, result) {
  188. var canvas = scene.canvas;
  189. var xScale = scene.drawingBufferWidth / canvas.clientWidth;
  190. var yScale = scene.drawingBufferHeight / canvas.clientHeight;
  191. return Cartesian2.fromElements(windowPosition.x * xScale, windowPosition.y * yScale, result);
  192. };
  193. return SceneTransforms;
  194. });