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;