SceneTransitioner.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889
  1. import Cartesian3 from '../Core/Cartesian3.js';
  2. import Cartographic from '../Core/Cartographic.js';
  3. import Check from '../Core/Check.js';
  4. import defined from '../Core/defined.js';
  5. import destroyObject from '../Core/destroyObject.js';
  6. import EasingFunction from '../Core/EasingFunction.js';
  7. import CesiumMath from '../Core/Math.js';
  8. import Matrix4 from '../Core/Matrix4.js';
  9. import OrthographicFrustum from '../Core/OrthographicFrustum.js';
  10. import OrthographicOffCenterFrustum from '../Core/OrthographicOffCenterFrustum.js';
  11. import PerspectiveFrustum from '../Core/PerspectiveFrustum.js';
  12. import Ray from '../Core/Ray.js';
  13. import ScreenSpaceEventHandler from '../Core/ScreenSpaceEventHandler.js';
  14. import ScreenSpaceEventType from '../Core/ScreenSpaceEventType.js';
  15. import Transforms from '../Core/Transforms.js';
  16. import Camera from './Camera.js';
  17. import SceneMode from './SceneMode.js';
  18. /**
  19. * @private
  20. */
  21. function SceneTransitioner(scene) {
  22. //>>includeStart('debug', pragmas.debug);
  23. Check.typeOf.object('scene', scene);
  24. //>>includeEnd('debug');
  25. this._scene = scene;
  26. this._currentTweens = [];
  27. this._morphHandler = undefined;
  28. this._morphCancelled = false;
  29. this._completeMorph = undefined;
  30. this._morphToOrthographic = false;
  31. }
  32. SceneTransitioner.prototype.completeMorph = function() {
  33. if (defined(this._completeMorph)) {
  34. this._completeMorph();
  35. }
  36. };
  37. SceneTransitioner.prototype.morphTo2D = function(duration, ellipsoid) {
  38. if (defined(this._completeMorph)) {
  39. this._completeMorph();
  40. }
  41. var scene = this._scene;
  42. this._previousMode = scene.mode;
  43. this._morphToOrthographic = scene.camera.frustum instanceof OrthographicFrustum;
  44. if (this._previousMode === SceneMode.SCENE2D || this._previousMode === SceneMode.MORPHING) {
  45. return;
  46. }
  47. this._scene.morphStart.raiseEvent(this, this._previousMode, SceneMode.SCENE2D, true);
  48. scene._mode = SceneMode.MORPHING;
  49. scene.camera._setTransform(Matrix4.IDENTITY);
  50. if (this._previousMode === SceneMode.COLUMBUS_VIEW) {
  51. morphFromColumbusViewTo2D(this, duration);
  52. } else {
  53. morphFrom3DTo2D(this, duration, ellipsoid);
  54. }
  55. if (duration === 0.0 && defined(this._completeMorph)) {
  56. this._completeMorph();
  57. }
  58. };
  59. var scratchToCVPosition = new Cartesian3();
  60. var scratchToCVDirection = new Cartesian3();
  61. var scratchToCVUp = new Cartesian3();
  62. var scratchToCVPosition2D = new Cartesian3();
  63. var scratchToCVDirection2D = new Cartesian3();
  64. var scratchToCVUp2D = new Cartesian3();
  65. var scratchToCVSurfacePosition = new Cartesian3();
  66. var scratchToCVCartographic = new Cartographic();
  67. var scratchToCVToENU = new Matrix4();
  68. var scratchToCVFrustumPerspective = new PerspectiveFrustum();
  69. var scratchToCVFrustumOrthographic = new OrthographicFrustum();
  70. var scratchToCVCamera = {
  71. position : undefined,
  72. direction : undefined,
  73. up : undefined,
  74. position2D : undefined,
  75. direction2D : undefined,
  76. up2D : undefined,
  77. frustum : undefined
  78. };
  79. SceneTransitioner.prototype.morphToColumbusView = function(duration, ellipsoid) {
  80. if (defined(this._completeMorph)) {
  81. this._completeMorph();
  82. }
  83. var scene = this._scene;
  84. this._previousMode = scene.mode;
  85. if (this._previousMode === SceneMode.COLUMBUS_VIEW || this._previousMode === SceneMode.MORPHING) {
  86. return;
  87. }
  88. this._scene.morphStart.raiseEvent(this, this._previousMode, SceneMode.COLUMBUS_VIEW, true);
  89. scene.camera._setTransform(Matrix4.IDENTITY);
  90. var position = scratchToCVPosition;
  91. var direction = scratchToCVDirection;
  92. var up = scratchToCVUp;
  93. if (duration > 0.0) {
  94. position.x = 0.0;
  95. position.y = -1.0;
  96. position.z = 1.0;
  97. position = Cartesian3.multiplyByScalar(Cartesian3.normalize(position, position), 5.0 * ellipsoid.maximumRadius, position);
  98. Cartesian3.negate(Cartesian3.normalize(position, direction), direction);
  99. Cartesian3.cross(Cartesian3.UNIT_X, direction, up);
  100. } else {
  101. var camera = scene.camera;
  102. if (this._previousMode === SceneMode.SCENE2D) {
  103. Cartesian3.clone(camera.position, position);
  104. position.z = camera.frustum.right - camera.frustum.left;
  105. Cartesian3.negate(Cartesian3.UNIT_Z, direction);
  106. Cartesian3.clone(Cartesian3.UNIT_Y, up);
  107. } else {
  108. Cartesian3.clone(camera.positionWC, position);
  109. Cartesian3.clone(camera.directionWC, direction);
  110. Cartesian3.clone(camera.upWC, up);
  111. var surfacePoint = ellipsoid.scaleToGeodeticSurface(position, scratchToCVSurfacePosition);
  112. var toENU = Transforms.eastNorthUpToFixedFrame(surfacePoint, ellipsoid, scratchToCVToENU);
  113. Matrix4.inverseTransformation(toENU, toENU);
  114. scene.mapProjection.project(ellipsoid.cartesianToCartographic(position, scratchToCVCartographic), position);
  115. Matrix4.multiplyByPointAsVector(toENU, direction, direction);
  116. Matrix4.multiplyByPointAsVector(toENU, up, up);
  117. }
  118. }
  119. var frustum;
  120. if (this._morphToOrthographic) {
  121. frustum = scratchToCVFrustumOrthographic;
  122. frustum.width = scene.camera.frustum.right - scene.camera.frustum.left;
  123. frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight;
  124. } else {
  125. frustum = scratchToCVFrustumPerspective;
  126. frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight;
  127. frustum.fov = CesiumMath.toRadians(60.0);
  128. }
  129. var cameraCV = scratchToCVCamera;
  130. cameraCV.position = position;
  131. cameraCV.direction = direction;
  132. cameraCV.up = up;
  133. cameraCV.frustum = frustum;
  134. var complete = completeColumbusViewCallback(cameraCV);
  135. createMorphHandler(this, complete);
  136. if (this._previousMode === SceneMode.SCENE2D) {
  137. morphFrom2DToColumbusView(this, duration, cameraCV, complete);
  138. } else {
  139. cameraCV.position2D = Matrix4.multiplyByPoint(Camera.TRANSFORM_2D, position, scratchToCVPosition2D);
  140. cameraCV.direction2D = Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, direction, scratchToCVDirection2D);
  141. cameraCV.up2D = Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, up, scratchToCVUp2D);
  142. scene._mode = SceneMode.MORPHING;
  143. morphFrom3DToColumbusView(this, duration, cameraCV, complete);
  144. }
  145. if (duration === 0.0 && defined(this._completeMorph)) {
  146. this._completeMorph();
  147. }
  148. };
  149. var scratchCVTo3DCamera = {
  150. position : new Cartesian3(),
  151. direction : new Cartesian3(),
  152. up : new Cartesian3(),
  153. frustum : undefined
  154. };
  155. var scratch2DTo3DFrustumPersp = new PerspectiveFrustum();
  156. SceneTransitioner.prototype.morphTo3D = function(duration, ellipsoid) {
  157. if (defined(this._completeMorph)) {
  158. this._completeMorph();
  159. }
  160. var scene = this._scene;
  161. this._previousMode = scene.mode;
  162. if (this._previousMode === SceneMode.SCENE3D || this._previousMode === SceneMode.MORPHING) {
  163. return;
  164. }
  165. this._scene.morphStart.raiseEvent(this, this._previousMode, SceneMode.SCENE3D, true);
  166. scene._mode = SceneMode.MORPHING;
  167. scene.camera._setTransform(Matrix4.IDENTITY);
  168. if (this._previousMode === SceneMode.SCENE2D) {
  169. morphFrom2DTo3D(this, duration, ellipsoid);
  170. } else {
  171. var camera3D;
  172. if (duration > 0.0) {
  173. camera3D = scratchCVTo3DCamera;
  174. Cartesian3.fromDegrees(0.0, 0.0, 5.0 * ellipsoid.maximumRadius, ellipsoid, camera3D.position);
  175. Cartesian3.negate(camera3D.position, camera3D.direction);
  176. Cartesian3.normalize(camera3D.direction, camera3D.direction);
  177. Cartesian3.clone(Cartesian3.UNIT_Z, camera3D.up);
  178. } else {
  179. camera3D = getColumbusViewTo3DCamera(this, ellipsoid);
  180. }
  181. var frustum;
  182. var camera = scene.camera;
  183. if (camera.frustum instanceof OrthographicFrustum) {
  184. frustum = camera.frustum.clone();
  185. } else {
  186. frustum = scratch2DTo3DFrustumPersp;
  187. frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight;
  188. frustum.fov = CesiumMath.toRadians(60.0);
  189. }
  190. camera3D.frustum = frustum;
  191. var complete = complete3DCallback(camera3D);
  192. createMorphHandler(this, complete);
  193. morphFromColumbusViewTo3D(this, duration, camera3D, complete);
  194. }
  195. if (duration === 0.0 && defined(this._completeMorph)) {
  196. this._completeMorph();
  197. }
  198. };
  199. /**
  200. * Returns true if this object was destroyed; otherwise, false.
  201. * <br /><br />
  202. * If this object was destroyed, it should not be used; calling any function other than
  203. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  204. *
  205. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  206. */
  207. SceneTransitioner.prototype.isDestroyed = function() {
  208. return false;
  209. };
  210. /**
  211. * Once an object is destroyed, it should not be used; calling any function other than
  212. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  213. * assign the return value (<code>undefined</code>) to the object as done in the example.
  214. *
  215. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  216. *
  217. * @example
  218. * transitioner = transitioner && transitioner.destroy();
  219. */
  220. SceneTransitioner.prototype.destroy = function() {
  221. destroyMorphHandler(this);
  222. return destroyObject(this);
  223. };
  224. function createMorphHandler(transitioner, completeMorphFunction) {
  225. if (transitioner._scene.completeMorphOnUserInput) {
  226. transitioner._morphHandler = new ScreenSpaceEventHandler(transitioner._scene.canvas);
  227. var completeMorph = function() {
  228. transitioner._morphCancelled = true;
  229. transitioner._scene.camera.cancelFlight();
  230. completeMorphFunction(transitioner);
  231. };
  232. transitioner._completeMorph = completeMorph;
  233. transitioner._morphHandler.setInputAction(completeMorph, ScreenSpaceEventType.LEFT_DOWN);
  234. transitioner._morphHandler.setInputAction(completeMorph, ScreenSpaceEventType.MIDDLE_DOWN);
  235. transitioner._morphHandler.setInputAction(completeMorph, ScreenSpaceEventType.RIGHT_DOWN);
  236. transitioner._morphHandler.setInputAction(completeMorph, ScreenSpaceEventType.WHEEL);
  237. }
  238. }
  239. function destroyMorphHandler(transitioner) {
  240. var tweens = transitioner._currentTweens;
  241. for ( var i = 0; i < tweens.length; ++i) {
  242. tweens[i].cancelTween();
  243. }
  244. transitioner._currentTweens.length = 0;
  245. transitioner._morphHandler = transitioner._morphHandler && transitioner._morphHandler.destroy();
  246. }
  247. var scratchCVTo3DCartographic = new Cartographic();
  248. var scratchCVTo3DSurfacePoint = new Cartesian3();
  249. var scratchCVTo3DFromENU = new Matrix4();
  250. function getColumbusViewTo3DCamera(transitioner, ellipsoid) {
  251. var scene = transitioner._scene;
  252. var camera = scene.camera;
  253. var camera3D = scratchCVTo3DCamera;
  254. var position = camera3D.position;
  255. var direction = camera3D.direction;
  256. var up = camera3D.up;
  257. var positionCarto = scene.mapProjection.unproject(camera.position, scratchCVTo3DCartographic);
  258. ellipsoid.cartographicToCartesian(positionCarto, position);
  259. var surfacePoint = ellipsoid.scaleToGeodeticSurface(position, scratchCVTo3DSurfacePoint);
  260. var fromENU = Transforms.eastNorthUpToFixedFrame(surfacePoint, ellipsoid, scratchCVTo3DFromENU);
  261. Matrix4.multiplyByPointAsVector(fromENU, camera.direction, direction);
  262. Matrix4.multiplyByPointAsVector(fromENU, camera.up, up);
  263. return camera3D;
  264. }
  265. var scratchCVTo3DStartPos = new Cartesian3();
  266. var scratchCVTo3DStartDir = new Cartesian3();
  267. var scratchCVTo3DStartUp = new Cartesian3();
  268. var scratchCVTo3DEndPos = new Cartesian3();
  269. var scratchCVTo3DEndDir = new Cartesian3();
  270. var scratchCVTo3DEndUp = new Cartesian3();
  271. function morphFromColumbusViewTo3D(transitioner, duration, endCamera, complete) {
  272. duration *= 0.5;
  273. var scene = transitioner._scene;
  274. var camera = scene.camera;
  275. var startPos = Cartesian3.clone(camera.position, scratchCVTo3DStartPos);
  276. var startDir = Cartesian3.clone(camera.direction, scratchCVTo3DStartDir);
  277. var startUp = Cartesian3.clone(camera.up, scratchCVTo3DStartUp);
  278. var endPos = Matrix4.multiplyByPoint(Camera.TRANSFORM_2D_INVERSE, endCamera.position, scratchCVTo3DEndPos);
  279. var endDir = Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D_INVERSE, endCamera.direction, scratchCVTo3DEndDir);
  280. var endUp = Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D_INVERSE, endCamera.up, scratchCVTo3DEndUp);
  281. function update(value) {
  282. columbusViewMorph(startPos, endPos, value.time, camera.position);
  283. columbusViewMorph(startDir, endDir, value.time, camera.direction);
  284. columbusViewMorph(startUp, endUp, value.time, camera.up);
  285. Cartesian3.cross(camera.direction, camera.up, camera.right);
  286. Cartesian3.normalize(camera.right, camera.right);
  287. }
  288. var tween = scene.tweens.add({
  289. duration : duration,
  290. easingFunction : EasingFunction.QUARTIC_OUT,
  291. startObject : {
  292. time : 0.0
  293. },
  294. stopObject : {
  295. time : 1.0
  296. },
  297. update : update,
  298. complete : function() {
  299. addMorphTimeAnimations(transitioner, scene, 0.0, 1.0, duration, complete);
  300. }
  301. });
  302. transitioner._currentTweens.push(tween);
  303. }
  304. var scratch2DTo3DFrustumOrtho = new OrthographicFrustum();
  305. var scratch3DToCVStartPos = new Cartesian3();
  306. var scratch3DToCVStartDir = new Cartesian3();
  307. var scratch3DToCVStartUp = new Cartesian3();
  308. var scratch3DToCVEndPos = new Cartesian3();
  309. var scratch3DToCVEndDir = new Cartesian3();
  310. var scratch3DToCVEndUp = new Cartesian3();
  311. function morphFrom2DTo3D(transitioner, duration, ellipsoid) {
  312. duration /= 3.0;
  313. var scene = transitioner._scene;
  314. var camera = scene.camera;
  315. var camera3D;
  316. if (duration > 0.0) {
  317. camera3D = scratchCVTo3DCamera;
  318. Cartesian3.fromDegrees(0.0, 0.0, 5.0 * ellipsoid.maximumRadius, ellipsoid, camera3D.position);
  319. Cartesian3.negate(camera3D.position, camera3D.direction);
  320. Cartesian3.normalize(camera3D.direction, camera3D.direction);
  321. Cartesian3.clone(Cartesian3.UNIT_Z, camera3D.up);
  322. } else {
  323. camera.position.z = camera.frustum.right - camera.frustum.left;
  324. camera3D = getColumbusViewTo3DCamera(transitioner, ellipsoid);
  325. }
  326. var frustum;
  327. if (transitioner._morphToOrthographic) {
  328. frustum = scratch2DTo3DFrustumOrtho;
  329. frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight;
  330. frustum.width = camera.frustum.right - camera.frustum.left;
  331. } else {
  332. frustum = scratch2DTo3DFrustumPersp;
  333. frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight;
  334. frustum.fov = CesiumMath.toRadians(60.0);
  335. }
  336. camera3D.frustum = frustum;
  337. var complete = complete3DCallback(camera3D);
  338. createMorphHandler(transitioner, complete);
  339. var morph;
  340. if (transitioner._morphToOrthographic) {
  341. morph = function() {
  342. morphFromColumbusViewTo3D(transitioner, duration, camera3D, complete);
  343. };
  344. } else {
  345. morph = function() {
  346. morphOrthographicToPerspective(transitioner, duration, camera3D, function() {
  347. morphFromColumbusViewTo3D(transitioner, duration, camera3D, complete);
  348. });
  349. };
  350. }
  351. if (duration > 0.0) {
  352. scene._mode = SceneMode.SCENE2D;
  353. camera.flyTo({
  354. duration : duration,
  355. destination : Cartesian3.fromDegrees(0.0, 0.0, 5.0 * ellipsoid.maximumRadius, ellipsoid, scratch3DToCVEndPos),
  356. complete : function() {
  357. scene._mode = SceneMode.MORPHING;
  358. morph();
  359. }
  360. });
  361. } else {
  362. morph();
  363. }
  364. }
  365. function columbusViewMorph(startPosition, endPosition, time, result) {
  366. // Just linear for now.
  367. return Cartesian3.lerp(startPosition, endPosition, time, result);
  368. }
  369. function morphPerspectiveToOrthographic(transitioner, duration, endCamera, updateHeight, complete) {
  370. var scene = transitioner._scene;
  371. var camera = scene.camera;
  372. if (camera.frustum instanceof OrthographicFrustum) {
  373. return;
  374. }
  375. var startFOV = camera.frustum.fov;
  376. var endFOV = CesiumMath.RADIANS_PER_DEGREE * 0.5;
  377. var d = endCamera.position.z * Math.tan(startFOV * 0.5);
  378. camera.frustum.far = d / Math.tan(endFOV * 0.5) + 10000000.0;
  379. function update(value) {
  380. camera.frustum.fov = CesiumMath.lerp(startFOV, endFOV, value.time);
  381. var height = d / Math.tan(camera.frustum.fov * 0.5);
  382. updateHeight(camera, height);
  383. }
  384. var tween = scene.tweens.add({
  385. duration : duration,
  386. easingFunction : EasingFunction.QUARTIC_OUT,
  387. startObject : {
  388. time : 0.0
  389. },
  390. stopObject : {
  391. time : 1.0
  392. },
  393. update : update,
  394. complete : function() {
  395. camera.frustum = endCamera.frustum.clone();
  396. complete(transitioner);
  397. }
  398. });
  399. transitioner._currentTweens.push(tween);
  400. }
  401. var scratchCVTo2DStartPos = new Cartesian3();
  402. var scratchCVTo2DStartDir = new Cartesian3();
  403. var scratchCVTo2DStartUp = new Cartesian3();
  404. var scratchCVTo2DEndPos = new Cartesian3();
  405. var scratchCVTo2DEndDir = new Cartesian3();
  406. var scratchCVTo2DEndUp = new Cartesian3();
  407. var scratchCVTo2DFrustum = new OrthographicOffCenterFrustum();
  408. var scratchCVTo2DRay = new Ray();
  409. var scratchCVTo2DPickPos = new Cartesian3();
  410. var scratchCVTo2DCamera = {
  411. position : undefined,
  412. direction : undefined,
  413. up : undefined,
  414. frustum : undefined
  415. };
  416. function morphFromColumbusViewTo2D(transitioner, duration) {
  417. duration *= 0.5;
  418. var scene = transitioner._scene;
  419. var camera = scene.camera;
  420. var startPos = Cartesian3.clone(camera.position, scratchCVTo2DStartPos);
  421. var startDir = Cartesian3.clone(camera.direction, scratchCVTo2DStartDir);
  422. var startUp = Cartesian3.clone(camera.up, scratchCVTo2DStartUp);
  423. var endDir = Cartesian3.negate(Cartesian3.UNIT_Z, scratchCVTo2DEndDir);
  424. var endUp = Cartesian3.clone(Cartesian3.UNIT_Y, scratchCVTo2DEndUp);
  425. var endPos = scratchCVTo2DEndPos;
  426. if (duration > 0.0) {
  427. Cartesian3.clone(Cartesian3.ZERO, scratchCVTo2DEndPos);
  428. endPos.z = 5.0 * scene.mapProjection.ellipsoid.maximumRadius;
  429. } else {
  430. Cartesian3.clone(startPos, scratchCVTo2DEndPos);
  431. var ray = scratchCVTo2DRay;
  432. Matrix4.multiplyByPoint(Camera.TRANSFORM_2D, startPos, ray.origin);
  433. Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, startDir, ray.direction);
  434. var globe = scene.globe;
  435. if (defined(globe)) {
  436. var pickPos = globe.pickWorldCoordinates(ray, scene, scratchCVTo2DPickPos);
  437. if (defined(pickPos)) {
  438. Matrix4.multiplyByPoint(Camera.TRANSFORM_2D_INVERSE, pickPos, endPos);
  439. endPos.z += Cartesian3.distance(startPos, endPos);
  440. }
  441. }
  442. }
  443. var frustum = scratchCVTo2DFrustum;
  444. frustum.right = endPos.z * 0.5;
  445. frustum.left = -frustum.right;
  446. frustum.top = frustum.right * (scene.drawingBufferHeight / scene.drawingBufferWidth);
  447. frustum.bottom = -frustum.top;
  448. var camera2D = scratchCVTo2DCamera;
  449. camera2D.position = endPos;
  450. camera2D.direction = endDir;
  451. camera2D.up = endUp;
  452. camera2D.frustum = frustum;
  453. var complete = complete2DCallback(camera2D);
  454. createMorphHandler(transitioner, complete);
  455. function updateCV(value) {
  456. columbusViewMorph(startPos, endPos, value.time, camera.position);
  457. columbusViewMorph(startDir, endDir, value.time, camera.direction);
  458. columbusViewMorph(startUp, endUp, value.time, camera.up);
  459. Cartesian3.cross(camera.direction, camera.up, camera.right);
  460. Cartesian3.normalize(camera.right, camera.right);
  461. camera._adjustOrthographicFrustum(true);
  462. }
  463. function updateHeight(camera, height) {
  464. camera.position.z = height;
  465. }
  466. var tween = scene.tweens.add({
  467. duration : duration,
  468. easingFunction : EasingFunction.QUARTIC_OUT,
  469. startObject : {
  470. time : 0.0
  471. },
  472. stopObject : {
  473. time : 1.0
  474. },
  475. update : updateCV,
  476. complete : function() {
  477. morphPerspectiveToOrthographic(transitioner, duration, camera2D, updateHeight, complete);
  478. }
  479. });
  480. transitioner._currentTweens.push(tween);
  481. }
  482. var scratch3DTo2DCartographic = new Cartographic();
  483. var scratch3DTo2DCamera = {
  484. position : new Cartesian3(),
  485. direction : new Cartesian3(),
  486. up : new Cartesian3(),
  487. position2D : new Cartesian3(),
  488. direction2D : new Cartesian3(),
  489. up2D : new Cartesian3(),
  490. frustum : new OrthographicOffCenterFrustum()
  491. };
  492. var scratch3DTo2DEndCamera = {
  493. position : new Cartesian3(),
  494. direction : new Cartesian3(),
  495. up : new Cartesian3(),
  496. frustum : undefined
  497. };
  498. var scratch3DTo2DPickPosition = new Cartesian3();
  499. var scratch3DTo2DRay = new Ray();
  500. var scratch3DTo2DToENU = new Matrix4();
  501. var scratch3DTo2DSurfacePoint = new Cartesian3();
  502. function morphFrom3DTo2D(transitioner, duration, ellipsoid) {
  503. duration *= 0.5;
  504. var scene = transitioner._scene;
  505. var camera = scene.camera;
  506. var camera2D = scratch3DTo2DCamera;
  507. if (duration > 0.0) {
  508. Cartesian3.clone(Cartesian3.ZERO, camera2D.position);
  509. camera2D.position.z = 5.0 * ellipsoid.maximumRadius;
  510. Cartesian3.negate(Cartesian3.UNIT_Z, camera2D.direction);
  511. Cartesian3.clone(Cartesian3.UNIT_Y, camera2D.up);
  512. } else {
  513. ellipsoid.cartesianToCartographic(camera.positionWC, scratch3DTo2DCartographic);
  514. scene.mapProjection.project(scratch3DTo2DCartographic, camera2D.position);
  515. Cartesian3.negate(Cartesian3.UNIT_Z, camera2D.direction);
  516. Cartesian3.clone(Cartesian3.UNIT_Y, camera2D.up);
  517. var ray = scratch3DTo2DRay;
  518. Cartesian3.clone(camera2D.position2D, ray.origin);
  519. var rayDirection = Cartesian3.clone(camera.directionWC, ray.direction);
  520. var surfacePoint = ellipsoid.scaleToGeodeticSurface(camera.positionWC, scratch3DTo2DSurfacePoint);
  521. var toENU = Transforms.eastNorthUpToFixedFrame(surfacePoint, ellipsoid, scratch3DTo2DToENU);
  522. Matrix4.inverseTransformation(toENU, toENU);
  523. Matrix4.multiplyByPointAsVector(toENU, rayDirection, rayDirection);
  524. Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, rayDirection, rayDirection);
  525. var globe = scene.globe;
  526. if (defined(globe)) {
  527. var pickedPos = globe.pickWorldCoordinates(ray, scene, scratch3DTo2DPickPosition);
  528. if (defined(pickedPos)) {
  529. var height = Cartesian3.distance(camera2D.position2D, pickedPos);
  530. pickedPos.x += height;
  531. Cartesian3.clone(pickedPos, camera2D.position2D);
  532. }
  533. }
  534. }
  535. function updateHeight(camera, height) {
  536. camera.position.x = height;
  537. }
  538. Matrix4.multiplyByPoint(Camera.TRANSFORM_2D, camera2D.position, camera2D.position2D);
  539. Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, camera2D.direction, camera2D.direction2D);
  540. Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, camera2D.up, camera2D.up2D);
  541. var frustum = camera2D.frustum;
  542. frustum.right = camera2D.position.z * 0.5;
  543. frustum.left = -frustum.right;
  544. frustum.top = frustum.right * (scene.drawingBufferHeight / scene.drawingBufferWidth);
  545. frustum.bottom = -frustum.top;
  546. var endCamera = scratch3DTo2DEndCamera;
  547. Matrix4.multiplyByPoint(Camera.TRANSFORM_2D_INVERSE, camera2D.position2D, endCamera.position);
  548. Cartesian3.clone(camera2D.direction, endCamera.direction);
  549. Cartesian3.clone(camera2D.up, endCamera.up);
  550. endCamera.frustum = frustum;
  551. var complete = complete2DCallback(endCamera);
  552. createMorphHandler(transitioner, complete);
  553. function completeCallback() {
  554. morphPerspectiveToOrthographic(transitioner, duration, camera2D, updateHeight, complete);
  555. }
  556. morphFrom3DToColumbusView(transitioner, duration, camera2D, completeCallback);
  557. }
  558. function morphOrthographicToPerspective(transitioner, duration, cameraCV, complete) {
  559. var scene = transitioner._scene;
  560. var camera = scene.camera;
  561. var height = camera.frustum.right - camera.frustum.left;
  562. camera.frustum = cameraCV.frustum.clone();
  563. var endFOV = camera.frustum.fov;
  564. var startFOV = CesiumMath.RADIANS_PER_DEGREE * 0.5;
  565. var d = height * Math.tan(endFOV * 0.5);
  566. camera.frustum.far = d / Math.tan(startFOV * 0.5) + 10000000.0;
  567. camera.frustum.fov = startFOV;
  568. function update(value) {
  569. camera.frustum.fov = CesiumMath.lerp(startFOV, endFOV, value.time);
  570. camera.position.z = d / Math.tan(camera.frustum.fov * 0.5);
  571. }
  572. var tween = scene.tweens.add({
  573. duration : duration,
  574. easingFunction : EasingFunction.QUARTIC_OUT,
  575. startObject : {
  576. time : 0.0
  577. },
  578. stopObject : {
  579. time : 1.0
  580. },
  581. update : update,
  582. complete : function() {
  583. complete(transitioner);
  584. }
  585. });
  586. transitioner._currentTweens.push(tween);
  587. }
  588. function morphFrom2DToColumbusView(transitioner, duration, cameraCV, complete) {
  589. duration *= 0.5;
  590. var scene = transitioner._scene;
  591. var camera = scene.camera;
  592. var endPos = Cartesian3.clone(cameraCV.position, scratch3DToCVEndPos);
  593. var endDir = Cartesian3.clone(cameraCV.direction, scratch3DToCVEndDir);
  594. var endUp = Cartesian3.clone(cameraCV.up, scratch3DToCVEndUp);
  595. scene._mode = SceneMode.MORPHING;
  596. function morph() {
  597. camera.frustum = cameraCV.frustum.clone();
  598. var startPos = Cartesian3.clone(camera.position, scratch3DToCVStartPos);
  599. var startDir = Cartesian3.clone(camera.direction, scratch3DToCVStartDir);
  600. var startUp = Cartesian3.clone(camera.up, scratch3DToCVStartUp);
  601. startPos.z = endPos.z;
  602. function update(value) {
  603. columbusViewMorph(startPos, endPos, value.time, camera.position);
  604. columbusViewMorph(startDir, endDir, value.time, camera.direction);
  605. columbusViewMorph(startUp, endUp, value.time, camera.up);
  606. Cartesian3.cross(camera.direction, camera.up, camera.right);
  607. Cartesian3.normalize(camera.right, camera.right);
  608. }
  609. var tween = scene.tweens.add({
  610. duration : duration,
  611. easingFunction : EasingFunction.QUARTIC_OUT,
  612. startObject : {
  613. time : 0.0
  614. },
  615. stopObject : {
  616. time : 1.0
  617. },
  618. update : update,
  619. complete : function() {
  620. complete(transitioner);
  621. }
  622. });
  623. transitioner._currentTweens.push(tween);
  624. }
  625. if (transitioner._morphToOrthographic) {
  626. morph();
  627. } else {
  628. morphOrthographicToPerspective(transitioner, 0.0, cameraCV, morph);
  629. }
  630. }
  631. function morphFrom3DToColumbusView(transitioner, duration, endCamera, complete) {
  632. var scene = transitioner._scene;
  633. var camera = scene.camera;
  634. var startPos = Cartesian3.clone(camera.position, scratch3DToCVStartPos);
  635. var startDir = Cartesian3.clone(camera.direction, scratch3DToCVStartDir);
  636. var startUp = Cartesian3.clone(camera.up, scratch3DToCVStartUp);
  637. var endPos = Cartesian3.clone(endCamera.position2D, scratch3DToCVEndPos);
  638. var endDir = Cartesian3.clone(endCamera.direction2D, scratch3DToCVEndDir);
  639. var endUp = Cartesian3.clone(endCamera.up2D, scratch3DToCVEndUp);
  640. function update(value) {
  641. columbusViewMorph(startPos, endPos, value.time, camera.position);
  642. columbusViewMorph(startDir, endDir, value.time, camera.direction);
  643. columbusViewMorph(startUp, endUp, value.time, camera.up);
  644. Cartesian3.cross(camera.direction, camera.up, camera.right);
  645. Cartesian3.normalize(camera.right, camera.right);
  646. camera._adjustOrthographicFrustum(true);
  647. }
  648. var tween = scene.tweens.add({
  649. duration : duration,
  650. easingFunction : EasingFunction.QUARTIC_OUT,
  651. startObject : {
  652. time : 0.0
  653. },
  654. stopObject : {
  655. time : 1.0
  656. },
  657. update : update,
  658. complete : function() {
  659. addMorphTimeAnimations(transitioner, scene, 1.0, 0.0, duration, complete);
  660. }
  661. });
  662. transitioner._currentTweens.push(tween);
  663. }
  664. function addMorphTimeAnimations(transitioner, scene, start, stop, duration, complete) {
  665. // Later, this will be linear and each object will adjust, if desired, in its vertex shader.
  666. var options = {
  667. object : scene,
  668. property : 'morphTime',
  669. startValue : start,
  670. stopValue : stop,
  671. duration : duration,
  672. easingFunction : EasingFunction.QUARTIC_OUT
  673. };
  674. if (defined(complete)) {
  675. options.complete = function() {
  676. complete(transitioner);
  677. };
  678. }
  679. var tween = scene.tweens.addProperty(options);
  680. transitioner._currentTweens.push(tween);
  681. }
  682. function complete3DCallback(camera3D) {
  683. return function(transitioner) {
  684. var scene = transitioner._scene;
  685. scene._mode = SceneMode.SCENE3D;
  686. scene.morphTime = SceneMode.getMorphTime(SceneMode.SCENE3D);
  687. destroyMorphHandler(transitioner);
  688. var camera = scene.camera;
  689. if (transitioner._previousMode !== SceneMode.MORPHING || transitioner._morphCancelled) {
  690. transitioner._morphCancelled = false;
  691. Cartesian3.clone(camera3D.position, camera.position);
  692. Cartesian3.clone(camera3D.direction, camera.direction);
  693. Cartesian3.clone(camera3D.up, camera.up);
  694. Cartesian3.cross(camera.direction, camera.up, camera.right);
  695. Cartesian3.normalize(camera.right, camera.right);
  696. camera.frustum = camera3D.frustum.clone();
  697. }
  698. var frustum = camera.frustum;
  699. if (scene.frameState.useLogDepth) {
  700. frustum.near = 0.1;
  701. frustum.far = 10000000000.0;
  702. }
  703. var wasMorphing = defined(transitioner._completeMorph);
  704. transitioner._completeMorph = undefined;
  705. scene.camera.update(scene.mode);
  706. transitioner._scene.morphComplete.raiseEvent(transitioner, transitioner._previousMode, SceneMode.SCENE3D, wasMorphing);
  707. };
  708. }
  709. function complete2DCallback(camera2D) {
  710. return function(transitioner) {
  711. var scene = transitioner._scene;
  712. scene._mode = SceneMode.SCENE2D;
  713. scene.morphTime = SceneMode.getMorphTime(SceneMode.SCENE2D);
  714. destroyMorphHandler(transitioner);
  715. var camera = scene.camera;
  716. Cartesian3.clone(camera2D.position, camera.position);
  717. camera.position.z = scene.mapProjection.ellipsoid.maximumRadius * 2.0;
  718. Cartesian3.clone(camera2D.direction, camera.direction);
  719. Cartesian3.clone(camera2D.up, camera.up);
  720. Cartesian3.cross(camera.direction, camera.up, camera.right);
  721. Cartesian3.normalize(camera.right, camera.right);
  722. camera.frustum = camera2D.frustum.clone();
  723. var wasMorphing = defined(transitioner._completeMorph);
  724. transitioner._completeMorph = undefined;
  725. scene.camera.update(scene.mode);
  726. transitioner._scene.morphComplete.raiseEvent(transitioner, transitioner._previousMode, SceneMode.SCENE2D, wasMorphing);
  727. };
  728. }
  729. function completeColumbusViewCallback(cameraCV) {
  730. return function(transitioner) {
  731. var scene = transitioner._scene;
  732. scene._mode = SceneMode.COLUMBUS_VIEW;
  733. scene.morphTime = SceneMode.getMorphTime(SceneMode.COLUMBUS_VIEW);
  734. destroyMorphHandler(transitioner);
  735. var camera = scene.camera;
  736. if (transitioner._previousModeMode !== SceneMode.MORPHING || transitioner._morphCancelled) {
  737. transitioner._morphCancelled = false;
  738. Cartesian3.clone(cameraCV.position, camera.position);
  739. Cartesian3.clone(cameraCV.direction, camera.direction);
  740. Cartesian3.clone(cameraCV.up, camera.up);
  741. Cartesian3.cross(camera.direction, camera.up, camera.right);
  742. Cartesian3.normalize(camera.right, camera.right);
  743. }
  744. var frustum = camera.frustum;
  745. if (scene.frameState.useLogDepth) {
  746. frustum.near = 0.1;
  747. frustum.far = 10000000000.0;
  748. }
  749. var wasMorphing = defined(transitioner._completeMorph);
  750. transitioner._completeMorph = undefined;
  751. scene.camera.update(scene.mode);
  752. transitioner._scene.morphComplete.raiseEvent(transitioner, transitioner._previousMode, SceneMode.COLUMBUS_VIEW, wasMorphing);
  753. };
  754. }
  755. export default SceneTransitioner;