diff --git a/Apps/Sandcastle/gallery/Camera.html b/Apps/Sandcastle/gallery/Camera.html index 8dbbb33272a0..b52641041766 100644 --- a/Apps/Sandcastle/gallery/Camera.html +++ b/Apps/Sandcastle/gallery/Camera.html @@ -189,8 +189,35 @@ }); } +function flyInACity() { + Sandcastle.declare(flyInACity); + + var camera = scene.camera; + camera.flyTo({ + destination : Cesium.Cartesian3.fromDegrees(-73.98580932617188, 40.74843406689482, 363.34038727246224), + complete : function() { + setTimeout(function() { + camera.flyTo({ + destination : Cesium.Cartesian3.fromDegrees(-73.98585975679403, 40.75759944127251, 186.50838555841779), + orientation : { + heading : Cesium.Math.toRadians(200.0), + pitch : Cesium.Math.toRadians(-50.0) + }, + easingFunction : Cesium.EasingFunction.LINEAR_NONE + }); + }, 3000); + } + }); +} + Sandcastle.addToolbarMenu([{ text : 'Camera Options' +}, { + text : 'Fly in a city', + onselect : function() { + flyInACity(); + Sandcastle.highlight(flyInACity); + } }, { text : 'Fly to San Diego', onselect : function() { diff --git a/CHANGES.md b/CHANGES.md index a0dde7454ef5..97000fef604f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ Change Log * Breaking changes * Removed `Scene.fxaaOrderIndependentTranslucency`, which was deprecated in 1.10. Use `Scene.fxaa` which is now `true` by default. + * Removed `Camera.clone` that was deprecated in 1.10. * Deprecated * The STK World Terrain url `cesiumjs.org/stk-terrain/world` has been deprecated, use `assets.agi.com/stk-terrain/world` instead. A redirect will be in place until 1.14. * Deprecated `AxisAlignedBoundingBox.intersect` and `BoundingSphere.intersect`. These will be removed in 1.13. Use `.intersectPlane` and, if necessary, `Plane.fromCartesian4`. @@ -31,6 +32,13 @@ Change Log * Add `TerrainMesh.orientedBoundingBox` which holds the `OrientedBoundingBox` for the mesh for a single terrain tile. * Use `OrientedBoundingBox` when rendering terrain and imagery to improve performance of rendering and loading (by up to 50% of terrain/imagery tiles, depending on camera view). * Fixed 2D and Columbus view lighting issue [#2635](https://github.com/AnalyticalGraphicsInc/cesium/issues/2635). +* Improved camera flights. [#2825](https://github.com/AnalyticalGraphicsInc/cesium/pull/2825) +* Fixed camera flights that ended up at the wrong position in Columbus view. [#802](https://github.com/AnalyticalGraphicsInc/cesium/issues/802) +* Fixed camera flights through the map in 2D. [#804](https://github.com/AnalyticalGraphicsInc/cesium/issues/804) +* Fixed strange camera flights from opposite sides of the globe. [#1158](https://github.com/AnalyticalGraphicsInc/cesium/issues/1158) +* Fixed camera flights that wouldn't fly to the home view after zooming out past it. [#1400](https://github.com/AnalyticalGraphicsInc/cesium/issues/1400) +* Fixed flying to rectangles that cross the IDL in Columbus view and 2D. [#2093](https://github.com/AnalyticalGraphicsInc/cesium/issues/2093) +* Fixed flights with a pitch of -90 degrees. [#2468](https://github.com/AnalyticalGraphicsInc/cesium/issues/2468) ### 1.10 - 2015-06-01 diff --git a/Source/Core/EasingFunction.js b/Source/Core/EasingFunction.js index 154c1384b1b7..ef96a6e6d888 100644 --- a/Source/Core/EasingFunction.js +++ b/Source/Core/EasingFunction.js @@ -14,8 +14,6 @@ define([ * * @namespace * @alias EasingFunction - * - * @private */ var EasingFunction = { /** diff --git a/Source/Scene/Camera.js b/Source/Scene/Camera.js index dd47c2eea875..2a9001eaaf87 100644 --- a/Source/Scene/Camera.js +++ b/Source/Scene/Camera.js @@ -508,6 +508,31 @@ define([ } } + function getHeading(direction, up) { + var heading; + if (!CesiumMath.equalsEpsilon(Math.abs(direction.z), 1.0, CesiumMath.EPSILON3)) { + heading = Math.atan2(direction.y, direction.x) - CesiumMath.PI_OVER_TWO; + } else { + heading = Math.atan2(up.y, up.x) - CesiumMath.PI_OVER_TWO; + } + + return CesiumMath.TWO_PI - CesiumMath.zeroToTwoPi(heading); + } + + function getPitch(direction) { + return CesiumMath.PI_OVER_TWO - CesiumMath.acosClamped(direction.z); + } + + function getRoll(direction, up, right) { + var roll = 0.0; + if (!CesiumMath.equalsEpsilon(Math.abs(direction.z), 1.0, CesiumMath.EPSILON3)) { + roll = Math.atan2(-right.z, up.z); + roll = CesiumMath.zeroToTwoPi(roll + CesiumMath.TWO_PI); + } + + return roll; + } + var scratchHPRMatrix1 = new Matrix4(); var scratchHPRMatrix2 = new Matrix4(); @@ -663,19 +688,11 @@ define([ var transform = Transforms.eastNorthUpToFixedFrame(this.positionWC, ellipsoid, scratchHPRMatrix2); this._setTransform(transform); - var direction = this.direction; - var up = this.up; - - var heading; - if (!CesiumMath.equalsEpsilon(Math.abs(direction.z), 1.0, CesiumMath.EPSILON3)) { - heading = Math.atan2(direction.y, direction.x) - CesiumMath.PI_OVER_TWO; - } else { - heading = Math.atan2(up.y, up.x) - CesiumMath.PI_OVER_TWO; - } + var heading = getHeading(this.direction, this.up); this._setTransform(oldTransform); - return CesiumMath.TWO_PI - CesiumMath.zeroToTwoPi(heading); + return heading; } return undefined; @@ -698,7 +715,7 @@ define([ var transform = Transforms.eastNorthUpToFixedFrame(this.positionWC, ellipsoid, scratchHPRMatrix2); this._setTransform(transform); - var pitch = CesiumMath.PI_OVER_TWO - CesiumMath.acosClamped(this.direction.z); + var pitch = getPitch(this.direction); this._setTransform(oldTransform); @@ -725,15 +742,7 @@ define([ var transform = Transforms.eastNorthUpToFixedFrame(this.positionWC, ellipsoid, scratchHPRMatrix2); this._setTransform(transform); - var up = this.up; - var right = this.right; - var direction = this.direction; - - var roll = 0.0; - if (!CesiumMath.equalsEpsilon(Math.abs(direction.z), 1.0, CesiumMath.EPSILON3)) { - roll = Math.atan2(-right.z, up.z); - roll = CesiumMath.zeroToTwoPi(roll + CesiumMath.TWO_PI); - } + var roll = getRoll(this.direction, this.up, this.right); this._setTransform(oldTransform); @@ -2277,14 +2286,21 @@ define([ var scratchFlyToMatrix4 = new Matrix4(); var newOptions = { destination : undefined, - direction : undefined, - up : undefined, + heading : undefined, + pitch : undefined, + roll : undefined, duration : undefined, complete : undefined, cancel : undefined, - endTransform : undefined + endTransform : undefined, + maximumHeight : undefined, + easingFunction : undefined }; + var scratchFlyDirection = new Cartesian3(); + var scratchFlyUp = new Cartesian3(); + var scratchFlyRight = new Cartesian3(); + /** * Flies the camera from its current position to a new position. * @@ -2299,6 +2315,8 @@ define([ * @param {Matrix4} [options.endTransform] Transform matrix representing the reference frame the camera will be in when the flight is completed. * @param {Boolean} [options.convert=true] When true, the destination is converted to the correct coordinate system for each scene mode. When false, the destination is expected * to be in the correct coordinate system. + * @param {Number} [options.maximumHeight] The maximum height at the peak of the flight. + * @param {EasingFunction|EasingFunction~Callback} [options.easingFunction] Controls how the time is interpolated over the duration of the flight. * * @exception {DeveloperError} If either direction or up is given, then both are required. * @@ -2346,42 +2364,52 @@ define([ var isRectangle = defined(destination.west); if (isRectangle) { + if (scene.mode !== SceneMode.SCENE3D && destination.west > destination.east) { + destination = Rectangle.MAX_VALUE; + } destination = scene.camera.getRectangleCameraCoordinates(destination, scratchFlyToDestination); } - var direction; - var up; + var heading; + var pitch; + var roll; var orientation = defaultValue(options.orientation, defaultValue.EMPTY_OBJECT); if (defined(orientation.heading)) { - var heading = defaultValue(orientation.heading, 0.0); - var pitch = defaultValue(orientation.pitch, -CesiumMath.PI_OVER_TWO); - var roll = defaultValue(orientation.roll, 0.0); + heading = orientation.heading; + pitch = orientation.pitch; + roll = orientation.roll; + } else if (defined(orientation.direction)) { + var direction = Cartesian3.clone(orientation.direction, scratchFlyDirection); + var up = Cartesian3.clone(orientation.up, scratchFlyUp); - var rotQuat = Quaternion.fromHeadingPitchRoll(heading - CesiumMath.PI_OVER_TWO, pitch, roll, scratchFlyToQuaternion); - var rotMat = Matrix3.fromQuaternion(rotQuat, scratchFlyToMatrix3); + if (scene.mode === SceneMode.SCENE3D) { + var ellipsoid = this._projection.ellipsoid; + var transform = Transforms.eastNorthUpToFixedFrame(destination, ellipsoid, scratchHPRMatrix1); + var invTransform = Matrix4.inverseTransformation(transform, scratchHPRMatrix2); - direction = Matrix3.getColumn(rotMat, 0, scratchFlyToDirection); - up = Matrix3.getColumn(rotMat, 2, scratchFlyToUp); + Matrix4.multiplyByPointAsVector(invTransform, direction, direction); + Matrix4.multiplyByPointAsVector(invTransform, up, up); + } - var ellipsoid = this._projection.ellipsoid; - var transform = Transforms.eastNorthUpToFixedFrame(destination, ellipsoid, scratchFlyToMatrix4); + var right = Cartesian3.cross(direction, up, scratchFlyRight); - Matrix4.multiplyByPointAsVector(transform, direction, direction); - Matrix4.multiplyByPointAsVector(transform, up, up); - } else if (defined(orientation.direction)) { - direction = orientation.direction; - up = orientation.up; + heading = getHeading(direction, up); + pitch = getPitch(direction); + roll = getRoll(direction, up, right); } newOptions.destination = destination; - newOptions.direction = direction; - newOptions.up = up; + newOptions.heading = heading; + newOptions.pitch = pitch; + newOptions.roll = roll; newOptions.duration = options.duration; newOptions.complete = options.complete; newOptions.cancel = options.cancel; newOptions.endTransform = options.endTransform; newOptions.convert = isRectangle ? false : options.convert; + newOptions.maximumHeight = options.maximumHeight; + newOptions.easingFunction = options.easingFunction; scene.tweens.add(CameraFlightPath.createTween(scene, newOptions)); }; @@ -2469,6 +2497,9 @@ define([ var scratchflyToBoundingSphereDirection = new Cartesian3(); var scratchflyToBoundingSphereUp = new Cartesian3(); var scratchflyToBoundingSphereRight = new Cartesian3(); + var scratchFlyToBoundingSphereCart4 = new Cartesian4(); + var scratchFlyToBoundingSphereQuaternion = new Quaternion(); + var scratchFlyToBoundingSphereMatrix3 = new Matrix3(); /** * Flys the camera to a location where the current view contains the provided bounding sphere. @@ -2489,6 +2520,8 @@ define([ * @param {Camera~FlightCompleteCallback} [options.complete] The function to execute when the flight is complete. * @param {Camera~FlightCancelledCallback} [options.cancel] The function to execute if the flight is cancelled. * @param {Matrix4} [options.endTransform] Transform matrix representing the reference frame the camera will be in when the flight is completed. + * @param {Number} [options.maximumHeight] The maximum height at the peak of the flight. + * @param {EasingFunction|EasingFunction~Callback} [options.easingFunction] Controls how the time is interpolated over the duration of the flight. */ Camera.prototype.flyToBoundingSphere = function(boundingSphere, options) { //>>includeStart('debug', pragmas.debug); @@ -2521,6 +2554,14 @@ define([ Cartesian3.normalize(direction, direction); up = Matrix4.multiplyByPointAsVector(transform, Cartesian3.UNIT_Z, scratchflyToBoundingSphereUp); + if (1.0 - Math.abs(Cartesian3.dot(direction, up)) < CesiumMath.EPSILON6) { + var rotateQuat = Quaternion.fromAxisAngle(direction, offset.heading, scratchFlyToBoundingSphereQuaternion); + var rotation = Matrix3.fromQuaternion(rotateQuat, scratchFlyToBoundingSphereMatrix3); + + Cartesian3.fromCartesian4(Matrix4.getColumn(transform, 1, scratchFlyToBoundingSphereCart4), up); + Matrix3.multiplyByVector(rotation, up, up); + } + var right = Cartesian3.cross(direction, up, scratchflyToBoundingSphereRight); Cartesian3.cross(right, direction, up); Cartesian3.normalize(up, up); @@ -2535,27 +2576,12 @@ define([ duration : options.duration, complete : options.complete, cancel : options.cancel, - endTransform : options.endTransform + endTransform : options.endTransform, + maximumHeight : options.maximumHeight, + easingFunction : options.easingFunction }); }; - /** - * Returns a duplicate of a Camera instance. - * @deprecated - * @returns {Camera} The provided result parameter or a new copy of the Camera instance. - */ - Camera.prototype.clone = function() { - var camera = new Camera(this._scene); - camera.position = Cartesian3.clone(this.position); - camera.direction = Cartesian3.clone(this.direction); - camera.up = Cartesian3.clone(this.up); - camera.right = Cartesian3.clone(this.right); - camera._transform = Matrix4.clone(this.transform); - camera._transformChanged = true; - camera.frustum = this.frustum.clone(); - return camera; - }; - /** * @private */ diff --git a/Source/Scene/CameraFlightPath.js b/Source/Scene/CameraFlightPath.js index 78a0fbcf7c20..25dbec8378f8 100644 --- a/Source/Scene/CameraFlightPath.js +++ b/Source/Scene/CameraFlightPath.js @@ -3,18 +3,11 @@ define([ '../Core/Cartesian2', '../Core/Cartesian3', '../Core/Cartographic', - '../Core/clone', '../Core/defaultValue', '../Core/defined', '../Core/DeveloperError', '../Core/EasingFunction', - '../Core/HermiteSpline', - '../Core/LinearSpline', '../Core/Math', - '../Core/Matrix3', - '../Core/Matrix4', - '../Core/Quaternion', - '../Core/QuaternionSpline', './PerspectiveFrustum', './PerspectiveOffCenterFrustum', './SceneMode' @@ -22,18 +15,11 @@ define([ Cartesian2, Cartesian3, Cartographic, - clone, defaultValue, defined, DeveloperError, EasingFunction, - HermiteSpline, - LinearSpline, CesiumMath, - Matrix3, - Matrix4, - Quaternion, - QuaternionSpline, PerspectiveFrustum, PerspectiveOffCenterFrustum, SceneMode) { @@ -49,28 +35,6 @@ define([ var CameraFlightPath = { }; - var c3destination = new Cartesian3(); - var rotMatrix = new Matrix3(); - var viewMat = new Matrix3(); - - var cqRight = new Cartesian3(); - var cqUp = new Cartesian3(); - function createQuaternion(direction, up, result) { - Cartesian3.cross(direction, up, cqRight); - Cartesian3.cross(cqRight, direction, cqUp); - viewMat[0] = cqRight.x; - viewMat[1] = cqUp.x; - viewMat[2] = -direction.x; - viewMat[3] = cqRight.y; - viewMat[4] = cqUp.y; - viewMat[5] = -direction.y; - viewMat[6] = cqRight.z; - viewMat[7] = cqUp.z; - viewMat[8] = -direction.z; - - return Quaternion.fromRotationMatrix(viewMat, result); - } - function getAltitude(frustum, dx, dy) { var near; var top; @@ -93,290 +57,159 @@ define([ var scratchCart = new Cartesian3(); var scratchCart2 = new Cartesian3(); - var scratchCart3 = new Cartesian3(); - var scratchCart4 = new Cartesian3(); - var rotMatrixScratch = new Matrix3(); - function createPath3D(camera, ellipsoid, start, up, right, end, duration) { - // get minimum altitude from which the whole ellipsoid is visible - var radius = ellipsoid.maximumRadius; - var frustum = camera.frustum; - var maxStartAlt = getAltitude(frustum, radius, radius); - var dot = Cartesian3.dot(Cartesian3.normalize(start, scratchCart), Cartesian3.normalize(end, scratchCart2)); + function createHeightFunction(camera, destination, startHeight, endHeight, optionAltitude) { + var altitude = optionAltitude; + var maxHeight; + + if (!defined(optionAltitude)) { + var start = camera.position; + var end = destination; + var up = camera.up; + var right = camera.right; + var frustum = camera.frustum; - var points; - var altitude; - var incrementPercentage; - if (Cartesian3.magnitude(start) > maxStartAlt) { - altitude = radius + 0.6 * (maxStartAlt - radius); - incrementPercentage = 0.35; - } else { var diff = Cartesian3.subtract(start, end, scratchCart); - altitude = Cartesian3.magnitude(Cartesian3.add(Cartesian3.multiplyByScalar(diff, 0.5, scratchCart2), end, scratchCart2)); var verticalDistance = Cartesian3.magnitude(Cartesian3.multiplyByScalar(up, Cartesian3.dot(diff, up), scratchCart2)); var horizontalDistance = Cartesian3.magnitude(Cartesian3.multiplyByScalar(right, Cartesian3.dot(diff, right), scratchCart2)); - altitude += getAltitude(frustum, verticalDistance, horizontalDistance); - incrementPercentage = CesiumMath.clamp(dot + 1.0, 0.25, 0.5); - } - var aboveEnd = Cartesian3.multiplyByScalar(Cartesian3.normalize(end, scratchCart2), altitude, scratchCart2); - var afterStart = Cartesian3.multiplyByScalar(Cartesian3.normalize(start, scratchCart), altitude, scratchCart); - - var axis, angle, rotation; - var middle = new Cartesian3(); - if (Cartesian3.magnitude(end) > maxStartAlt && dot > 0.75) { - middle = Cartesian3.add(Cartesian3.multiplyByScalar(Cartesian3.subtract(start, end, middle), 0.5, middle), end, middle); - points = [ start, middle, end ]; - } else if (Cartesian3.magnitude(start) > maxStartAlt && dot > 0) { - middle = Cartesian3.add(Cartesian3.multiplyByScalar(Cartesian3.subtract(start, aboveEnd, middle), 0.5, middle), aboveEnd, middle); - points = [ start, middle, end ]; - } else { - points = [ start ]; - - angle = CesiumMath.acosClamped(Cartesian3.dot(Cartesian3.normalize(afterStart, scratchCart3), Cartesian3.normalize(aboveEnd, scratchCart4))); - axis = Cartesian3.cross(aboveEnd, afterStart, scratchCart3); - if (Cartesian3.equalsEpsilon(axis, Cartesian3.ZERO, CesiumMath.EPSILON6)) { - axis = Cartesian3.UNIT_Z; - } + maxHeight = Math.max(startHeight, endHeight); + altitude = Math.min(getAltitude(frustum, verticalDistance, horizontalDistance) * 0.20, 1000000000.0); + } - var increment = incrementPercentage * angle; - var startCondition = angle - increment; - for ( var i = startCondition; i > 0.0; i = i - increment) { - rotation = Matrix3.fromQuaternion(Quaternion.fromAxisAngle(axis, i), rotMatrixScratch); - points.push(Matrix3.multiplyByVector(rotation, aboveEnd, new Cartesian3())); - } + if (defined(optionAltitude) || maxHeight < altitude) { + var power = 8.0; + var factor = 1000000.0; - points.push(end); - } + var s = -Math.pow((altitude - startHeight) * factor, 1.0 / power); + var e = Math.pow((altitude - endHeight) * factor, 1.0 / power); - var times = new Array(points.length); - var scalar = duration / (points.length - 1); - for ( var k = 0; k < points.length; ++k) { - times[k] = k * scalar; + return function(t) { + var x = t * (e - s) + s; + return -Math.pow(x, power) / factor + altitude; + }; } - return HermiteSpline.createNaturalCubic({ - points : points, - times : times - }); + return function(t) { + return CesiumMath.lerp(startHeight, endHeight, t); + }; } - var direction3D = new Cartesian3(); - var right3D = new Cartesian3(); - var up3D = new Cartesian3(); - var quat3D = new Quaternion(); - - function createOrientations3D(path, startDirection, startUp, endDirection, endUp) { - var points = path.points; - var orientations = new Array(points.length); - orientations[0] = createQuaternion(startDirection, startUp); - - var point; - var length = points.length - 1; - for (var i = 1; i < length; ++i) { - point = points[i]; - Cartesian3.normalize(Cartesian3.negate(point, direction3D), direction3D); - Cartesian3.normalize(Cartesian3.cross(direction3D, Cartesian3.UNIT_Z, right3D), right3D); - Cartesian3.cross(right3D, direction3D, up3D); - orientations[i] = createQuaternion(direction3D, up3D, quat3D); + function adjustAngleForLERP(startAngle, endAngle) { + if (CesiumMath.equalsEpsilon(startAngle, CesiumMath.TWO_PI, CesiumMath.EPSILON11)) { + startAngle = 0.0; } - point = points[length]; - if (defined(endDirection) && defined(endUp)) { - orientations[length] = createQuaternion(endDirection, endUp); - } else { - Cartesian3.normalize(Cartesian3.negate(point, direction3D), direction3D); - Cartesian3.normalize(Cartesian3.cross(direction3D, Cartesian3.UNIT_Z, right3D), right3D); - Cartesian3.cross(right3D, direction3D, up3D); - orientations[length] = createQuaternion(direction3D, up3D, quat3D); + if (endAngle > startAngle + Math.PI) { + startAngle += CesiumMath.TWO_PI; + } else if (endAngle < startAngle - Math.PI) { + startAngle -= CesiumMath.TWO_PI; } - return new QuaternionSpline({ - points : orientations, - times : path.times - }); + return startAngle; } - var scratchStartPosition = new Cartesian3(); - var scratchStartDirection = new Cartesian3(); - var scratchStartUp = new Cartesian3(); - var scratchStartRight = new Cartesian3(); - var currentFrame = new Matrix4(); + var scratchStart = new Cartesian3(); - function createUpdate3D(scene, destination, duration, direction, up) { + function createUpdateCV(scene, duration, destination, heading, pitch, roll, optionAltitude) { var camera = scene.camera; - var ellipsoid = scene.mapProjection.ellipsoid; - var start = camera.cameraToWorldCoordinatesPoint(camera.position, scratchStartPosition); - var startDirection = camera.cameraToWorldCoordinatesVector(camera.direction, scratchStartDirection); - var startUp = camera.cameraToWorldCoordinatesVector(camera.up, scratchStartUp); - var startRight = Cartesian3.cross(startDirection, startUp, scratchStartRight); + var start = Cartesian3.clone(camera.position, scratchStart); + var startPitch = camera.pitch; + var startHeading = adjustAngleForLERP(camera.heading, heading); + var startRoll = adjustAngleForLERP(camera.roll, roll); - var path = createPath3D(camera, ellipsoid, start, startUp, startRight, destination, duration); - var orientations = createOrientations3D(path, startDirection, startUp, direction, up); + var heightFunction = createHeightFunction(camera, destination, start.z, destination.z, optionAltitude); var update = function(value) { - var time = value.time; - var orientation = orientations.evaluate(time); - Matrix3.fromQuaternion(orientation, rotMatrix); - - Matrix4.clone(camera.transform, currentFrame); - camera._setTransform(Matrix4.IDENTITY); + var time = value.time / duration; - camera.position = path.evaluate(time, camera.position); - camera.right = Matrix3.getRow(rotMatrix, 0, camera.right); - camera.up = Matrix3.getRow(rotMatrix, 1, camera.up); - camera.direction = Cartesian3.negate(Matrix3.getRow(rotMatrix, 2, camera.direction), camera.direction); + camera.setView({ + heading : CesiumMath.lerp(startHeading, heading, time), + pitch : CesiumMath.lerp(startPitch, pitch, time), + roll : CesiumMath.lerp(startRoll, roll, time) + }); - camera._setTransform(currentFrame); + Cartesian2.lerp(start, destination, time, camera.position); + camera.position.z = heightFunction(time); }; return update; } - var cartScratch1 = new Cartesian3(); - function createPath2D(camera, ellipsoid, start, end, duration) { - if (CesiumMath.equalsEpsilon(Cartesian2.magnitude(start), Cartesian2.magnitude(end), 10000.0)) { - return new LinearSpline({ - points : [start, end], - times : [0.0, duration] - }); - } + var scratchStartCart = new Cartographic(); + var scratchEndCart = new Cartographic(); + var scratchCurrentPositionCart = new Cartographic(); - // get minimum altitude from which the whole map is visible - var radius = ellipsoid.maximumRadius; - var frustum = camera.frustum; - var maxStartAlt = getAltitude(frustum, Math.PI * radius, CesiumMath.PI_OVER_TWO * radius); - - var points; - var altitude; - var incrementPercentage = 0.5; - if (start.z > maxStartAlt) { - altitude = 0.6 * maxStartAlt; - } else { - var diff = Cartesian3.subtract(start, end, cartScratch1); - altitude = getAltitude(frustum, Math.abs(diff.y), Math.abs(diff.x)); - } + function createUpdate3D(scene, duration, destination, heading, pitch, roll, optionAltitude) { + var camera = scene.camera; + var projection = scene.mapProjection; + var ellipsoid = projection.ellipsoid; - var aboveEnd = Cartesian3.clone(end); - aboveEnd.z = altitude; - var afterStart = Cartesian3.clone(start); - afterStart.z = altitude; - - var middle = new Cartesian3(); - if (end.z > maxStartAlt) { - middle = Cartesian3.add(Cartesian3.multiplyByScalar(Cartesian3.subtract(start, end, middle), 0.5, middle), end, middle); - points = [ start, middle, end ]; - } else if (start.z > maxStartAlt) { - middle = Cartesian3.add(Cartesian3.multiplyByScalar(Cartesian3.subtract(start, aboveEnd, middle), 0.5, middle), aboveEnd, middle); - points = [ start, middle, end ]; - } else { - points = [ start ]; - - var v = Cartesian3.subtract(afterStart, aboveEnd, cartScratch1); - var distance = Cartesian3.magnitude(v); - Cartesian3.normalize(v, v); - - var increment = incrementPercentage * distance; - var startCondition = distance - increment; - for ( var i = startCondition; i > 0.0; i = i - increment) { - var p = new Cartesian3(); - points.push(Cartesian3.add(Cartesian3.multiplyByScalar(v, i, p), aboveEnd, p)); - } + var startCart = Cartographic.clone(camera.positionCartographic, scratchStartCart); + var startPitch = camera.pitch; + var startHeading = adjustAngleForLERP(camera.heading, heading); + var startRoll = adjustAngleForLERP(camera.roll, roll); - points.push(end); + var destCart = ellipsoid.cartesianToCartographic(destination, scratchEndCart); + if (destCart.height <= 0.0) { + destCart.height = startCart.height; } - var times = new Array(points.length); - var scalar = duration / (points.length - 1); - for ( var k = 0; k < points.length; ++k) { - times[k] = k * scalar; - } + startCart.longitude = CesiumMath.zeroToTwoPi(startCart.longitude); + destCart.longitude = CesiumMath.zeroToTwoPi(destCart.longitude); - return HermiteSpline.createNaturalCubic({ - points : points, - times : times - }); - } - - var direction2D = Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()); - var right2D = new Cartesian3(); - right2D = Cartesian3.normalize(Cartesian3.cross(direction2D, Cartesian3.UNIT_Y, right2D), right2D); - var up2D = Cartesian3.cross(right2D, direction2D, new Cartesian3()); - var quat = createQuaternion(direction2D, up2D); - - function createOrientations2D(camera, path, endDirection, endUp) { - var points = path.points; - var orientations = new Array(points.length); - orientations[0] = createQuaternion(camera.direction, camera.up); - - var length = points.length - 1; - for (var i = 1; i < length; ++i) { - orientations[i] = quat; - } - - if (defined(endDirection) && defined(endUp)) { - orientations[length] = createQuaternion(endDirection, endUp); - } else { - orientations[length] = quat; + var diff = startCart.longitude - destCart.longitude; + if (diff < -CesiumMath.PI) { + startCart.longitude += CesiumMath.TWO_PI; + } else if (diff > CesiumMath.PI) { + destCart.longitude += CesiumMath.TWO_PI; } - return new QuaternionSpline({ - points : orientations, - times : path.times - }); - } - - function createUpdateCV(scene, destination, duration, direction, up) { - var camera = scene.camera; - var ellipsoid = scene.mapProjection.ellipsoid; - - var path = createPath2D(camera, ellipsoid, Cartesian3.clone(camera.position), destination, duration); - var orientations = createOrientations2D(camera, path, direction, up); + var heightFunction = createHeightFunction(camera, destination, startCart.height, destCart.height, optionAltitude); var update = function(value) { - var time = value.time; - var orientation = orientations.evaluate(time); - Matrix3.fromQuaternion(orientation, rotMatrix); - - Matrix4.clone(camera.transform, currentFrame); - camera._setTransform(Matrix4.IDENTITY); - - camera.position = path.evaluate(time, camera.position); - camera.right = Matrix3.getRow(rotMatrix, 0, camera.right); - camera.up = Matrix3.getRow(rotMatrix, 1, camera.up); - camera.direction = Cartesian3.negate(Matrix3.getRow(rotMatrix, 2, camera.direction), camera.direction); - - camera._setTransform(currentFrame); + var time = value.time / duration; + + var position = scratchCurrentPositionCart; + position.longitude = CesiumMath.lerp(startCart.longitude, destCart.longitude, time); + position.latitude = CesiumMath.lerp(startCart.latitude, destCart.latitude, time); + position.height = heightFunction(time); + + camera.setView({ + positionCartographic : position, + heading : CesiumMath.lerp(startHeading, heading, time), + pitch : CesiumMath.lerp(startPitch, pitch, time), + roll : CesiumMath.lerp(startRoll, roll, time) + }); }; return update; } - function createUpdate2D(scene, destination, duration, direction, up) { + function createUpdate2D(scene, duration, destination, heading, pitch, roll, optionAltitude) { var camera = scene.camera; - var ellipsoid = scene.mapProjection.ellipsoid; - - var start = Cartesian3.clone(camera.position); - start.z = camera.frustum.right - camera.frustum.left; - var path = createPath2D(camera, ellipsoid, start, destination, duration); - var orientations = createOrientations2D(camera, path, Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), up); + var start = Cartesian3.clone(camera.position, scratchStart); + var startPitch = camera.pitch; + var startHeading = adjustAngleForLERP(camera.heading, heading); + var startRoll = adjustAngleForLERP(camera.roll, roll); - var height = camera.position.z; + var startHeight = camera.frustum.right - camera.frustum.left; + var heightFunction = createHeightFunction(camera, destination, startHeight, destination.z, optionAltitude); var update = function(value) { - var time = value.time; - var orientation = orientations.evaluate(time); - Matrix3.fromQuaternion(orientation, rotMatrix); + var time = value.time / duration; - camera.position = path.evaluate(time); - var zoom = camera.position.z; - camera.position.z = height; + camera.setView({ + heading : CesiumMath.lerp(startHeading, heading, time), + pitch : CesiumMath.lerp(startPitch, pitch, time), + roll : CesiumMath.lerp(startRoll, roll, time) + }); + + Cartesian2.lerp(start, destination, time, camera.position); - camera.right = Matrix3.getRow(rotMatrix, 0, camera.right); - camera.up = Matrix3.getRow(rotMatrix, 1, camera.up); - camera.direction = Cartesian3.negate(Matrix3.getRow(rotMatrix, 2, camera.direction), camera.direction); + var zoom = heightFunction(time); var frustum = camera.frustum; var ratio = frustum.top / frustum.right; @@ -397,11 +230,30 @@ define([ var scratchCartographic = new Cartographic(); var scratchDestination = new Cartesian3(); + function emptyFlight(complete, cancel) { + return { + startObject : {}, + stopObject : {}, + duration : 0.0, + complete : complete, + cancel : cancel + }; + } + + function wrapCallback(controller, cb) { + var wrapped = function() { + if (typeof cb === 'function') { + cb(); + } + + controller.enableInputs = true; + }; + return wrapped; + } + CameraFlightPath.createTween = function(scene, options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); var destination = options.destination; - var direction = options.direction; - var up = options.up; //>>includeStart('debug', pragmas.debug); if (!defined(scene)) { @@ -410,136 +262,93 @@ define([ if (!defined(destination)) { throw new DeveloperError('destination is required.'); } - if ((defined(direction) && !defined(up)) || (defined(up) && !defined(direction))) { - throw new DeveloperError('If either direction or up is given, then both are required.'); - } //>>includeEnd('debug'); + var projection = scene.mapProjection; + var ellipsoid = projection.ellipsoid; + + var maximumHeight = options.maximumHeight; + var easingFunction = options.easingFunction; + if (scene.mode === SceneMode.MORPHING) { - return { - startObject : {}, - stopObject: {}, - duration : 0.0 - }; + return emptyFlight(); } var convert = defaultValue(options.convert, true); if (convert && scene.mode !== SceneMode.SCENE3D) { - var projection = scene.mapProjection; - var ellipsoid = projection.ellipsoid; ellipsoid.cartesianToCartographic(destination, scratchCartographic); destination = projection.project(scratchCartographic, scratchDestination); } - var duration = defaultValue(options.duration, 3.0); - var controller = scene.screenSpaceCameraController; - controller.enableInputs = false; - - var wrapCallback = function(cb) { - var wrapped = function() { - if (typeof cb === 'function') { - cb(); - } - - controller.enableInputs = true; - }; - return wrapped; - }; - var complete = wrapCallback(options.complete); - var cancel = wrapCallback(options.cancel); - var camera = scene.camera; var transform = options.endTransform; if (defined(transform)) { camera._setTransform(transform); } - var frustum = camera.frustum; - if (scene.mode === SceneMode.SCENE2D) { - if (Cartesian2.equalsEpsilon(camera.position, destination, CesiumMath.EPSILON6) && (CesiumMath.equalsEpsilon(Math.max(frustum.right - frustum.left, frustum.top - frustum.bottom), destination.z, CesiumMath.EPSILON6))) { - return { - startObject : {}, - stopObject: {}, - duration : 0.0, - complete : complete, - cancel: cancel - }; - } - } else if (Cartesian3.equalsEpsilon(destination, camera.position, CesiumMath.EPSILON6)) { - return { - startObject : {}, - stopObject: {}, - duration : 0.0, - complete : complete, - cancel: cancel - }; + var duration = options.duration; + if (!defined(duration)) { + duration = Math.ceil(Cartesian3.distance(camera.position, destination) / 1000000.0) + 2.0; + duration = Math.min(duration, 3.0); } - if (duration <= 0.0) { - var newOnComplete = function() { - var position = destination; - if (scene.mode === SceneMode.SCENE3D) { - if (!defined(options.direction) && !defined(options.up)){ - dirScratch = Cartesian3.normalize(Cartesian3.negate(position, dirScratch), dirScratch); - rightScratch = Cartesian3.normalize(Cartesian3.cross(dirScratch, Cartesian3.UNIT_Z, rightScratch), rightScratch); - } else { - dirScratch = options.direction; - rightScratch = Cartesian3.normalize(Cartesian3.cross(dirScratch, options.up, rightScratch), rightScratch); - } - upScratch = defaultValue(options.up, Cartesian3.cross(rightScratch, dirScratch, upScratch)); - } else { - if (!defined(options.direction) && !defined(options.up)){ - dirScratch = Cartesian3.negate(Cartesian3.UNIT_Z, dirScratch); - rightScratch = Cartesian3.normalize(Cartesian3.cross(dirScratch, Cartesian3.UNIT_Y, rightScratch), rightScratch); - } else { - dirScratch = options.direction; - rightScratch = Cartesian3.normalize(Cartesian3.cross(dirScratch, options.up, rightScratch), rightScratch); - } - upScratch = defaultValue(options.up, Cartesian3.cross(rightScratch, dirScratch, upScratch)); - } + var mode = scene.mode; + var heading = defaultValue(options.heading, 0.0); + var pitch = scene.mode !== SceneMode.SCENE2D ? defaultValue(options.pitch, -CesiumMath.PI_OVER_TWO) : -CesiumMath.PI_OVER_TWO; + var roll = defaultValue(options.roll, 0.0); + + var controller = scene.screenSpaceCameraController; + controller.enableInputs = false; - Cartesian3.clone(position, camera.position); - Cartesian3.clone(dirScratch, camera.direction); - Cartesian3.clone(upScratch, camera.up); - Cartesian3.clone(rightScratch, camera.right); + var complete = wrapCallback(controller, options.complete); + var cancel = wrapCallback(controller, options.cancel); - if (scene.mode === SceneMode.SCENE2D) { - var zoom = camera.position.z; - var ratio = frustum.top / frustum.right; + var frustum = camera.frustum; - var incrementAmount = (zoom - (frustum.right - frustum.left)) * 0.5; - frustum.right += incrementAmount; - frustum.left -= incrementAmount; - frustum.top = ratio * frustum.right; - frustum.bottom = -frustum.top; - } + var empty = scene.mode === SceneMode.SCENE2D; + empty = empty && Cartesian2.equalsEpsilon(camera.position, destination, CesiumMath.EPSILON6); + empty = empty && CesiumMath.equalsEpsilon(Math.max(frustum.right - frustum.left, frustum.top - frustum.bottom), destination.z, CesiumMath.EPSILON6); + + empty = empty || (scene.mode !== SceneMode.SCENE2D && Cartesian3.equalsEpsilon(destination, camera.position, CesiumMath.EPSILON6)); + + if (empty) { + return emptyFlight(complete, cancel); + } + + var updateFunctions = new Array(4); + updateFunctions[SceneMode.SCENE2D] = createUpdate2D; + updateFunctions[SceneMode.SCENE3D] = createUpdate3D; + updateFunctions[SceneMode.COLUMBUS_VIEW] = createUpdateCV; + + if (duration <= 0.0) { + var newOnComplete = function() { + var update = updateFunctions[mode](scene, 1.0, destination, heading, pitch, roll, maximumHeight); + update({ time: 1.0 }); if (typeof complete === 'function') { complete(); } }; - return { - startObject : {}, - stopObject: {}, - duration : 0.0, - complete : newOnComplete, - cancel: cancel - }; + return emptyFlight(newOnComplete, cancel); } - var update; - if (scene.mode === SceneMode.SCENE3D) { - update = createUpdate3D(scene, destination, duration, direction, up); - } else if (scene.mode === SceneMode.SCENE2D) { - update = createUpdate2D(scene, destination, duration, direction, up); - } else { - update = createUpdateCV(scene, destination, duration, direction, up); + var update = updateFunctions[mode](scene, duration, destination, heading, pitch, roll, maximumHeight); + + if (!defined(easingFunction)) { + var startHeight = camera.positionCartographic.height; + var endHeight = mode === SceneMode.SCENE3D ? ellipsoid.cartesianToCartographic(destination).height : destination.z; + + if (startHeight > endHeight && startHeight > 11500.0) { + easingFunction = EasingFunction.CUBIC_OUT; + } else { + easingFunction = EasingFunction.QUINTIC_IN_OUT; + } } return { duration : duration, - easingFunction : EasingFunction.SINUSOIDAL_IN_OUT, + easingFunction : easingFunction, startObject : { time : 0.0 }, diff --git a/Source/Widgets/Geocoder/GeocoderViewModel.js b/Source/Widgets/Geocoder/GeocoderViewModel.js index fe46522240e0..5a5e56a38a24 100644 --- a/Source/Widgets/Geocoder/GeocoderViewModel.js +++ b/Source/Widgets/Geocoder/GeocoderViewModel.js @@ -44,7 +44,7 @@ define([ * written to the console reminding you that you must create and supply a Bing Maps * key as soon as possible. Please do not deploy an application that uses * this widget without creating a separate key for your application. - * @param {Number} [options.flightDuration=1.5] The duration of the camera flight to an entered location, in seconds. + * @param {Number} [options.flightDuration] The duration of the camera flight to an entered location, in seconds. */ var GeocoderViewModel = function(options) { //>>includeStart('debug', pragmas.debug); @@ -60,7 +60,7 @@ define([ this._key = BingMapsApi.getKey(options.key); this._scene = options.scene; - this._flightDuration = defaultValue(options.flightDuration, 1.5); + this._flightDuration = options.flightDuration; this._searchText = ''; this._isSearchInProgress = false; this._geocodeInProgress = undefined; @@ -117,9 +117,10 @@ define([ /** * Gets or sets the the duration of the camera flight in seconds. * A value of zero causes the camera to instantly switch to the geocoding location. + * The duration will be computed based on the distance when undefined. * - * @type {Number} - * @default 1.5 + * @type {Number|undefined} + * @default undefined */ this.flightDuration = undefined; knockout.defineProperty(this, 'flightDuration', { @@ -128,7 +129,7 @@ define([ }, set : function(value) { //>>includeStart('debug', pragmas.debug); - if (value < 0) { + if (defined(value) && value < 0) { throw new DeveloperError('value must be positive.'); } //>>includeEnd('debug'); diff --git a/Source/Widgets/HomeButton/HomeButtonViewModel.js b/Source/Widgets/HomeButton/HomeButtonViewModel.js index c60964f28a66..657df1065c35 100644 --- a/Source/Widgets/HomeButton/HomeButtonViewModel.js +++ b/Source/Widgets/HomeButton/HomeButtonViewModel.js @@ -32,10 +32,6 @@ define([ scene.completeMorph(); } - var direction; - var right; - var up; - if (mode === SceneMode.SCENE2D) { scene.camera.flyTo({ destination : Rectangle.MAX_VALUE, @@ -50,16 +46,12 @@ define([ Cartesian3.normalize(destination, destination); Cartesian3.multiplyByScalar(destination, mag, destination); - direction = Cartesian3.normalize(destination, new Cartesian3()); - Cartesian3.negate(direction, direction); - right = Cartesian3.cross(direction, Cartesian3.UNIT_Z, new Cartesian3()); - up = Cartesian3.cross(right, direction, new Cartesian3()); - scene.camera.flyTo({ destination : destination, orientation : { - direction: direction, - up : up + heading : 0.0, + pitch : -Math.PI * 0.5, + roll : 0.0 }, duration : duration, endTransform : Matrix4.IDENTITY @@ -68,17 +60,15 @@ define([ var maxRadii = scene.globe.ellipsoid.maximumRadius; var position = new Cartesian3(0.0, -1.0, 1.0); position = Cartesian3.multiplyByScalar(Cartesian3.normalize(position, position), 5.0 * maxRadii, position); - direction = new Cartesian3(); - direction = Cartesian3.normalize(Cartesian3.subtract(Cartesian3.ZERO, position, direction), direction); - right = Cartesian3.cross(direction, Cartesian3.UNIT_Z, new Cartesian3()); - up = Cartesian3.cross(right, direction, new Cartesian3()); + var pitch = -Math.acos(Cartesian3.normalize(position, new Cartesian3()).z); scene.camera.flyTo({ destination : position, duration : duration, orientation : { - direction : direction, - up : up + heading : 0.0, + pitch : pitch, + roll : 0.0 }, endTransform : Matrix4.IDENTITY, convert : false @@ -92,7 +82,7 @@ define([ * @constructor * * @param {Scene} scene The scene instance to use. - * @param {Number} [duration=1.5] The duration of the camera flight in seconds. + * @param {Number} [duration] The duration of the camera flight in seconds. */ var HomeButtonViewModel = function(scene, duration) { //>>includeStart('debug', pragmas.debug); @@ -101,8 +91,6 @@ define([ } //>>includeEnd('debug'); - duration = defaultValue(duration, 1.5); - this._scene = scene; this._duration = duration; @@ -149,9 +137,10 @@ define([ /** * Gets or sets the the duration of the camera flight in seconds. * A value of zero causes the camera to instantly switch to home view. + * The duration will be computed based on the distance when undefined. * @memberof HomeButtonViewModel.prototype * - * @type {Number} + * @type {Number|undefined} */ duration : { get : function() { @@ -159,7 +148,7 @@ define([ }, set : function(value) { //>>includeStart('debug', pragmas.debug); - if (value < 0) { + if (defined(value) && value < 0) { throw new DeveloperError('value must be positive.'); } //>>includeEnd('debug'); diff --git a/Specs/Scene/CameraFlightPathSpec.js b/Specs/Scene/CameraFlightPathSpec.js index 90d7544c9616..75b14818707d 100644 --- a/Specs/Scene/CameraFlightPathSpec.js +++ b/Specs/Scene/CameraFlightPathSpec.js @@ -59,24 +59,6 @@ defineSuite([ }).toThrowDeveloperError(); }); - it('create animation throws with just up and no direction', function() { - expect(function() { - CameraFlightPath.createTween(scene, { - destination : Cartesian3.ZERO, - up : Cartesian3.UNIT_Z - }); - }).toThrowDeveloperError(); - }); - - it('create animation throws with just direction and no up', function() { - expect(function() { - CameraFlightPath.createTween(scene, { - destination : Cartesian3.ZERO, - direction : Cartesian3.UNIT_X - }); - }).toThrowDeveloperError(); - }); - it('creates an animation', function() { var destination = new Cartesian3(1e9, 1e9, 1e9); var duration = 5.0; @@ -105,30 +87,35 @@ defineSuite([ var camera = scene.camera; var startPosition = Cartesian3.clone(camera.position); - var startDirection = Cartesian3.clone(camera.direction); - var startUp = Cartesian3.clone(camera.up); + var startHeading = camera.heading; + var startPitch = camera.pitch; + var startRoll = camera.roll; var endPosition = Cartesian3.negate(startPosition, new Cartesian3()); - var endDirection = Cartesian3.negate(startDirection, new Cartesian3()); - var endUp = Cartesian3.negate(startUp, new Cartesian3()); + var endHeading = CesiumMath.toRadians(20.0); + var endPitch = CesiumMath.toRadians(-45.0); + var endRoll = CesiumMath.TWO_PI; var duration = 5.0; var flight = CameraFlightPath.createTween(scene, { destination : endPosition, - direction : endDirection, - up : endUp, + heading : endHeading, + pitch : endPitch, + roll : endRoll, duration : duration }); flight.update({ time : 0.0 }); expect(camera.position).toEqualEpsilon(startPosition, CesiumMath.EPSILON12); - expect(camera.direction).toEqualEpsilon(startDirection, CesiumMath.EPSILON12); - expect(camera.up).toEqualEpsilon(startUp, CesiumMath.EPSILON12); + expect(camera.heading).toEqualEpsilon(startHeading, CesiumMath.EPSILON12); + expect(camera.pitch).toEqualEpsilon(startPitch, CesiumMath.EPSILON12); + expect(camera.roll).toEqualEpsilon(startRoll, CesiumMath.EPSILON12); flight.update({ time : duration }); expect(camera.position).toEqualEpsilon(endPosition, CesiumMath.EPSILON12); - expect(camera.direction).toEqualEpsilon(endDirection, CesiumMath.EPSILON12); - expect(camera.up).toEqualEpsilon(endUp, CesiumMath.EPSILON12); + expect(camera.heading).toEqualEpsilon(endHeading, CesiumMath.EPSILON12); + expect(camera.pitch).toEqualEpsilon(endPitch, CesiumMath.EPSILON12); + expect(camera.roll).toEqualEpsilon(endRoll, CesiumMath.EPSILON12); }); it('creates an animation in Columbus view', function() { @@ -141,32 +128,22 @@ defineSuite([ camera.right = Cartesian3.cross(camera.direction, camera.up, new Cartesian3()); var startPosition = Cartesian3.clone(camera.position); - var startDirection = Cartesian3.clone(camera.direction); - var startUp = Cartesian3.clone(camera.up); var projection = scene.mapProjection; - var destination = Cartesian3.add(startPosition, new Cartesian3(-6e6 * Math.PI, 6e6 * CesiumMath.PI_OVER_FOUR, 100.0), new Cartesian3()); + var destination = Cartesian3.add(startPosition, new Cartesian3(-6e5 * Math.PI, 6e5 * CesiumMath.PI_OVER_FOUR, 100.0), new Cartesian3()); var endPosition = projection.ellipsoid.cartographicToCartesian(projection.unproject(destination)); - var endDirection = Cartesian3.clone(startDirection); - var endUp = Cartesian3.negate(startUp, new Cartesian3()); var duration = 5.0; var flight = CameraFlightPath.createTween(scene, { destination : endPosition, - direction : endDirection, - up : endUp, duration : duration }); flight.update({ time : 0.0 }); expect(camera.position).toEqualEpsilon(startPosition, CesiumMath.EPSILON12); - expect(camera.direction).toEqualEpsilon(startDirection, CesiumMath.EPSILON12); - expect(camera.up).toEqualEpsilon(startUp, CesiumMath.EPSILON12); flight.update({ time : duration }); expect(camera.position).toEqualEpsilon(destination, CesiumMath.EPSILON4); - expect(camera.direction).toEqualEpsilon(endDirection, CesiumMath.EPSILON12); - expect(camera.up).toEqualEpsilon(endUp, CesiumMath.EPSILON12); }); it('creates an animation in 2D', function() { @@ -181,36 +158,26 @@ defineSuite([ var startHeight = camera.frustum.right - camera.frustum.left; var startPosition = Cartesian3.clone(camera.position); - var startDirection = Cartesian3.clone(camera.direction); - var startUp = Cartesian3.clone(camera.up); var projection = scene.mapProjection; var destination = Cartesian3.add(startPosition, new Cartesian3(-6e6 * Math.PI, 6e6 * CesiumMath.PI_OVER_FOUR, 100.0), new Cartesian3()); var endPosition = projection.ellipsoid.cartographicToCartesian(projection.unproject(destination)); - var endDirection = Cartesian3.clone(startDirection); - var endUp = Cartesian3.negate(startUp, new Cartesian3()); var duration = 5.0; var flight = CameraFlightPath.createTween(scene, { destination : endPosition, - direction : endDirection, - up : endUp, duration : duration }); flight.update({ time : 0.0 }); expect(camera.position).toEqualEpsilon(startPosition, CesiumMath.EPSILON12); - expect(camera.direction).toEqualEpsilon(startDirection, CesiumMath.EPSILON12); - expect(camera.up).toEqualEpsilon(startUp, CesiumMath.EPSILON12); - expect(camera.frustum.right - camera.frustum.left).toEqual(startHeight); + expect(camera.frustum.right - camera.frustum.left).toEqualEpsilon(startHeight, CesiumMath.EPSILON7); flight.update({ time : duration }); - expect(camera.position.x).toEqualEpsilon(destination.x, CesiumMath.EPSILON8); - expect(camera.position.y).toEqualEpsilon(destination.y, CesiumMath.EPSILON8); - expect(camera.position.z).toEqualEpsilon(startPosition.z, CesiumMath.EPSILON8); - expect(camera.direction).toEqualEpsilon(endDirection, CesiumMath.EPSILON8); - expect(camera.up).toEqualEpsilon(endUp, CesiumMath.EPSILON8); - expect(camera.frustum.right - camera.frustum.left).toEqualEpsilon(destination.z, CesiumMath.EPSILON8); + expect(camera.position.x).toEqualEpsilon(destination.x, CesiumMath.EPSILON7); + expect(camera.position.y).toEqualEpsilon(destination.y, CesiumMath.EPSILON7); + expect(camera.position.z).toEqualEpsilon(startPosition.z, CesiumMath.EPSILON7); + expect(camera.frustum.right - camera.frustum.left).toEqualEpsilon(destination.z, CesiumMath.EPSILON7); }); it('creates a path where the start and end points only differ in height', function() { @@ -275,7 +242,7 @@ defineSuite([ expect(flight.update).toBeUndefined(); expect(scene.camera.position).not.toEqual(destination); flight.complete(); - expect(scene.camera.position).toEqual(destination); + expect(scene.camera.position).toEqualEpsilon(destination, CesiumMath.EPSILON14); }); it('duration is 0 when destination is the same as camera position in 2D', function() { @@ -347,30 +314,25 @@ defineSuite([ camera.right = Cartesian3.cross(camera.direction, camera.up, new Cartesian3()); camera.frustum = createOrthographicFrustum(); + camera.update(scene.mode); + + var startHeight = camera.frustum.right - camera.frustum.left; var startPosition = Cartesian3.clone(camera.position); - var startDirection = Cartesian3.clone(camera.direction); - var startUp = Cartesian3.clone(camera.up); var projection = scene.mapProjection; - var destination = Cartesian3.add(startPosition, new Cartesian3(-6e6 * Math.PI, 6e6 * CesiumMath.PI_OVER_FOUR, 100.0), new Cartesian3()); + var destination = Cartesian3.add(startPosition, new Cartesian3(-6e5 * Math.PI, 6e5 * CesiumMath.PI_OVER_FOUR, 100.0), new Cartesian3()); var endPosition = projection.ellipsoid.cartographicToCartesian(projection.unproject(destination)); - var endDirection = Cartesian3.clone(startDirection); - var endUp = Cartesian3.negate(startUp, new Cartesian3()); var flight = CameraFlightPath.createTween(scene, { destination : endPosition, - direction : endDirection, - up : endUp, duration : 0.0 }); expect(typeof flight.complete).toEqual('function'); flight.complete(); - expect(camera.position.x).toEqualEpsilon(destination.x, CesiumMath.EPSILON8); - expect(camera.position.y).toEqualEpsilon(destination.y, CesiumMath.EPSILON8); - expect(camera.direction).toEqualEpsilon(endDirection, CesiumMath.EPSILON8); - expect(camera.up).toEqualEpsilon(endUp, CesiumMath.EPSILON8); - expect(camera.frustum.right - camera.frustum.left).toEqualEpsilon(destination.z, CesiumMath.EPSILON8); + expect(camera.position.x).toEqualEpsilon(destination.x, CesiumMath.EPSILON7); + expect(camera.position.y).toEqualEpsilon(destination.y, CesiumMath.EPSILON7); + expect(camera.frustum.right - camera.frustum.left).toEqualEpsilon(destination.z, CesiumMath.EPSILON7); }); it('creates an animation in Columbus view 0 duration', function() { @@ -402,25 +364,16 @@ defineSuite([ var camera = scene.camera; var startPosition = Cartesian3.clone(camera.position); - var startDirection = Cartesian3.clone(camera.direction); - var startUp = Cartesian3.clone(camera.up); - var endPosition = Cartesian3.negate(startPosition, new Cartesian3()); - var endDirection = Cartesian3.negate(startDirection, new Cartesian3()); - var endUp = Cartesian3.negate(startUp, new Cartesian3()); var flight = CameraFlightPath.createTween(scene, { destination : endPosition, - direction : endDirection, - up : endUp, duration : 0.0 }); expect(typeof flight.complete).toEqual('function'); flight.complete(); expect(camera.position).toEqualEpsilon(endPosition, CesiumMath.EPSILON12); - expect(camera.direction).toEqualEpsilon(endDirection, CesiumMath.EPSILON12); - expect(camera.up).toEqualEpsilon(endUp, CesiumMath.EPSILON12); }); }); diff --git a/Specs/Scene/CameraSpec.js b/Specs/Scene/CameraSpec.js index 79a3beec4f59..dc55b83e03fc 100644 --- a/Specs/Scene/CameraSpec.js +++ b/Specs/Scene/CameraSpec.js @@ -1031,7 +1031,7 @@ defineSuite([ var target = Cartesian3.fromDegrees(0.0, 0.0); var offset = new Cartesian3(0.0, -1.0, 0.0); - var tempCamera = camera.clone(); + var tempCamera = Camera.clone(camera); tempCamera.lookAt(target, offset); expect(tempCamera.position).toEqualEpsilon(offset, CesiumMath.EPSILON11); @@ -1050,7 +1050,7 @@ defineSuite([ var pitch = CesiumMath.toRadians(-45.0); var range = 2.0; - var tempCamera = camera.clone(); + var tempCamera = Camera.clone(camera); tempCamera.lookAt(target, new HeadingPitchRange(heading, pitch, range)); tempCamera.lookAtTransform(Matrix4.IDENTITY); @@ -1085,7 +1085,7 @@ defineSuite([ frustum.top = 1.0; frustum.bottom = -1.0; - var tempCamera = camera.clone(); + var tempCamera = Camera.clone(camera); tempCamera.frustum = frustum; tempCamera.update(SceneMode.SCENE2D); @@ -1110,7 +1110,7 @@ defineSuite([ frustum.top = 1.0; frustum.bottom = -1.0; - var tempCamera = camera.clone(); + var tempCamera = Camera.clone(camera); tempCamera.frustum = frustum; tempCamera.update(SceneMode.SCENE2D); @@ -1143,7 +1143,7 @@ defineSuite([ var offset = new Cartesian3(1.0, 1.0, 0.0); var transform = Transforms.eastNorthUpToFixedFrame(target, Ellipsoid.UNIT_SPHERE); - var tempCamera = camera.clone(); + var tempCamera = Camera.clone(camera); tempCamera.lookAtTransform(transform, offset); expect(tempCamera.position).toEqualEpsilon(offset, CesiumMath.EPSILON11); @@ -1185,7 +1185,7 @@ defineSuite([ var range = 2.0; var transform = Transforms.eastNorthUpToFixedFrame(target); - var tempCamera = camera.clone(); + var tempCamera = Camera.clone(camera); tempCamera.lookAtTransform(transform, new HeadingPitchRange(heading, pitch, range)); tempCamera.lookAtTransform(Matrix4.IDENTITY); @@ -1214,7 +1214,7 @@ defineSuite([ frustum.top = 1.0; frustum.bottom = -1.0; - var tempCamera = camera.clone(); + var tempCamera = Camera.clone(camera); tempCamera.frustum = frustum; tempCamera.update(SceneMode.SCENE2D); @@ -1239,7 +1239,7 @@ defineSuite([ frustum.top = 1.0; frustum.bottom = -1.0; - var tempCamera = camera.clone(); + var tempCamera = Camera.clone(camera); tempCamera.frustum = frustum; tempCamera.update(SceneMode.SCENE2D); @@ -1959,13 +1959,16 @@ defineSuite([ var expectedOptions = { destination : options.destination, - direction : undefined, - up : undefined, + heading : undefined, + pitch : undefined, + roll : undefined, duration : undefined, complete : undefined, cancel : undefined, endTransform : undefined, - convert : undefined + convert : undefined, + maximumHeight : undefined, + easingFunction : undefined }; expect(CameraFlightPath.createTween).toHaveBeenCalledWith(scene, expectedOptions); diff --git a/Specs/Scene/SceneTransformsSpec.js b/Specs/Scene/SceneTransformsSpec.js index 1c19dd9cc26c..5e707bb792e7 100644 --- a/Specs/Scene/SceneTransformsSpec.js +++ b/Specs/Scene/SceneTransformsSpec.js @@ -5,6 +5,7 @@ defineSuite([ 'Core/Cartesian3', 'Core/Ellipsoid', 'Core/Math', + 'Scene/Camera', 'Specs/createScene' ], function( SceneTransforms, @@ -12,6 +13,7 @@ defineSuite([ Cartesian3, Ellipsoid, CesiumMath, + Camera, createScene) { "use strict"; /*global jasmine,describe,xdescribe,it,xit,expect,beforeEach,afterEach,beforeAll,afterAll,spyOn*/ @@ -21,7 +23,7 @@ defineSuite([ beforeAll(function() { scene = createScene(); - defaultCamera = scene.camera.clone(); + defaultCamera = Camera.clone(scene.camera); }); afterAll(function() {