import Cartesian3 from "../Core/Cartesian3.js"; import Cartographic from "../Core/Cartographic.js"; import Check from "../Core/Check.js"; import defined from "../Core/defined.js"; import destroyObject from "../Core/destroyObject.js"; import EasingFunction from "../Core/EasingFunction.js"; import CesiumMath from "../Core/Math.js"; import Matrix4 from "../Core/Matrix4.js"; import OrthographicFrustum from "../Core/OrthographicFrustum.js"; import OrthographicOffCenterFrustum from "../Core/OrthographicOffCenterFrustum.js"; import PerspectiveFrustum from "../Core/PerspectiveFrustum.js"; import Ray from "../Core/Ray.js"; import ScreenSpaceEventHandler from "../Core/ScreenSpaceEventHandler.js"; import ScreenSpaceEventType from "../Core/ScreenSpaceEventType.js"; import Transforms from "../Core/Transforms.js"; import Camera from "./Camera.js"; import SceneMode from "./SceneMode.js"; /** * @private */ function SceneTransitioner(scene) { //>>includeStart('debug', pragmas.debug); Check.typeOf.object("scene", scene); //>>includeEnd('debug'); this._scene = scene; this._currentTweens = []; this._morphHandler = undefined; this._morphCancelled = false; this._completeMorph = undefined; this._morphToOrthographic = false; } SceneTransitioner.prototype.completeMorph = function () { if (defined(this._completeMorph)) { this._completeMorph(); } }; SceneTransitioner.prototype.morphTo2D = function (duration, ellipsoid) { if (defined(this._completeMorph)) { this._completeMorph(); } const scene = this._scene; this._previousMode = scene.mode; this._morphToOrthographic = scene.camera.frustum instanceof OrthographicFrustum; if ( this._previousMode === SceneMode.SCENE2D || this._previousMode === SceneMode.MORPHING ) { return; } this._scene.morphStart.raiseEvent( this, this._previousMode, SceneMode.SCENE2D, true ); scene._mode = SceneMode.MORPHING; scene.camera._setTransform(Matrix4.IDENTITY); if (this._previousMode === SceneMode.COLUMBUS_VIEW) { morphFromColumbusViewTo2D(this, duration); } else { morphFrom3DTo2D(this, duration, ellipsoid); } if (duration === 0.0 && defined(this._completeMorph)) { this._completeMorph(); } }; const scratchToCVPosition = new Cartesian3(); const scratchToCVDirection = new Cartesian3(); const scratchToCVUp = new Cartesian3(); const scratchToCVPosition2D = new Cartesian3(); const scratchToCVDirection2D = new Cartesian3(); const scratchToCVUp2D = new Cartesian3(); const scratchToCVSurfacePosition = new Cartesian3(); const scratchToCVCartographic = new Cartographic(); const scratchToCVToENU = new Matrix4(); const scratchToCVFrustumPerspective = new PerspectiveFrustum(); const scratchToCVFrustumOrthographic = new OrthographicFrustum(); const scratchToCVCamera = { position: undefined, direction: undefined, up: undefined, position2D: undefined, direction2D: undefined, up2D: undefined, frustum: undefined, }; SceneTransitioner.prototype.morphToColumbusView = function ( duration, ellipsoid ) { if (defined(this._completeMorph)) { this._completeMorph(); } const scene = this._scene; this._previousMode = scene.mode; if ( this._previousMode === SceneMode.COLUMBUS_VIEW || this._previousMode === SceneMode.MORPHING ) { return; } this._scene.morphStart.raiseEvent( this, this._previousMode, SceneMode.COLUMBUS_VIEW, true ); scene.camera._setTransform(Matrix4.IDENTITY); let position = scratchToCVPosition; const direction = scratchToCVDirection; const up = scratchToCVUp; if (duration > 0.0) { position.x = 0.0; position.y = -1.0; position.z = 1.0; position = Cartesian3.multiplyByScalar( Cartesian3.normalize(position, position), 5.0 * ellipsoid.maximumRadius, position ); Cartesian3.negate(Cartesian3.normalize(position, direction), direction); Cartesian3.cross(Cartesian3.UNIT_X, direction, up); } else { const camera = scene.camera; if (this._previousMode === SceneMode.SCENE2D) { Cartesian3.clone(camera.position, position); position.z = camera.frustum.right - camera.frustum.left; Cartesian3.negate(Cartesian3.UNIT_Z, direction); Cartesian3.clone(Cartesian3.UNIT_Y, up); } else { Cartesian3.clone(camera.positionWC, position); Cartesian3.clone(camera.directionWC, direction); Cartesian3.clone(camera.upWC, up); const surfacePoint = ellipsoid.scaleToGeodeticSurface( position, scratchToCVSurfacePosition ); const toENU = Transforms.eastNorthUpToFixedFrame( surfacePoint, ellipsoid, scratchToCVToENU ); Matrix4.inverseTransformation(toENU, toENU); scene.mapProjection.project( ellipsoid.cartesianToCartographic(position, scratchToCVCartographic), position ); Matrix4.multiplyByPointAsVector(toENU, direction, direction); Matrix4.multiplyByPointAsVector(toENU, up, up); } } let frustum; if (this._morphToOrthographic) { frustum = scratchToCVFrustumOrthographic; frustum.width = scene.camera.frustum.right - scene.camera.frustum.left; frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight; } else { frustum = scratchToCVFrustumPerspective; frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight; frustum.fov = CesiumMath.toRadians(60.0); } const cameraCV = scratchToCVCamera; cameraCV.position = position; cameraCV.direction = direction; cameraCV.up = up; cameraCV.frustum = frustum; const complete = completeColumbusViewCallback(cameraCV); createMorphHandler(this, complete); if (this._previousMode === SceneMode.SCENE2D) { morphFrom2DToColumbusView(this, duration, cameraCV, complete); } else { cameraCV.position2D = Matrix4.multiplyByPoint( Camera.TRANSFORM_2D, position, scratchToCVPosition2D ); cameraCV.direction2D = Matrix4.multiplyByPointAsVector( Camera.TRANSFORM_2D, direction, scratchToCVDirection2D ); cameraCV.up2D = Matrix4.multiplyByPointAsVector( Camera.TRANSFORM_2D, up, scratchToCVUp2D ); scene._mode = SceneMode.MORPHING; morphFrom3DToColumbusView(this, duration, cameraCV, complete); } if (duration === 0.0 && defined(this._completeMorph)) { this._completeMorph(); } }; const scratchCVTo3DCamera = { position: new Cartesian3(), direction: new Cartesian3(), up: new Cartesian3(), frustum: undefined, }; const scratch2DTo3DFrustumPersp = new PerspectiveFrustum(); SceneTransitioner.prototype.morphTo3D = function (duration, ellipsoid) { if (defined(this._completeMorph)) { this._completeMorph(); } const scene = this._scene; this._previousMode = scene.mode; if ( this._previousMode === SceneMode.SCENE3D || this._previousMode === SceneMode.MORPHING ) { return; } this._scene.morphStart.raiseEvent( this, this._previousMode, SceneMode.SCENE3D, true ); scene._mode = SceneMode.MORPHING; scene.camera._setTransform(Matrix4.IDENTITY); if (this._previousMode === SceneMode.SCENE2D) { morphFrom2DTo3D(this, duration, ellipsoid); } else { let camera3D; if (duration > 0.0) { camera3D = scratchCVTo3DCamera; Cartesian3.fromDegrees( 0.0, 0.0, 5.0 * ellipsoid.maximumRadius, ellipsoid, camera3D.position ); Cartesian3.negate(camera3D.position, camera3D.direction); Cartesian3.normalize(camera3D.direction, camera3D.direction); Cartesian3.clone(Cartesian3.UNIT_Z, camera3D.up); } else { camera3D = getColumbusViewTo3DCamera(this, ellipsoid); } let frustum; const camera = scene.camera; if (camera.frustum instanceof OrthographicFrustum) { frustum = camera.frustum.clone(); } else { frustum = scratch2DTo3DFrustumPersp; frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight; frustum.fov = CesiumMath.toRadians(60.0); } camera3D.frustum = frustum; const complete = complete3DCallback(camera3D); createMorphHandler(this, complete); morphFromColumbusViewTo3D(this, duration, camera3D, complete); } if (duration === 0.0 && defined(this._completeMorph)) { this._completeMorph(); } }; /** * Returns true if this object was destroyed; otherwise, false. *

* If this object was destroyed, it should not be used; calling any function other than * isDestroyed will result in a {@link DeveloperError} exception. * * @returns {boolean} true if this object was destroyed; otherwise, false. */ SceneTransitioner.prototype.isDestroyed = function () { return false; }; /** * Once an object is destroyed, it should not be used; calling any function other than * isDestroyed will result in a {@link DeveloperError} exception. Therefore, * assign the return value (undefined) to the object as done in the example. * * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called. * * @example * transitioner = transitioner && transitioner.destroy(); */ SceneTransitioner.prototype.destroy = function () { destroyMorphHandler(this); return destroyObject(this); }; function createMorphHandler(transitioner, completeMorphFunction) { if (transitioner._scene.completeMorphOnUserInput) { transitioner._morphHandler = new ScreenSpaceEventHandler( transitioner._scene.canvas ); const completeMorph = function () { transitioner._morphCancelled = true; transitioner._scene.camera.cancelFlight(); completeMorphFunction(transitioner); }; transitioner._completeMorph = completeMorph; transitioner._morphHandler.setInputAction( completeMorph, ScreenSpaceEventType.LEFT_DOWN ); transitioner._morphHandler.setInputAction( completeMorph, ScreenSpaceEventType.MIDDLE_DOWN ); transitioner._morphHandler.setInputAction( completeMorph, ScreenSpaceEventType.RIGHT_DOWN ); transitioner._morphHandler.setInputAction( completeMorph, ScreenSpaceEventType.WHEEL ); } } function destroyMorphHandler(transitioner) { const tweens = transitioner._currentTweens; for (let i = 0; i < tweens.length; ++i) { tweens[i].cancelTween(); } transitioner._currentTweens.length = 0; transitioner._morphHandler = transitioner._morphHandler && transitioner._morphHandler.destroy(); } const scratchCVTo3DCartographic = new Cartographic(); const scratchCVTo3DSurfacePoint = new Cartesian3(); const scratchCVTo3DFromENU = new Matrix4(); function getColumbusViewTo3DCamera(transitioner, ellipsoid) { const scene = transitioner._scene; const camera = scene.camera; const camera3D = scratchCVTo3DCamera; const position = camera3D.position; const direction = camera3D.direction; const up = camera3D.up; const positionCarto = scene.mapProjection.unproject( camera.position, scratchCVTo3DCartographic ); ellipsoid.cartographicToCartesian(positionCarto, position); const surfacePoint = ellipsoid.scaleToGeodeticSurface( position, scratchCVTo3DSurfacePoint ); const fromENU = Transforms.eastNorthUpToFixedFrame( surfacePoint, ellipsoid, scratchCVTo3DFromENU ); Matrix4.multiplyByPointAsVector(fromENU, camera.direction, direction); Matrix4.multiplyByPointAsVector(fromENU, camera.up, up); return camera3D; } const scratchCVTo3DStartPos = new Cartesian3(); const scratchCVTo3DStartDir = new Cartesian3(); const scratchCVTo3DStartUp = new Cartesian3(); const scratchCVTo3DEndPos = new Cartesian3(); const scratchCVTo3DEndDir = new Cartesian3(); const scratchCVTo3DEndUp = new Cartesian3(); function morphFromColumbusViewTo3D( transitioner, duration, endCamera, complete ) { duration *= 0.5; const scene = transitioner._scene; const camera = scene.camera; const startPos = Cartesian3.clone(camera.position, scratchCVTo3DStartPos); const startDir = Cartesian3.clone(camera.direction, scratchCVTo3DStartDir); const startUp = Cartesian3.clone(camera.up, scratchCVTo3DStartUp); const endPos = Matrix4.multiplyByPoint( Camera.TRANSFORM_2D_INVERSE, endCamera.position, scratchCVTo3DEndPos ); const endDir = Matrix4.multiplyByPointAsVector( Camera.TRANSFORM_2D_INVERSE, endCamera.direction, scratchCVTo3DEndDir ); const endUp = Matrix4.multiplyByPointAsVector( Camera.TRANSFORM_2D_INVERSE, endCamera.up, scratchCVTo3DEndUp ); function update(value) { columbusViewMorph(startPos, endPos, value.time, camera.position); columbusViewMorph(startDir, endDir, value.time, camera.direction); columbusViewMorph(startUp, endUp, value.time, camera.up); Cartesian3.cross(camera.direction, camera.up, camera.right); Cartesian3.normalize(camera.right, camera.right); } const tween = scene.tweens.add({ duration: duration, easingFunction: EasingFunction.QUARTIC_OUT, startObject: { time: 0.0, }, stopObject: { time: 1.0, }, update: update, complete: function () { addMorphTimeAnimations(transitioner, scene, 0.0, 1.0, duration, complete); }, }); transitioner._currentTweens.push(tween); } const scratch2DTo3DFrustumOrtho = new OrthographicFrustum(); const scratch3DToCVStartPos = new Cartesian3(); const scratch3DToCVStartDir = new Cartesian3(); const scratch3DToCVStartUp = new Cartesian3(); const scratch3DToCVEndPos = new Cartesian3(); const scratch3DToCVEndDir = new Cartesian3(); const scratch3DToCVEndUp = new Cartesian3(); function morphFrom2DTo3D(transitioner, duration, ellipsoid) { duration /= 3.0; const scene = transitioner._scene; const camera = scene.camera; let camera3D; if (duration > 0.0) { camera3D = scratchCVTo3DCamera; Cartesian3.fromDegrees( 0.0, 0.0, 5.0 * ellipsoid.maximumRadius, ellipsoid, camera3D.position ); Cartesian3.negate(camera3D.position, camera3D.direction); Cartesian3.normalize(camera3D.direction, camera3D.direction); Cartesian3.clone(Cartesian3.UNIT_Z, camera3D.up); } else { camera.position.z = camera.frustum.right - camera.frustum.left; camera3D = getColumbusViewTo3DCamera(transitioner, ellipsoid); } let frustum; if (transitioner._morphToOrthographic) { frustum = scratch2DTo3DFrustumOrtho; frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight; frustum.width = camera.frustum.right - camera.frustum.left; } else { frustum = scratch2DTo3DFrustumPersp; frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight; frustum.fov = CesiumMath.toRadians(60.0); } camera3D.frustum = frustum; const complete = complete3DCallback(camera3D); createMorphHandler(transitioner, complete); let morph; if (transitioner._morphToOrthographic) { morph = function () { morphFromColumbusViewTo3D(transitioner, duration, camera3D, complete); }; } else { morph = function () { morphOrthographicToPerspective( transitioner, duration, camera3D, function () { morphFromColumbusViewTo3D(transitioner, duration, camera3D, complete); } ); }; } if (duration > 0.0) { scene._mode = SceneMode.SCENE2D; camera.flyTo({ duration: duration, destination: Cartesian3.fromDegrees( 0.0, 0.0, 5.0 * ellipsoid.maximumRadius, ellipsoid, scratch3DToCVEndPos ), complete: function () { scene._mode = SceneMode.MORPHING; morph(); }, }); } else { morph(); } } function columbusViewMorph(startPosition, endPosition, time, result) { // Just linear for now. return Cartesian3.lerp(startPosition, endPosition, time, result); } function morphPerspectiveToOrthographic( transitioner, duration, endCamera, updateHeight, complete ) { const scene = transitioner._scene; const camera = scene.camera; if (camera.frustum instanceof OrthographicFrustum) { return; } const startFOV = camera.frustum.fov; const endFOV = CesiumMath.RADIANS_PER_DEGREE * 0.5; const d = endCamera.position.z * Math.tan(startFOV * 0.5); camera.frustum.far = d / Math.tan(endFOV * 0.5) + 10000000.0; function update(value) { camera.frustum.fov = CesiumMath.lerp(startFOV, endFOV, value.time); const height = d / Math.tan(camera.frustum.fov * 0.5); updateHeight(camera, height); } const tween = scene.tweens.add({ duration: duration, easingFunction: EasingFunction.QUARTIC_OUT, startObject: { time: 0.0, }, stopObject: { time: 1.0, }, update: update, complete: function () { camera.frustum = endCamera.frustum.clone(); complete(transitioner); }, }); transitioner._currentTweens.push(tween); } const scratchCVTo2DStartPos = new Cartesian3(); const scratchCVTo2DStartDir = new Cartesian3(); const scratchCVTo2DStartUp = new Cartesian3(); const scratchCVTo2DEndPos = new Cartesian3(); const scratchCVTo2DEndDir = new Cartesian3(); const scratchCVTo2DEndUp = new Cartesian3(); const scratchCVTo2DFrustum = new OrthographicOffCenterFrustum(); const scratchCVTo2DRay = new Ray(); const scratchCVTo2DPickPos = new Cartesian3(); const scratchCVTo2DCamera = { position: undefined, direction: undefined, up: undefined, frustum: undefined, }; function morphFromColumbusViewTo2D(transitioner, duration) { duration *= 0.5; const scene = transitioner._scene; const camera = scene.camera; const startPos = Cartesian3.clone(camera.position, scratchCVTo2DStartPos); const startDir = Cartesian3.clone(camera.direction, scratchCVTo2DStartDir); const startUp = Cartesian3.clone(camera.up, scratchCVTo2DStartUp); const endDir = Cartesian3.negate(Cartesian3.UNIT_Z, scratchCVTo2DEndDir); const endUp = Cartesian3.clone(Cartesian3.UNIT_Y, scratchCVTo2DEndUp); const endPos = scratchCVTo2DEndPos; if (duration > 0.0) { Cartesian3.clone(Cartesian3.ZERO, scratchCVTo2DEndPos); endPos.z = 5.0 * scene.mapProjection.ellipsoid.maximumRadius; } else { Cartesian3.clone(startPos, scratchCVTo2DEndPos); const ray = scratchCVTo2DRay; Matrix4.multiplyByPoint(Camera.TRANSFORM_2D, startPos, ray.origin); Matrix4.multiplyByPointAsVector( Camera.TRANSFORM_2D, startDir, ray.direction ); const globe = scene.globe; if (defined(globe)) { const pickPos = globe.pickWorldCoordinates( ray, scene, true, scratchCVTo2DPickPos ); if (defined(pickPos)) { Matrix4.multiplyByPoint(Camera.TRANSFORM_2D_INVERSE, pickPos, endPos); endPos.z += Cartesian3.distance(startPos, endPos); } } } const frustum = scratchCVTo2DFrustum; frustum.right = endPos.z * 0.5; frustum.left = -frustum.right; frustum.top = frustum.right * (scene.drawingBufferHeight / scene.drawingBufferWidth); frustum.bottom = -frustum.top; const camera2D = scratchCVTo2DCamera; camera2D.position = endPos; camera2D.direction = endDir; camera2D.up = endUp; camera2D.frustum = frustum; const complete = complete2DCallback(camera2D); createMorphHandler(transitioner, complete); function updateCV(value) { columbusViewMorph(startPos, endPos, value.time, camera.position); columbusViewMorph(startDir, endDir, value.time, camera.direction); columbusViewMorph(startUp, endUp, value.time, camera.up); Cartesian3.cross(camera.direction, camera.up, camera.right); Cartesian3.normalize(camera.right, camera.right); camera._adjustOrthographicFrustum(true); } function updateHeight(camera, height) { camera.position.z = height; } const tween = scene.tweens.add({ duration: duration, easingFunction: EasingFunction.QUARTIC_OUT, startObject: { time: 0.0, }, stopObject: { time: 1.0, }, update: updateCV, complete: function () { morphPerspectiveToOrthographic( transitioner, duration, camera2D, updateHeight, complete ); }, }); transitioner._currentTweens.push(tween); } const scratch3DTo2DCartographic = new Cartographic(); const scratch3DTo2DCamera = { position: new Cartesian3(), direction: new Cartesian3(), up: new Cartesian3(), position2D: new Cartesian3(), direction2D: new Cartesian3(), up2D: new Cartesian3(), frustum: new OrthographicOffCenterFrustum(), }; const scratch3DTo2DEndCamera = { position: new Cartesian3(), direction: new Cartesian3(), up: new Cartesian3(), frustum: undefined, }; const scratch3DTo2DPickPosition = new Cartesian3(); const scratch3DTo2DRay = new Ray(); const scratch3DTo2DToENU = new Matrix4(); const scratch3DTo2DSurfacePoint = new Cartesian3(); function morphFrom3DTo2D(transitioner, duration, ellipsoid) { duration *= 0.5; const scene = transitioner._scene; const camera = scene.camera; const camera2D = scratch3DTo2DCamera; if (duration > 0.0) { Cartesian3.clone(Cartesian3.ZERO, camera2D.position); camera2D.position.z = 5.0 * ellipsoid.maximumRadius; Cartesian3.negate(Cartesian3.UNIT_Z, camera2D.direction); Cartesian3.clone(Cartesian3.UNIT_Y, camera2D.up); } else { ellipsoid.cartesianToCartographic( camera.positionWC, scratch3DTo2DCartographic ); scene.mapProjection.project(scratch3DTo2DCartographic, camera2D.position); Cartesian3.negate(Cartesian3.UNIT_Z, camera2D.direction); Cartesian3.clone(Cartesian3.UNIT_Y, camera2D.up); const ray = scratch3DTo2DRay; Cartesian3.clone(camera2D.position2D, ray.origin); const rayDirection = Cartesian3.clone(camera.directionWC, ray.direction); const surfacePoint = ellipsoid.scaleToGeodeticSurface( camera.positionWC, scratch3DTo2DSurfacePoint ); const toENU = Transforms.eastNorthUpToFixedFrame( surfacePoint, ellipsoid, scratch3DTo2DToENU ); Matrix4.inverseTransformation(toENU, toENU); Matrix4.multiplyByPointAsVector(toENU, rayDirection, rayDirection); Matrix4.multiplyByPointAsVector( Camera.TRANSFORM_2D, rayDirection, rayDirection ); const globe = scene.globe; if (defined(globe)) { const pickedPos = globe.pickWorldCoordinates( ray, scene, true, scratch3DTo2DPickPosition ); if (defined(pickedPos)) { const height = Cartesian3.distance(camera2D.position2D, pickedPos); pickedPos.x += height; Cartesian3.clone(pickedPos, camera2D.position2D); } } } function updateHeight(camera, height) { camera.position.x = height; } Matrix4.multiplyByPoint( Camera.TRANSFORM_2D, camera2D.position, camera2D.position2D ); Matrix4.multiplyByPointAsVector( Camera.TRANSFORM_2D, camera2D.direction, camera2D.direction2D ); Matrix4.multiplyByPointAsVector( Camera.TRANSFORM_2D, camera2D.up, camera2D.up2D ); const frustum = camera2D.frustum; frustum.right = camera2D.position.z * 0.5; frustum.left = -frustum.right; frustum.top = frustum.right * (scene.drawingBufferHeight / scene.drawingBufferWidth); frustum.bottom = -frustum.top; const endCamera = scratch3DTo2DEndCamera; Matrix4.multiplyByPoint( Camera.TRANSFORM_2D_INVERSE, camera2D.position2D, endCamera.position ); Cartesian3.clone(camera2D.direction, endCamera.direction); Cartesian3.clone(camera2D.up, endCamera.up); endCamera.frustum = frustum; const complete = complete2DCallback(endCamera); createMorphHandler(transitioner, complete); function completeCallback() { morphPerspectiveToOrthographic( transitioner, duration, camera2D, updateHeight, complete ); } morphFrom3DToColumbusView(transitioner, duration, camera2D, completeCallback); } function morphOrthographicToPerspective( transitioner, duration, cameraCV, complete ) { const scene = transitioner._scene; const camera = scene.camera; const height = camera.frustum.right - camera.frustum.left; camera.frustum = cameraCV.frustum.clone(); const endFOV = camera.frustum.fov; const startFOV = CesiumMath.RADIANS_PER_DEGREE * 0.5; const d = height * Math.tan(endFOV * 0.5); camera.frustum.far = d / Math.tan(startFOV * 0.5) + 10000000.0; camera.frustum.fov = startFOV; function update(value) { camera.frustum.fov = CesiumMath.lerp(startFOV, endFOV, value.time); camera.position.z = d / Math.tan(camera.frustum.fov * 0.5); } const tween = scene.tweens.add({ duration: duration, easingFunction: EasingFunction.QUARTIC_OUT, startObject: { time: 0.0, }, stopObject: { time: 1.0, }, update: update, complete: function () { complete(transitioner); }, }); transitioner._currentTweens.push(tween); } function morphFrom2DToColumbusView(transitioner, duration, cameraCV, complete) { duration *= 0.5; const scene = transitioner._scene; const camera = scene.camera; const endPos = Cartesian3.clone(cameraCV.position, scratch3DToCVEndPos); const endDir = Cartesian3.clone(cameraCV.direction, scratch3DToCVEndDir); const endUp = Cartesian3.clone(cameraCV.up, scratch3DToCVEndUp); scene._mode = SceneMode.MORPHING; function morph() { camera.frustum = cameraCV.frustum.clone(); const startPos = Cartesian3.clone(camera.position, scratch3DToCVStartPos); const startDir = Cartesian3.clone(camera.direction, scratch3DToCVStartDir); const startUp = Cartesian3.clone(camera.up, scratch3DToCVStartUp); startPos.z = endPos.z; function update(value) { columbusViewMorph(startPos, endPos, value.time, camera.position); columbusViewMorph(startDir, endDir, value.time, camera.direction); columbusViewMorph(startUp, endUp, value.time, camera.up); Cartesian3.cross(camera.direction, camera.up, camera.right); Cartesian3.normalize(camera.right, camera.right); } const tween = scene.tweens.add({ duration: duration, easingFunction: EasingFunction.QUARTIC_OUT, startObject: { time: 0.0, }, stopObject: { time: 1.0, }, update: update, complete: function () { complete(transitioner); }, }); transitioner._currentTweens.push(tween); } if (transitioner._morphToOrthographic) { morph(); } else { morphOrthographicToPerspective(transitioner, 0.0, cameraCV, morph); } } function morphFrom3DToColumbusView( transitioner, duration, endCamera, complete ) { const scene = transitioner._scene; const camera = scene.camera; const startPos = Cartesian3.clone(camera.position, scratch3DToCVStartPos); const startDir = Cartesian3.clone(camera.direction, scratch3DToCVStartDir); const startUp = Cartesian3.clone(camera.up, scratch3DToCVStartUp); const endPos = Cartesian3.clone(endCamera.position2D, scratch3DToCVEndPos); const endDir = Cartesian3.clone(endCamera.direction2D, scratch3DToCVEndDir); const endUp = Cartesian3.clone(endCamera.up2D, scratch3DToCVEndUp); function update(value) { columbusViewMorph(startPos, endPos, value.time, camera.position); columbusViewMorph(startDir, endDir, value.time, camera.direction); columbusViewMorph(startUp, endUp, value.time, camera.up); Cartesian3.cross(camera.direction, camera.up, camera.right); Cartesian3.normalize(camera.right, camera.right); camera._adjustOrthographicFrustum(true); } const tween = scene.tweens.add({ duration: duration, easingFunction: EasingFunction.QUARTIC_OUT, startObject: { time: 0.0, }, stopObject: { time: 1.0, }, update: update, complete: function () { addMorphTimeAnimations(transitioner, scene, 1.0, 0.0, duration, complete); }, }); transitioner._currentTweens.push(tween); } function addMorphTimeAnimations( transitioner, scene, start, stop, duration, complete ) { // Later, this will be linear and each object will adjust, if desired, in its vertex shader. const options = { object: scene, property: "morphTime", startValue: start, stopValue: stop, duration: duration, easingFunction: EasingFunction.QUARTIC_OUT, }; if (defined(complete)) { options.complete = function () { complete(transitioner); }; } const tween = scene.tweens.addProperty(options); transitioner._currentTweens.push(tween); } function complete3DCallback(camera3D) { return function (transitioner) { const scene = transitioner._scene; scene._mode = SceneMode.SCENE3D; scene.morphTime = SceneMode.getMorphTime(SceneMode.SCENE3D); destroyMorphHandler(transitioner); const camera = scene.camera; if ( transitioner._previousMode !== SceneMode.MORPHING || transitioner._morphCancelled ) { transitioner._morphCancelled = false; Cartesian3.clone(camera3D.position, camera.position); Cartesian3.clone(camera3D.direction, camera.direction); Cartesian3.clone(camera3D.up, camera.up); Cartesian3.cross(camera.direction, camera.up, camera.right); Cartesian3.normalize(camera.right, camera.right); camera.frustum = camera3D.frustum.clone(); } const frustum = camera.frustum; if (scene.frameState.useLogDepth) { frustum.near = 0.1; frustum.far = 10000000000.0; } const wasMorphing = defined(transitioner._completeMorph); transitioner._completeMorph = undefined; scene.camera.update(scene.mode); transitioner._scene.morphComplete.raiseEvent( transitioner, transitioner._previousMode, SceneMode.SCENE3D, wasMorphing ); }; } function complete2DCallback(camera2D) { return function (transitioner) { const scene = transitioner._scene; scene._mode = SceneMode.SCENE2D; scene.morphTime = SceneMode.getMorphTime(SceneMode.SCENE2D); destroyMorphHandler(transitioner); const camera = scene.camera; Cartesian3.clone(camera2D.position, camera.position); camera.position.z = scene.mapProjection.ellipsoid.maximumRadius * 2.0; Cartesian3.clone(camera2D.direction, camera.direction); Cartesian3.clone(camera2D.up, camera.up); Cartesian3.cross(camera.direction, camera.up, camera.right); Cartesian3.normalize(camera.right, camera.right); camera.frustum = camera2D.frustum.clone(); const wasMorphing = defined(transitioner._completeMorph); transitioner._completeMorph = undefined; scene.camera.update(scene.mode); transitioner._scene.morphComplete.raiseEvent( transitioner, transitioner._previousMode, SceneMode.SCENE2D, wasMorphing ); }; } function completeColumbusViewCallback(cameraCV) { return function (transitioner) { const scene = transitioner._scene; scene._mode = SceneMode.COLUMBUS_VIEW; scene.morphTime = SceneMode.getMorphTime(SceneMode.COLUMBUS_VIEW); destroyMorphHandler(transitioner); const camera = scene.camera; if ( transitioner._previousModeMode !== SceneMode.MORPHING || transitioner._morphCancelled ) { transitioner._morphCancelled = false; Cartesian3.clone(cameraCV.position, camera.position); Cartesian3.clone(cameraCV.direction, camera.direction); Cartesian3.clone(cameraCV.up, camera.up); Cartesian3.cross(camera.direction, camera.up, camera.right); Cartesian3.normalize(camera.right, camera.right); } const frustum = camera.frustum; if (scene.frameState.useLogDepth) { frustum.near = 0.1; frustum.far = 10000000000.0; } const wasMorphing = defined(transitioner._completeMorph); transitioner._completeMorph = undefined; scene.camera.update(scene.mode); transitioner._scene.morphComplete.raiseEvent( transitioner, transitioner._previousMode, SceneMode.COLUMBUS_VIEW, wasMorphing ); }; } export default SceneTransitioner;