diff --git a/Apps/Sandcastle/gallery/3D Models.html b/Apps/Sandcastle/gallery/3D Models.html index c57013b94b47..923029316eaf 100644 --- a/Apps/Sandcastle/gallery/3D Models.html +++ b/Apps/Sandcastle/gallery/3D Models.html @@ -56,8 +56,6 @@ camera.transform = transform; camera.constrainedAxis = Cesium.Cartesian3.UNIT_Y; var controller = scene.screenSpaceCameraController; - controller.ellipsoid = Cesium.Ellipsoid.UNIT_SPHERE; - controller.enableTilt = false; var r = 1.25 * Math.max(model.boundingSphere.radius, camera.frustum.near); controller.minimumZoomDistance = r * 0.25; camera.lookAt(new Cesium.Cartesian3(r, r, r), Cesium.Cartesian3.ZERO, Cesium.Cartesian3.UNIT_Y); diff --git a/Apps/Sandcastle/gallery/Camera.html b/Apps/Sandcastle/gallery/Camera.html index 70682eea837b..1a1e47cd4dc5 100644 --- a/Apps/Sandcastle/gallery/Camera.html +++ b/Apps/Sandcastle/gallery/Camera.html @@ -35,10 +35,6 @@ scene.primitives.removeAll(); scene.tweens.removeAll(); - var controller = scene.screenSpaceCameraController; - controller.ellipsoid = scene.globe.ellipsoid; - controller.enableTilt = true; - scene.camera.setTransform(Cesium.Matrix4.IDENTITY); clock.multiplier = 1.0; @@ -135,10 +131,6 @@ Cesium.Matrix4.clone(transform, camera.transform); camera.constrainedAxis = Cesium.Cartesian3.UNIT_Z; - var controller = scene.screenSpaceCameraController; - controller.ellipsoid = Cesium.Ellipsoid.UNIT_SPHERE; - controller.enableTilt = false; - // Zoom in camera.lookAt( new Cesium.Cartesian3(-120000.0, -120000.0, 120000.0), diff --git a/CHANGES.md b/CHANGES.md index 02babdfbc2df..9af6e98271d9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -75,6 +75,7 @@ Change Log * `Rectangle.getCenter` -> `Rectangle.center` * `CullingVolume.getVisibility` -> `CullingVolume.computeVisibility` * `SimplePolylineGeometry` and `PolylineGeometry` positions curve to follow the ellipsoid surface by default. To disable this behavior, set the option `followSurface=false`. + * Removed `ScreenSpaceCameraController.ellipsoid`. The behavior that depended on the ellipsoid is now determined based on the scene state. * Sandcastle examples now automatically wrap the example code in RequireJS boilerplate. To upgrade any custom examples, copy the code into an existing example (such as Hello World) and save a new file. * Replaced `PerspectiveFrustum.fovy` with `PerspectiveFrustum.fov` which will change the field of view angle in either the x or y direction depending on the aspect ratio. * Added northUpEast transform to help support display of glTF models because Y is their up axis. @@ -86,6 +87,10 @@ Change Log * Added `Primitive.ready`. * Prevent primitives from flashing off and on when modifying static DataSources. * Added `scene3DOnly` options to `Viewer`, `CesiumWidget`, and `Scene` constructors. This setting optimizes memory usage and performance for 3D mode at the cost of losing the ability to use 2D or Columbus View. +* Added the following methods to `IntersectionTests`: `rayTriangle`, `lineSegmentTriangle`, `raySphere`, and `lineSegmentSphere`. +* Added `Globe.getHeight` and `Globe.pick` for finding the terrain height at a given Cartographic coordinate and picking the terrain with a ray. +* Modified the default camera tilt mouse behavior to tilt about the point clicked. +* Added camera collision detection with terrain to the default mouse interaction. * Matrix types now have `add` and `subtract` functions. * `Matrix3` type now has a `fromCrossProduct` function. diff --git a/Source/Core/Ellipsoid.js b/Source/Core/Ellipsoid.js index 8bf41519a6d2..af2621665333 100644 --- a/Source/Core/Ellipsoid.js +++ b/Source/Core/Ellipsoid.js @@ -19,27 +19,7 @@ define([ CesiumMath) { "use strict"; - /** - * A quadratic surface defined in Cartesian coordinates by the equation - * (x / a)^2 + (y / b)^2 + (z / c)^2 = 1. Primarily used - * by Cesium to represent the shape of planetary bodies. - * - * Rather than constructing this object directly, one of the provided - * constants is normally used. - * @alias Ellipsoid - * @constructor - * - * @param {Number} [x=0] The radius in the x direction. - * @param {Number} [y=0] The radius in the y direction. - * @param {Number} [z=0] The radius in the z direction. - * - * @exception {DeveloperError} All radii components must be greater than or equal to zero. - * - * @see Ellipsoid.fromCartesian3 - * @see Ellipsoid.WGS84 - * @see Ellipsoid.UNIT_SPHERE - */ - var Ellipsoid = function(x, y, z) { + function initialize(ellipsoid, x, y, z) { x = defaultValue(x, 0.0); y = defaultValue(y, 0.0); z = defaultValue(z, 0.0); @@ -50,29 +30,62 @@ define([ } //>>includeEnd('debug'); - this._radii = new Cartesian3(x, y, z); + ellipsoid._radii = new Cartesian3(x, y, z); - this._radiiSquared = new Cartesian3(x * x, + ellipsoid._radiiSquared = new Cartesian3(x * x, y * y, z * z); - this._radiiToTheFourth = new Cartesian3(x * x * x * x, + ellipsoid._radiiToTheFourth = new Cartesian3(x * x * x * x, y * y * y * y, z * z * z * z); - this._oneOverRadii = new Cartesian3(x === 0.0 ? 0.0 : 1.0 / x, + ellipsoid._oneOverRadii = new Cartesian3(x === 0.0 ? 0.0 : 1.0 / x, y === 0.0 ? 0.0 : 1.0 / y, z === 0.0 ? 0.0 : 1.0 / z); - this._oneOverRadiiSquared = new Cartesian3(x === 0.0 ? 0.0 : 1.0 / (x * x), + ellipsoid._oneOverRadiiSquared = new Cartesian3(x === 0.0 ? 0.0 : 1.0 / (x * x), y === 0.0 ? 0.0 : 1.0 / (y * y), z === 0.0 ? 0.0 : 1.0 / (z * z)); - this._minimumRadius = Math.min(x, y, z); + ellipsoid._minimumRadius = Math.min(x, y, z); - this._maximumRadius = Math.max(x, y, z); + ellipsoid._maximumRadius = Math.max(x, y, z); - this._centerToleranceSquared = CesiumMath.EPSILON1; + ellipsoid._centerToleranceSquared = CesiumMath.EPSILON1; + } + + /** + * A quadratic surface defined in Cartesian coordinates by the equation + * (x / a)^2 + (y / b)^2 + (z / c)^2 = 1. Primarily used + * by Cesium to represent the shape of planetary bodies. + * + * Rather than constructing this object directly, one of the provided + * constants is normally used. + * @alias Ellipsoid + * @constructor + * + * @param {Number} [x=0] The radius in the x direction. + * @param {Number} [y=0] The radius in the y direction. + * @param {Number} [z=0] The radius in the z direction. + * + * @exception {DeveloperError} All radii components must be greater than or equal to zero. + * + * @see Ellipsoid.fromCartesian3 + * @see Ellipsoid.WGS84 + * @see Ellipsoid.UNIT_SPHERE + */ + var Ellipsoid = function(x, y, z) { + this._radii = undefined; + this._radiiSquared = undefined; + this._radiiToTheFourth = undefined; + this._oneOverRadii = undefined; + this._oneOverRadiiSquared = undefined; + this._minimumRadius = undefined; + this._maximumRadius = undefined; + this._centerToleranceSquared = undefined; + + initialize(this, x, y, z); }; defineProperties(Ellipsoid.prototype, { @@ -189,11 +202,17 @@ define([ * @see Ellipsoid.WGS84 * @see Ellipsoid.UNIT_SPHERE */ - Ellipsoid.fromCartesian3 = function(cartesian) { + Ellipsoid.fromCartesian3 = function(cartesian, result) { + if (!defined(result)) { + result = new Ellipsoid(); + } + if (!defined(cartesian)) { - return new Ellipsoid(); + return result; } - return new Ellipsoid(cartesian.x, cartesian.y, cartesian.z); + + initialize(result, cartesian.x, cartesian.y, cartesian.z); + return result; }; /** diff --git a/Source/Core/IntersectionTests.js b/Source/Core/IntersectionTests.js index 21d4941a3798..fbf4bb761f26 100644 --- a/Source/Core/IntersectionTests.js +++ b/Source/Core/IntersectionTests.js @@ -2,21 +2,25 @@ define([ './Cartesian3', './Cartographic', + './defaultValue', './defined', './DeveloperError', './Math', './Matrix3', './QuadraticRealPolynomial', - './QuarticRealPolynomial' + './QuarticRealPolynomial', + './Ray' ], function( Cartesian3, Cartographic, + defaultValue, defined, DeveloperError, CesiumMath, Matrix3, QuadraticRealPolynomial, - QuarticRealPolynomial) { + QuarticRealPolynomial, + Ray) { "use strict"; /** @@ -69,6 +73,293 @@ define([ return Cartesian3.add(origin, result, result); }; + var scratchEdge0 = new Cartesian3(); + var scratchEdge1 = new Cartesian3(); + var scratchPVec = new Cartesian3(); + var scratchTVec = new Cartesian3(); + var scratchQVec = new Cartesian3(); + + function rayTriangle(ray, p0, p1, p2, cullBackFaces) { + //>>includeStart('debug', pragmas.debug); + if (!defined(ray)) { + throw new DeveloperError('ray is required.'); + } + if (!defined(p0)) { + throw new DeveloperError('p0 is required.'); + } + if (!defined(p1)) { + throw new DeveloperError('p1 is required.'); + } + if (!defined(p2)) { + throw new DeveloperError('p2 is required.'); + } + //>>includeEnd('debug'); + + cullBackFaces = defaultValue(cullBackFaces, false); + + var origin = ray.origin; + var direction = ray.direction; + + var edge0 = Cartesian3.subtract(p1, p0, scratchEdge0); + var edge1 = Cartesian3.subtract(p2, p0, scratchEdge1); + + var p = Cartesian3.cross(direction, edge1, scratchPVec); + var det = Cartesian3.dot(edge0, p); + + var tvec; + var q; + + var u; + var v; + var t; + + if (cullBackFaces) { + if (det < CesiumMath.EPSILON6) { + return undefined; + } + + tvec = Cartesian3.subtract(origin, p0, scratchTVec); + u = Cartesian3.dot(tvec, p); + if (u < 0.0 || u > det) { + return undefined; + } + + q = Cartesian3.cross(tvec, edge0, scratchQVec); + + v = Cartesian3.dot(direction, q); + if (v < 0.0 || u + v > det) { + return undefined; + } + + t = Cartesian3.dot(edge1, q) / det; + } else { + if (Math.abs(det) < CesiumMath.EPSILON6) { + return undefined; + } + var invDet = 1.0 / det; + + tvec = Cartesian3.subtract(origin, p0, scratchTVec); + u = Cartesian3.dot(tvec, p) * invDet; + if (u < 0.0 || u > 1.0) { + return undefined; + } + + q = Cartesian3.cross(tvec, edge0, scratchQVec); + + v = Cartesian3.dot(direction, q) * invDet; + if (v < 0.0 || u + v > 1.0) { + return undefined; + } + + t = Cartesian3.dot(edge1, q) * invDet; + } + + return t; + } + + /** + * Computes the intersection of a ray and a triangle. + * @memberof IntersectionTests + * + * @param {Ray} ray The ray. + * @param {Cartesian3} p0 The first vertex of the triangle. + * @param {Cartesian3} p1 The second vertex of the triangle. + * @param {Cartesian3} p2 The third vertex of the triangle. + * @param {Boolean} [cullBackFaces=false] If true, will only compute an intersection with the front face of the triangle + * and return undefined for intersections with the back face. + * @param {Cartesian3} [result] The Cartesian3 onto which to store the result. + * @returns {Cartesian3} The intersection point or undefined if there is no intersections. + */ + IntersectionTests.rayTriangle = function(ray, p0, p1, p2, cullBackFaces, result) { + var t = rayTriangle(ray, p0, p1, p2, cullBackFaces); + if (!defined(t) || t < 0.0) { + return undefined; + } + + if (!defined(result)) { + result = new Cartesian3(); + } + + Cartesian3.multiplyByScalar(ray.direction, t, result); + return Cartesian3.add(ray.origin, result, result); + }; + + var scratchLineSegmentTriangleRay = new Ray(); + + /** + * Computes the intersection of a line segment and a triangle. + * @memberof IntersectionTests + * + * @param {Cartesian3} v0 The an end point of the line segment. + * @param {Cartesian3} v1 The other end point of the line segment. + * @param {Cartesian3} p0 The first vertex of the triangle. + * @param {Cartesian3} p1 The second vertex of the triangle. + * @param {Cartesian3} p2 The third vertex of the triangle. + * @param {Boolean} [cullBackFaces=false] If true, will only compute an intersection with the front face of the triangle + * and return undefined for intersections with the back face. + * @param {Cartesian3} [result] The Cartesian3 onto which to store the result. + * @returns {Cartesian3} The intersection point or undefined if there is no intersections. + */ + IntersectionTests.lineSegmentTriangle = function(v0, v1, p0, p1, p2, cullBackFaces, result) { + //>>includeStart('debug', pragmas.debug); + if (!defined(v0)) { + throw new DeveloperError('v0 is required.'); + } + if (!defined(v1)) { + throw new DeveloperError('v1 is required.'); + } + //>>includeEnd('debug'); + + var ray = scratchLineSegmentTriangleRay; + Cartesian3.clone(v0, ray.origin); + Cartesian3.subtract(v1, v0, ray.direction); + Cartesian3.normalize(ray.direction, ray.direction); + + var t = rayTriangle(ray, p0, p1, p2, cullBackFaces); + if (!defined(t) || t < 0.0 || t > Cartesian3.distance(v0, v1)) { + return undefined; + } + + if (!defined(result)) { + result = new Cartesian3(); + } + + Cartesian3.multiplyByScalar(ray.direction, t, result); + return Cartesian3.add(ray.origin, result, result); + }; + + function solveQuadratic(a, b, c, result) { + var det = b * b - 4.0 * a * c; + if (det < 0.0) { + return undefined; + } else if (det > 0.0) { + var denom = 1.0 / (2.0 * a); + var disc = Math.sqrt(det); + var root0 = (-b + disc) * denom; + var root1 = (-b - disc) * denom; + + if (root0 < root1) { + result.root0 = root0; + result.root1 = root1; + } else { + result.root0 = root1; + result.root1 = root0; + } + + return result; + } + + var root = -b / (2.0 * a); + if (root === 0.0) { + return undefined; + } + + result.root0 = result.root1 = root; + return result; + } + + var raySphereRoots = { + root0 : 0.0, + root1 : 0.0 + }; + + function raySphere(ray, sphere, result) { + if (!defined(result)) { + result = {}; + } + + var origin = ray.origin; + var direction = ray.direction; + + var center = sphere.center; + var radiusSquared = sphere.radius * sphere.radius; + + var diff = Cartesian3.subtract(origin, center, scratchPVec); + + var a = Cartesian3.dot(direction, direction); + var b = 2.0 * Cartesian3.dot(direction, diff); + var c = Cartesian3.magnitudeSquared(diff) - radiusSquared; + + var roots = solveQuadratic(a, b, c, raySphereRoots); + if (!defined(roots)) { + return undefined; + } + + result.start = roots.root0; + result.stop = roots.root1; + return result; + } + + /** + * Computes the intersection points of a ray with a sphere. + * @memberof IntersectionTests + * + * @param {Ray} ray The ray. + * @param {BoundingSphere} sphere The sphere. + * @param {Object} [result] The result onto which to store the result. + * @returns {Object} An object with the first (start) and the second (stop) intersection scalars for points along the ray or undefined if there are no intersections. + */ + IntersectionTests.raySphere = function(ray, sphere, result) { + //>>includeStart('debug', pragmas.debug); + if (!defined(ray)) { + throw new DeveloperError('ray is required.'); + } + if (!defined(sphere)) { + throw new DeveloperError('sphere is required.'); + } + //>>includeEnd('debug'); + + result = raySphere(ray, sphere, result); + if (!defined(result) || result.stop < 0.0) { + return undefined; + } + + result.start = Math.max(result.start, 0.0); + return result; + }; + + var scratchLineSegmentRay = new Ray(); + + /** + * Computes the intersection points of a line segment with a sphere. + * @memberof IntersectionTests + * + * @param {Cartesian3} p0 An end point of the line segment. + * @param {Cartesian3} p1 The other end point of the line segment. + * @param {BoundingSphere} sphere The sphere. + * @param {Object} [result] The result onto which to store the result. + * @returns {Object} An object with the first (start) and the second (stop) intersection scalars for points along the line segment or undefined if there are no intersections. + */ + IntersectionTests.lineSegmentSphere = function(p0, p1, sphere, result) { + //>>includeStart('debug', pragmas.debug); + if (!defined(p0)) { + throw new DeveloperError('p0 is required.'); + } + if (!defined(p1)) { + throw new DeveloperError('p1 is required.'); + } + if (!defined(sphere)) { + throw new DeveloperError('sphere is required.'); + } + //>>includeEnd('debug'); + + var ray = scratchLineSegmentRay; + var origin = Cartesian3.clone(p0, ray.origin); + var direction = Cartesian3.subtract(p1, p0, ray.direction); + + var maxT = Cartesian3.magnitude(direction); + Cartesian3.normalize(direction, direction); + + result = raySphere(ray, sphere, result); + if (!defined(result) || result.stop < 0.0 || result.start > maxT) { + return undefined; + } + + result.start = Math.max(result.start, 0.0); + result.stop = Math.min(result.stop, maxT); + return result; + }; + var scratchQ = new Cartesian3(); var scratchW = new Cartesian3(); diff --git a/Source/DataSources/EntityView.js b/Source/DataSources/EntityView.js index 2a6b15c51fc4..c0ce5ef17b2b 100644 --- a/Source/DataSources/EntityView.js +++ b/Source/DataSources/EntityView.js @@ -144,8 +144,6 @@ define([ // Stationary or slow-moving, low-altitude objects use East-North-Up. Transforms.eastNorthUpToFixedFrame(cartesian, ellipsoid, camera.transform); } - - that._screenSpaceCameraController.ellipsoid = Ellipsoid.UNIT_SPHERE; } if (updateLookAt) { @@ -235,8 +233,6 @@ define([ } //>>includeEnd('debug'); - this._screenSpaceCameraController = scene.screenSpaceCameraController; - var positionProperty = entity.position; var objectChanged = entity !== this._lastEntity; var sceneModeChanged = scene.mode !== this._mode && scene.mode !== SceneMode.MORPHING; diff --git a/Source/Scene/Camera.js b/Source/Scene/Camera.js index 84614b53fe1b..05fe885b79e0 100644 --- a/Source/Scene/Camera.js +++ b/Source/Scene/Camera.js @@ -1143,23 +1143,6 @@ define([ this.look(this.direction, -amount); }; - var appendTransformMatrix = new Matrix4(); - - function appendTransform(camera, transform) { - var oldTransform; - if (defined(transform)) { - oldTransform = Matrix4.clone(camera.transform, appendTransformMatrix); - camera.setTransform(transform); - } - return oldTransform; - } - - function revertTransform(camera, transform) { - if (defined(transform)) { - camera.setTransform(transform); - } - } - var rotateScratchQuaternion = new Quaternion(); var rotateScratchMatrix = new Matrix3(); /** @@ -1168,20 +1151,13 @@ define([ * * @param {Cartesian3} axis The axis to rotate around given in world coordinates. * @param {Number} [angle] The angle, in radians, to rotate by. Defaults to defaultRotateAmount. - * @param {Matrix4} [transform] A transform to append to the camera transform before the rotation. Does not alter the camera's transform. * * @see Camera#rotateUp * @see Camera#rotateDown * @see Camera#rotateLeft * @see Camera#rotateRight - * - * @example - * // Rotate about a point on the earth. - * var center = ellipsoid.cartographicToCartesian(cartographic); - * var transform = Cesium.Matrix4.fromTranslation(center); - * camera.rotate(axis, angle, transform); */ - Camera.prototype.rotate = function(axis, angle, transform) { + Camera.prototype.rotate = function(axis, angle) { //>>includeStart('debug', pragmas.debug); if (!defined(axis)) { throw new DeveloperError('axis is required.'); @@ -1191,50 +1167,44 @@ define([ var turnAngle = defaultValue(angle, this.defaultRotateAmount); var quaternion = Quaternion.fromAxisAngle(axis, -turnAngle, rotateScratchQuaternion); var rotation = Matrix3.fromQuaternion(quaternion, rotateScratchMatrix); - var oldTransform = appendTransform(this, transform); Matrix3.multiplyByVector(rotation, this.position, this.position); Matrix3.multiplyByVector(rotation, this.direction, this.direction); Matrix3.multiplyByVector(rotation, this.up, this.up); Cartesian3.cross(this.direction, this.up, this.right); Cartesian3.cross(this.right, this.direction, this.up); - revertTransform(this, oldTransform); }; /** * Rotates the camera around the center of the camera's reference frame by angle downwards. * * @param {Number} [angle] The angle, in radians, to rotate by. Defaults to defaultRotateAmount. - * @param {Matrix4} [transform] A transform to append to the camera transform before the rotation. Does not alter the camera's transform. * * @see Camera#rotateUp * @see Camera#rotate */ - Camera.prototype.rotateDown = function(angle, transform) { + Camera.prototype.rotateDown = function(angle) { angle = defaultValue(angle, this.defaultRotateAmount); - rotateVertical(this, angle, transform); + rotateVertical(this, angle); }; /** * Rotates the camera around the center of the camera's reference frame by angle upwards. * * @param {Number} [angle] The angle, in radians, to rotate by. Defaults to defaultRotateAmount. - * @param {Matrix4} [transform] A transform to append to the camera transform before the rotation. Does not alter the camera's transform. * * @see Camera#rotateDown * @see Camera#rotate */ - Camera.prototype.rotateUp = function(angle, transform) { + Camera.prototype.rotateUp = function(angle) { angle = defaultValue(angle, this.defaultRotateAmount); - rotateVertical(this, -angle, transform); + rotateVertical(this, -angle); }; var rotateVertScratchP = new Cartesian3(); var rotateVertScratchA = new Cartesian3(); var rotateVertScratchTan = new Cartesian3(); var rotateVertScratchNegate = new Cartesian3(); - function rotateVertical(camera, angle, transform) { - var oldTransform = appendTransform(camera, transform); - + function rotateVertical(camera, angle) { var position = camera.position; var p = Cartesian3.normalize(position, rotateVertScratchP); if (defined(camera.constrainedAxis)) { @@ -1263,43 +1233,39 @@ define([ } else { camera.rotate(camera.right, angle); } - - revertTransform(camera, oldTransform); } /** * Rotates the camera around the center of the camera's reference frame by angle to the right. * * @param {Number} [angle] The angle, in radians, to rotate by. Defaults to defaultRotateAmount. - * @param {Matrix4} [transform] A transform to append to the camera transform before the rotation. Does not alter the camera's transform. * * @see Camera#rotateLeft * @see Camera#rotate */ - Camera.prototype.rotateRight = function(angle, transform) { + Camera.prototype.rotateRight = function(angle) { angle = defaultValue(angle, this.defaultRotateAmount); - rotateHorizontal(this, -angle, transform); + rotateHorizontal(this, -angle); }; /** * Rotates the camera around the center of the camera's reference frame by angle to the left. * * @param {Number} [angle] The angle, in radians, to rotate by. Defaults to defaultRotateAmount. - * @param {Matrix4} [transform] A transform to append to the camera transform before the rotation. Does not alter the camera's transform. * * @see Camera#rotateRight * @see Camera#rotate */ - Camera.prototype.rotateLeft = function(angle, transform) { + Camera.prototype.rotateLeft = function(angle) { angle = defaultValue(angle, this.defaultRotateAmount); - rotateHorizontal(this, angle, transform); + rotateHorizontal(this, angle); }; - function rotateHorizontal(camera, angle, transform) { + function rotateHorizontal(camera, angle) { if (defined(camera.constrainedAxis)) { - camera.rotate(camera.constrainedAxis, angle, transform); + camera.rotate(camera.constrainedAxis, angle); } else { - camera.rotate(camera.up, angle, transform); + camera.rotate(camera.up, angle); } } @@ -1743,7 +1709,8 @@ define([ return undefined; } - return Ray.getPoint(ray, intersection.start, result); + var t = (Cartesian3.magnitude(ray.origin) < ellipsoid.maximumRadius) ? intersection.stop : intersection.start; + return Ray.getPoint(ray, t, result); } var pickEllipsoid2DRay = new Ray(); diff --git a/Source/Scene/CameraEventAggregator.js b/Source/Scene/CameraEventAggregator.js index b308599c6a93..63c4c01abe81 100644 --- a/Source/Scene/CameraEventAggregator.js +++ b/Source/Scene/CameraEventAggregator.js @@ -2,6 +2,7 @@ define([ '../Core/Cartesian2', '../Core/defined', + '../Core/defineProperties', '../Core/destroyObject', '../Core/DeveloperError', '../Core/KeyboardEventModifier', @@ -12,6 +13,7 @@ define([ ], function( Cartesian2, defined, + defineProperties, destroyObject, DeveloperError, KeyboardEventModifier, @@ -42,11 +44,13 @@ define([ var update = aggregator._update; var isDown = aggregator._isDown; + var eventStartPosition = aggregator._eventStartPosition; var pressTime = aggregator._pressTime; var releaseTime = aggregator._releaseTime; update[key] = true; isDown[key] = false; + eventStartPosition[key] = new Cartesian2(); var movement = aggregator._movement[key]; if (!defined(movement)) { @@ -63,10 +67,11 @@ define([ }; movement.prevAngle = 0.0; - aggregator._eventHandler.setInputAction(function() { + aggregator._eventHandler.setInputAction(function(event) { aggregator._buttonsDown++; isDown[key] = true; pressTime[key] = new Date(); + Cartesian2.clone(event.position, eventStartPosition[key]); }, ScreenSpaceEventType.PINCH_START, modifier); aggregator._eventHandler.setInputAction(function() { @@ -134,10 +139,12 @@ define([ var key = getKey(type, modifier); var isDown = aggregator._isDown; + var eventStartPosition = aggregator._eventStartPosition; var pressTime = aggregator._pressTime; var releaseTime = aggregator._releaseTime; isDown[key] = false; + eventStartPosition[key] = new Cartesian2(); var lastMovement = aggregator._lastMovement[key]; if (!defined(lastMovement)) { @@ -161,11 +168,12 @@ define([ up = ScreenSpaceEventType.MIDDLE_UP; } - aggregator._eventHandler.setInputAction(function() { + aggregator._eventHandler.setInputAction(function(event) { aggregator._buttonsDown++; lastMovement.valid = false; isDown[key] = true; pressTime[key] = new Date(); + Cartesian2.clone(event.position, eventStartPosition[key]); }, down, modifier); aggregator._eventHandler.setInputAction(function() { @@ -230,6 +238,8 @@ define([ } } } + + Cartesian2.clone(mouseMovement.endPosition, aggregator._currentMousePosition); }, ScreenSpaceEventType.MOUSE_MOVE, modifier); } @@ -258,11 +268,14 @@ define([ this._movement = {}; this._lastMovement = {}; this._isDown = {}; + this._eventStartPosition = {}; this._pressTime = {}; this._releaseTime = {}; this._buttonsDown = 0; + this._currentMousePosition = new Cartesian2(); + listenToWheel(this, undefined); listenToPinch(this, undefined, canvas); listenMouseButtonDownUp(this, undefined, CameraEventType.LEFT_DRAG); @@ -285,6 +298,34 @@ define([ } }; + defineProperties(CameraEventAggregator.prototype, { + /** + * Gets the current mouse position. + * @memberof CameraEventAggregator.prototype + * @type {Cartesian2} + */ + currentMousePosition : { + get : function() { + return this._currentMousePosition; + } + }, + + /** + * Gets whether any mouse button is down, a touch has started, or the wheel has been moved. + * @memberof CameraEventAggregator.prototype + * @type {Boolean} + */ + anyButtonDown : { + get : function() { + var wheelMoved = !this._update[getKey(CameraEventType.WHEEL)] || + !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.SHIFT)] || + !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.CTRL)] || + !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.ALT)]; + return this._buttonsDown > 0 || wheelMoved; + } + } + }); + /** * Gets if a mouse button down or touch has started and has been moved. * @@ -364,16 +405,25 @@ define([ }; /** - * Gets whether any mouse button is down, a touch has started, or the wheel has been moved. + * Gets the mouse position that started the aggregation. * - * @returns {Boolean} Whether any mouse button is down, a touch has started, or the wheel has been moved. + * @param {CameraEventType} type The camera event type. + * @param {KeyboardEventModifier} [modifier] The keyboard modifier. + * @returns {Cartesian2} The mouse position. */ - CameraEventAggregator.prototype.anyButtonDown = function() { - var wheelMoved = !this._update[getKey(CameraEventType.WHEEL)] || - !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.SHIFT)] || - !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.CTRL)] || - !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.ALT)]; - return this._buttonsDown > 0 || wheelMoved; + CameraEventAggregator.prototype.getStartMousePosition = function(type, modifier) { + //>>includeStart('debug', pragmas.debug); + if (!defined(type)) { + throw new DeveloperError('type is required.'); + } + //>>includeEnd('debug'); + + if (type === CameraEventType.WHEEL) { + return this._currentMousePosition; + } + + var key = getKey(type, modifier); + return this._eventStartPosition[key]; }; /** @@ -459,4 +509,4 @@ define([ }; return CameraEventAggregator; -}); \ No newline at end of file +}); diff --git a/Source/Scene/Globe.js b/Source/Scene/Globe.js index 8e6587571b7b..eb6b7c54b032 100644 --- a/Source/Scene/Globe.js +++ b/Source/Scene/Globe.js @@ -11,6 +11,7 @@ define([ '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', + '../Core/DeveloperError', '../Core/destroyObject', '../Core/Ellipsoid', '../Core/EllipsoidTerrainProvider', @@ -19,11 +20,13 @@ define([ '../Core/Geometry', '../Core/GeometryAttribute', '../Core/Intersect', + '../Core/IntersectionTests', '../Core/loadImage', '../Core/Math', '../Core/Matrix4', '../Core/Occluder', '../Core/PrimitiveType', + '../Core/Ray', '../Core/Rectangle', '../Core/TerrainProvider', '../Core/Transforms', @@ -58,6 +61,7 @@ define([ defaultValue, defined, defineProperties, + DeveloperError, destroyObject, Ellipsoid, EllipsoidTerrainProvider, @@ -66,11 +70,13 @@ define([ Geometry, GeometryAttribute, Intersect, + IntersectionTests, loadImage, CesiumMath, Matrix4, Occluder, PrimitiveType, + Ray, Rectangle, TerrainProvider, Transforms, @@ -300,6 +306,165 @@ define([ } }); + function createComparePickTileFunction(rayOrigin) { + return function(a, b) { + var aDist = BoundingSphere.distanceSquaredTo(a.pickBoundingSphere, rayOrigin); + var bDist = BoundingSphere.distanceSquaredTo(b.pickBoundingSphere, rayOrigin); + + return aDist - bDist; + }; + } + + var scratchArray = []; + var scratchSphereIntersectionResult = { + start : 0.0, + stop : 0.0 + }; + + /** + * Find an intersection between a ray and the globe surface that was rendered. The ray must be given in world coordinates. + * + * @param {Ray} ray The ray to test for intersection. + * @param {Scene} scene The scene. + * @param {Cartesian3} [result] The object onto which to store the result. + * @returns {Cartesian3|undefined} The intersection or undefined if none was found. + * + * @example + * // find intersection of ray through a pixel and the globe + * var ray = scene.camera.getPickRay(windowCoordinates); + * var intersection = globe.pick(ray, scene); + */ + Globe.prototype.pick = function(ray, scene, result) { + //>>includeStart('debug', pragmas.debug); + if (!defined(ray)) { + throw new DeveloperError('ray is required'); + } + if (!defined(scene)) { + throw new DeveloperError('scene is required'); + } + //>>includeEnd('debug'); + + var mode = scene.mode; + var projection = scene.mapProjection; + + var sphereIntersections = scratchArray; + sphereIntersections.length = 0; + + var tilesToRender = this._surface._tilesToRender; + var length = tilesToRender.length; + + var tile; + var i; + + for (i = 0; i < length; ++i) { + tile = tilesToRender[i]; + var tileData = tile.data; + + if (!defined(tileData)) { + continue; + } + + var boundingVolume = tileData.pickBoundingSphere; + if (mode !== SceneMode.SCENE3D) { + BoundingSphere.fromRectangleWithHeights2D(tile.rectangle, projection, tileData.minimumHeight, tileData.maximumHeight, boundingVolume); + Cartesian3.fromElements(boundingVolume.center.z, boundingVolume.center.x, boundingVolume.center.y, boundingVolume.center); + } else { + BoundingSphere.clone(tileData.boundingSphere3D, boundingVolume); + } + + var boundingSphereIntersection = IntersectionTests.raySphere(ray, boundingVolume, scratchSphereIntersectionResult); + if (defined(boundingSphereIntersection)) { + sphereIntersections.push(tileData); + } + } + + sphereIntersections.sort(createComparePickTileFunction(ray.origin)); + + var intersection; + length = sphereIntersections.length; + for (i = 0; i < length; ++i) { + intersection = sphereIntersections[i].pick(ray, scene, true, result); + if (defined(intersection)) { + break; + } + } + + return intersection; + }; + + var scratchGetHeightCartesian = new Cartesian3(); + var scratchGetHeightIntersection = new Cartesian3(); + var scratchGetHeightCartographic = new Cartographic(); + var scratchGetHeightRay = new Ray(); + + /** + * Get the height of the surface at a given cartographic. + * + * @param {Cartographic} cartographic The cartographic for which to find the height. + * @returns {Number|undefined} The height of the cartographic or undefined if it could not be found. + */ + Globe.prototype.getHeight = function(cartographic) { + //>>includeStart('debug', pragmas.debug); + if (!defined(cartographic)) { + throw new DeveloperError('cartographic is required'); + } + //>>includeEnd('debug'); + + var levelZeroTiles = this._surface._levelZeroTiles; + if (!defined(levelZeroTiles)) { + return; + } + + var tile; + var i; + + var length = levelZeroTiles.length; + for (i = 0; i < length; ++i) { + tile = levelZeroTiles[i]; + if (Rectangle.contains(tile.rectangle, cartographic)) { + break; + } + } + + if (!defined(tile) || !Rectangle.contains(tile.rectangle, cartographic)) { + return undefined; + } + + //while(tile.state === QuadtreeTileLoadState.DONE) { + while (tile.renderable) { + var children = tile.children; + length = children.length; + + for (i = 0; i < length; ++i) { + tile = children[i]; + if (Rectangle.contains(tile.rectangle, cartographic)) { + break; + } + } + } + + while (defined(tile) && (!defined(tile.data) || !defined(tile.data.pickTerrain))) { + tile = tile.parent; + } + + if (!defined(tile)) { + return undefined; + } + + var ellipsoid = this._surface._tileProvider.tilingScheme.ellipsoid; + var cartesian = ellipsoid.cartographicToCartesian(cartographic, scratchGetHeightCartesian); + + var ray = scratchGetHeightRay; + Cartesian3.normalize(cartesian, ray.direction); + + var intersection = tile.data.pick(ray, undefined, false, scratchGetHeightIntersection); + if (!defined(intersection)) { + return undefined; + } + + return ellipsoid.cartesianToCartographic(intersection, scratchGetHeightCartographic).height; + }; + var depthQuadScratch = FeatureDetection.supportsTypedArrays() ? new Float32Array(12) : []; var scratchCartesian1 = new Cartesian3(); var scratchCartesian2 = new Cartesian3(); diff --git a/Source/Scene/GlobeSurfaceTile.js b/Source/Scene/GlobeSurfaceTile.js index 6d4c60b5337d..f088eb0c2088 100644 --- a/Source/Scene/GlobeSurfaceTile.js +++ b/Source/Scene/GlobeSurfaceTile.js @@ -4,9 +4,11 @@ define([ '../Core/Cartesian3', '../Core/Cartesian4', '../Core/Cartographic', + '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', '../Core/DeveloperError', + '../Core/IntersectionTests', '../Core/PixelFormat', '../Core/Rectangle', '../Renderer/PixelDatatype', @@ -15,6 +17,7 @@ define([ '../Renderer/TextureWrap', './ImageryState', './QuadtreeTileLoadState', + './SceneMode', './TerrainState', './TileTerrain' ], function( @@ -22,9 +25,11 @@ define([ Cartesian3, Cartesian4, Cartographic, + defaultValue, defined, defineProperties, DeveloperError, + IntersectionTests, PixelFormat, Rectangle, PixelDatatype, @@ -33,6 +38,7 @@ define([ TextureWrap, ImageryState, QuadtreeTileLoadState, + SceneMode, TerrainState, TileTerrain) { "use strict"; @@ -124,6 +130,9 @@ define([ this.loadedTerrain = undefined; this.upsampledTerrain = undefined; + + this.pickBoundingSphere = new BoundingSphere(); + this.pickTerrain = undefined; }; defineProperties(GlobeSurfaceTile.prototype, { @@ -161,6 +170,60 @@ define([ } }); + function getPosition(tile, scene, vertices, index, result) { + Cartesian3.unpack(vertices, index * 6, result); + Cartesian3.add(tile.center, result, result); + + if (defined(scene) && scene.mode !== SceneMode.SCENE3D) { + var projection = scene.mapProjection; + var ellipsoid = projection.ellipsoid; + var positionCart = ellipsoid.cartesianToCartographic(result); + projection.project(positionCart, result); + Cartesian3.fromElements(result.z, result.x, result.y, result); + } + + return result; + } + + var scratchV0 = new Cartesian3(); + var scratchV1 = new Cartesian3(); + var scratchV2 = new Cartesian3(); + var scratchCartesian = new Cartesian3(); + var scratchResult = new Cartesian3(); + + GlobeSurfaceTile.prototype.pick = function(ray, scene, cullBackFaces, result) { + var terrain = this.pickTerrain; + if (!defined(terrain)) { + return undefined; + } + + var mesh = terrain.mesh; + if (!defined(mesh)) { + return undefined; + } + + var vertices = mesh.vertices; + var indices = mesh.indices; + + var length = indices.length; + for (var i = 0; i < length; i += 3) { + var i0 = indices[i]; + var i1 = indices[i + 1]; + var i2 = indices[i + 2]; + + var v0 = getPosition(this, scene, vertices, i0, scratchV0); + var v1 = getPosition(this, scene, vertices, i1, scratchV1); + var v2 = getPosition(this, scene, vertices, i2, scratchV2); + + var intersection = IntersectionTests.rayTriangle(ray, v0, v1, v2, cullBackFaces, scratchResult); + if (defined(intersection)) { + return Cartesian3.clone(intersection, result); + } + } + + return undefined; + }; + GlobeSurfaceTile.prototype.freeResources = function() { if (defined(this.waterMaskTexture)) { --this.waterMaskTexture.referenceCount; @@ -182,6 +245,11 @@ define([ this.upsampledTerrain = undefined; } + if (defined(this.pickTerrain)) { + this.pickTerrain.freeResources(); + this.pickTerrain = undefined; + } + var i, len; var imageryList = this.imagery; @@ -404,6 +472,7 @@ define([ loaded.publishToTile(tile); // No further loading or upsampling is necessary. + surfaceTile.pickTerrain = defaultValue(surfaceTile.loadedTerrain, surfaceTile.upsampledTerrain); surfaceTile.loadedTerrain = undefined; surfaceTile.upsampledTerrain = undefined; } else if (loaded.state === TerrainState.FAILED) { @@ -439,6 +508,7 @@ define([ upsampled.publishToTile(tile); // No further upsampling is necessary. We need to continue loading, though. + surfaceTile.pickTerrain = surfaceTile.upsampledTerrain; surfaceTile.upsampledTerrain = undefined; } else if (upsampled.state === TerrainState.FAILED) { // Upsampling failed for some reason. This is pretty much a catastrophic failure, diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js index e1a812d2dbb7..e26f242a5d4d 100644 --- a/Source/Scene/Scene.js +++ b/Source/Scene/Scene.js @@ -438,7 +438,7 @@ define([ var camera = new Camera(this); this._camera = camera; - this._screenSpaceCameraController = new ScreenSpaceCameraController(canvas, camera); + this._screenSpaceCameraController = new ScreenSpaceCameraController(this); // initial guess at frustums. var near = camera.frustum.near; @@ -1311,9 +1311,8 @@ define([ } this._tweens.update(); - var mode = this._mode; - this._camera.update(mode); - this._screenSpaceCameraController.update(mode); + this._camera.update(this._mode); + this._screenSpaceCameraController.update(this._frameState); }; function render(scene, time) { diff --git a/Source/Scene/ScreenSpaceCameraController.js b/Source/Scene/ScreenSpaceCameraController.js index a9fe0b567ffc..3e25b15bd07a 100644 --- a/Source/Scene/ScreenSpaceCameraController.js +++ b/Source/Scene/ScreenSpaceCameraController.js @@ -4,6 +4,7 @@ define([ '../Core/Cartesian3', '../Core/Cartesian4', '../Core/Cartographic', + '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', '../Core/destroyObject', @@ -13,7 +14,10 @@ define([ '../Core/isArray', '../Core/KeyboardEventModifier', '../Core/Math', + '../Core/Matrix3', '../Core/Matrix4', + '../Core/Plane', + '../Core/Quaternion', '../Core/Ray', '../Core/Transforms', './CameraEventAggregator', @@ -25,6 +29,7 @@ define([ Cartesian3, Cartesian4, Cartographic, + defaultValue, defined, defineProperties, destroyObject, @@ -34,7 +39,10 @@ define([ isArray, KeyboardEventModifier, CesiumMath, + Matrix3, Matrix4, + Plane, + Quaternion, Ray, Transforms, CameraEventAggregator, @@ -48,16 +56,12 @@ define([ * @alias ScreenSpaceCameraController * @constructor * - * @param {Canvas} canvas The canvas to listen for events. - * @param {Camera} camera The camera. + * @param {Scene} scene The scene. */ - var ScreenSpaceCameraController = function(canvas, camera) { + var ScreenSpaceCameraController = function(scene) { //>>includeStart('debug', pragmas.debug); - if (!defined(canvas)) { - throw new DeveloperError('canvas is required.'); - } - if (!defined(camera)) { - throw new DeveloperError('camera is required.'); + if (!defined(scene)) { + throw new DeveloperError('scene is required.'); } //>>includeEnd('debug'); @@ -222,12 +226,24 @@ define([ eventType : CameraEventType.LEFT_DRAG, modifier : KeyboardEventModifier.SHIFT }; + /** + * The minimum height the camera must be before picking the terrain instead of the ellipsoid. + * @type {Number} + * @default 150000.0 + */ + this.minimumPickingTerrainHeight = 150000.0; + /** + * The minimum height the camera must be before tesing for collision with terrain. + * @type {Number} + * @default 10000.0 + */ + this.minimumCollisionTerrainHeight = 10000.0; - this._canvas = canvas; - this._camera = camera; - this._ellipsoid = Ellipsoid.WGS84; + this._scene = scene; + this._globe = undefined; + this._ellipsoid = undefined; - this._aggregator = new CameraEventAggregator(canvas); + this._aggregator = new CameraEventAggregator(scene.canvas); this._lastInertiaSpinMovement = undefined; this._lastInertiaZoomMovement = undefined; @@ -240,11 +256,19 @@ define([ this._horizontalRotationAxis = undefined; + this._tiltCenterMousePosition = new Cartesian2(); + this._tiltCenter = new Cartesian3(); + this._rotateMousePosition = new Cartesian2(); + this._rotateStartPosition = new Cartesian3(); + this._tiltCVOffMap = false; + + var projection = scene.mapProjection; + this._maxCoord = projection.project(new Cartographic(Math.PI, CesiumMath.PI_OVER_TWO)); + // Constants, Make any of these public? - var radius = this._ellipsoid.maximumRadius; this._zoomFactor = 5.0; - this._rotateFactor = 1.0 / radius; - this._rotateRateRangeAdjustment = radius; + this._rotateFactor = undefined; + this._rotateRateRangeAdjustment = undefined; this._maximumRotateRate = 1.77; this._minimumRotateRate = 1.0 / 5000.0; this._translateFactor = 1.0; @@ -252,31 +276,6 @@ define([ this._maximumZoomRate = 5906376272000.0; // distance from the Sun to Pluto in meters. }; - defineProperties(ScreenSpaceCameraController.prototype, { - /** - * Gets and sets the ellipsoid. The ellipsoid is used to determine the size of the map in 2D and Columbus view - * as well as how fast to rotate the camera based on the distance to its surface. - * @memberof ScreenSpaceCameraController.prototype - * @type {Ellipsoid} - */ - ellipsoid : { - get : function() { - return this._ellipsoid; - }, - set : function(ellipsoid) { - //>>includeStart('debug', pragmas.debug); - if (!defined(ellipsoid)) { - throw new DeveloperError('ellipsoid is required'); - } - //>>includeEnd('debug'); - var radius = ellipsoid.maximumRadius; - this._ellipsoid = ellipsoid; - this._rotateFactor = 1.0 / radius; - this._rotateRateRangeAdjustment = radius; - } - } - }); - function decay(time, coefficient) { if (time < 0) { return 0.0; @@ -296,7 +295,7 @@ define([ // hardware. Should be investigated further. var inertiaMaxClickTimeThreshold = 0.4; - function maintainInertia(aggregator, type, modifier, decayCoef, action, object, lastMovementName) { + function maintainInertia(aggregator, frameState, type, modifier, decayCoef, action, object, lastMovementName) { var movementState = object[lastMovementName]; if (!defined(movementState)) { movementState = object[lastMovementName] = { @@ -349,7 +348,8 @@ define([ } if (!aggregator.isButtonDown(type, modifier)) { - action(object, movementState); + var startPosition = aggregator.getStartMousePosition(type, modifier); + action(object, startPosition, movementState, frameState); } } else { movementState.active = false; @@ -358,7 +358,7 @@ define([ var scratchEventTypeArray = []; - function reactToInput(controller, enabled, eventTypes, action, inertiaConstant, inertiaStateName) { + function reactToInput(controller, frameState, enabled, eventTypes, action, inertiaConstant, inertiaStateName) { if (!defined(eventTypes)) { return; } @@ -377,18 +377,19 @@ define([ var modifier = eventType.modifier; var movement = aggregator.isMoving(type, modifier) && aggregator.getMovement(type, modifier); + var startPosition = aggregator.getStartMousePosition(type, modifier); if (controller.enableInputs && enabled) { if (movement) { - action(controller, movement); + action(controller, startPosition, movement, frameState); } else if (inertiaConstant < 1.0) { - maintainInertia(aggregator, type, modifier, inertiaConstant, action, controller, inertiaStateName); + maintainInertia(aggregator, frameState, type, modifier, inertiaConstant, action, controller, inertiaStateName); } } } } - function handleZoom(object, movement, zoomFactor, distanceMeasure, unitPositionDotDirection) { + function handleZoom(object, startPosition, movement, frameState, zoomFactor, distanceMeasure, unitPositionDotDirection) { var percentage = 1.0; if (defined(unitPositionDotDirection)) { percentage = CesiumMath.clamp(Math.abs(unitPositionDotDirection), 0.25, 1.0); @@ -404,7 +405,7 @@ define([ zoomRate = CesiumMath.clamp(zoomRate, object._minimumZoomRate, object._maximumZoomRate); var diff = movement.endPosition.y - movement.startPosition.y; - var rangeWindowRatio = diff / object._canvas.clientHeight; + var rangeWindowRatio = diff / object._scene.canvas.clientHeight; rangeWindowRatio = Math.min(rangeWindowRatio, object.maximumMovementRatio); var distance = zoomRate * rangeWindowRatio; @@ -422,7 +423,7 @@ define([ distance = distanceMeasure - maxHeight; } - object._camera.zoomIn(distance); + object._scene.camera.zoomIn(distance); } var translate2DStart = new Ray(); @@ -430,8 +431,8 @@ define([ var scratchTranslateP0 = new Cartesian3(); var scratchTranslateP1 = new Cartesian3(); - function translate2D(controller, movement) { - var camera = controller._camera; + function translate2D(controller, startPosition, movement, frameState) { + var camera = controller._scene.camera; var start = camera.getPickRay(movement.startPosition, translate2DStart).origin; var end = camera.getPickRay(movement.endPosition, translate2DEnd).origin; @@ -447,24 +448,25 @@ define([ } } - function zoom2D(controller, movement) { + function zoom2D(controller, startPosition, movement, frameState) { if (defined(movement.distance)) { movement = movement.distance; } - handleZoom(controller, movement, controller._zoomFactor, controller._camera.getMagnitude()); + handleZoom(controller, startPosition, movement, frameState, controller._zoomFactor, controller._scene.camera.getMagnitude()); } var twist2DStart = new Cartesian2(); var twist2DEnd = new Cartesian2(); - function twist2D(controller, movement) { + function twist2D(controller, startPosition, movement, frameState) { if (defined(movement.angleAndHeight)) { - singleAxisTwist2D(controller, movement.angleAndHeight); + singleAxisTwist2D(controller, startPosition, movement.angleAndHeight, frameState); return; } - var width = controller._canvas.clientWidth; - var height = controller._canvas.clientHeight; + var canvas = controller._scene.canvas; + var width = canvas.clientWidth; + var height = canvas.clientHeight; var start = twist2DStart; start.x = (2.0 / width) * movement.startPosition.x - 1.0; @@ -486,10 +488,10 @@ define([ } var theta = endTheta - startTheta; - controller._camera.twistRight(theta); + controller._scene.camera.twistRight(theta); } - function singleAxisTwist2D(controller, movement) { + function singleAxisTwist2D(controller, startPosition, movement, frameState) { var rotateRate = controller._rotateFactor * controller._rotateRateRangeAdjustment; if (rotateRate > controller._maximumRotateRate) { @@ -500,34 +502,36 @@ define([ rotateRate = controller._minimumRotateRate; } - var phiWindowRatio = (movement.endPosition.x - movement.startPosition.x) / controller._canvas.clientWidth; + var phiWindowRatio = (movement.endPosition.x - movement.startPosition.x) / controller._scene.canvas.clientWidth; phiWindowRatio = Math.min(phiWindowRatio, controller.maximumMovementRatio); var deltaPhi = rotateRate * phiWindowRatio * Math.PI * 4.0; - controller._camera.twistRight(deltaPhi); + controller._scene.camera.twistRight(deltaPhi); } - function update2D(controller) { + function update2D(controller, frameState) { var tweens = controller._tweens; - if (controller._aggregator.anyButtonDown()) { + if (controller._aggregator.anyButtonDown) { tweens.removeAll(); } - if (!Matrix4.equals(Matrix4.IDENTITY, controller._camera.transform)) { - reactToInput(controller, controller.enableRotate, controller.translateEventTypes, twist2D, controller.inertiaSpin, '_lastInertiaSpinMovement'); - reactToInput(controller, controller.enableZoom, controller.zoomEventTypes, zoom3D, controller.inertiaZoom, '_lastInertiaZoomMovement'); + var camera = controller._scene.camera; + + if (!Matrix4.equals(Matrix4.IDENTITY, camera.transform)) { + reactToInput(controller, frameState, controller.enableRotate, controller.translateEventTypes, twist2D, controller.inertiaSpin, '_lastInertiaSpinMovement'); + reactToInput(controller, frameState, controller.enableZoom, controller.zoomEventTypes, zoom3D, controller.inertiaZoom, '_lastInertiaZoomMovement'); } else { - reactToInput(controller, controller.enableTranslate, controller.translateEventTypes, translate2D, controller.inertiaTranslate, '_lastInertiaTranslateMovement'); - reactToInput(controller, controller.enableZoom, controller.zoomEventTypes, zoom2D, controller.inertiaZoom, '_lastInertiaZoomMovement'); - reactToInput(controller, controller.enableRotate, controller.tiltEventTypes, twist2D, controller.inertiaSpin, '_lastInertiaTiltMovement'); + reactToInput(controller, frameState, controller.enableTranslate, controller.translateEventTypes, translate2D, controller.inertiaTranslate, '_lastInertiaTranslateMovement'); + reactToInput(controller, frameState, controller.enableZoom, controller.zoomEventTypes, zoom2D, controller.inertiaZoom, '_lastInertiaZoomMovement'); + reactToInput(controller, frameState, controller.enableRotate, controller.tiltEventTypes, twist2D, controller.inertiaSpin, '_lastInertiaTiltMovement'); } - if (!controller._aggregator.anyButtonDown() && + if (!controller._aggregator.anyButtonDown && (!defined(controller._lastInertiaZoomMovement) || !controller._lastInertiaZoomMovement.active) && (!defined(controller._lastInertiaTranslateMovement) || !controller._lastInertiaTranslateMovement.active) && !tweens.contains(controller._tween)) { - var tween = controller._camera.createCorrectPositionTween(controller.bounceAnimationTime); + var tween = camera.createCorrectPositionTween(controller.bounceAnimationTime); if (defined(tween)) { controller._tween = tweens.add(tween); } @@ -541,23 +545,44 @@ define([ var translateCVStartPos = new Cartesian3(); var translateCVEndPos = new Cartesian3(); var translatCVDifference = new Cartesian3(); - function translateCV(controller, movement) { - var camera = controller._camera; - var startRay = camera.getPickRay(movement.startPosition, translateCVStartRay); - var endRay = camera.getPickRay(movement.endPosition, translateCVEndRay); + var translateCVOrigin = new Cartesian3(); + var translateCVPlane = new Plane(Cartesian3.ZERO, 0.0); + var translateCVStartMouse = new Cartesian2(); + var translateCVEndMouse = new Cartesian2(); + + function translateCV(controller, startPosition, movement, frameState) { + var camera = controller._scene.camera; + var startMouse = Cartesian3.clone(movement.startPosition, translateCVStartMouse); + var endMouse = Cartesian3.clone(movement.endPosition, translateCVEndMouse); + var startRay = camera.getPickRay(startMouse, translateCVStartRay); + + var origin = Cartesian3.clone(Cartesian3.ZERO, translateCVOrigin); var normal = Cartesian3.UNIT_X; - var position = startRay.origin; - var direction = startRay.direction; - var scalar = -Cartesian3.dot(normal, position) / Cartesian3.dot(normal, direction); - var startPlanePos = Cartesian3.multiplyByScalar(direction, scalar, translateCVStartPos); - Cartesian3.add(position, startPlanePos, startPlanePos); + if (defined(controller._globe) && camera.position.z < controller.minimumPickingTerrainHeight) { + var intersection = controller._globe.pick(startRay, frameState, translateCVStartPos); + if (defined(intersection)) { + origin.x = intersection.x; + } + } - position = endRay.origin; - direction = endRay.direction; - scalar = -Cartesian3.dot(normal, position) / Cartesian3.dot(normal, direction); - var endPlanePos = Cartesian3.multiplyByScalar(direction, scalar, translateCVEndPos); - Cartesian3.add(position, endPlanePos, endPlanePos); + if (origin.x > camera.position.z) { + var tempY = startMouse.y; + startMouse.y = endMouse.y; + endMouse.y = tempY; + } + + var plane = Plane.fromPointNormal(origin, normal, translateCVPlane); + + startRay = camera.getPickRay(startMouse, translateCVStartRay); + var startPlanePos = IntersectionTests.rayPlane(startRay, plane, translateCVStartPos); + + var endRay = camera.getPickRay(endMouse, translateCVEndRay); + var endPlanePos = IntersectionTests.rayPlane(endRay, plane, translateCVEndPos); + + if (!defined(startPlanePos) || !defined(endPlanePos)) { + return; + } var diff = Cartesian3.subtract(startPlanePos, endPlanePos, translatCVDifference); var temp = diff.x; @@ -574,18 +599,46 @@ define([ var rotateCVWindowPos = new Cartesian2(); var rotateCVWindowRay = new Ray(); var rotateCVCenter = new Cartesian3(); - var rotateTransform = new Matrix4(); + var rotateCVVerticalCenter = new Cartesian3(); + var rotateCVTransform = new Matrix4(); + var rotateCVVerticalTransform = new Matrix4(); + var rotateCVOrigin = new Cartesian3(); + var rotateCVPlane = new Plane(Cartesian3.ZERO, 0.0); + var rotateCVCartesian3 = new Cartesian3(); var rotateCVCart = new Cartographic(); + var rotateCVOldTransform = new Matrix4(); + var rotateCVQuaternion = new Quaternion(); + var rotateCVMatrix = new Matrix3(); - function rotateCV(controller, movement) { + function rotateCV(controller, startPosition, movement, frameState) { if (defined(movement.angleAndHeight)) { movement = movement.angleAndHeight; } + if (!Cartesian2.equals(startPosition, controller._tiltCenterMousePosition)) { + controller._tiltCVOffMap = false; + } + + var camera = controller._scene.camera; + var maxCoord = controller._maxCoord; + var onMap = Math.abs(camera.position.x) - maxCoord.x < 0 && Math.abs(camera.position.y) - maxCoord.y < 0; + + if (controller._tiltCVOffMap || !onMap || camera.position.z > controller.minimumPickingTerrainHeight) { + controller._tiltCVOffMap = true; + rotateCVOnPlane(controller, startPosition, movement, frameState); + } else { + rotateCVOnTerrain(controller, startPosition, movement, frameState); + } + } + + function rotateCVOnPlane(controller, startPosition, movement, frameState) { + var camera = controller._scene.camera; + var canvas = controller._scene.canvas; + var windowPosition = rotateCVWindowPos; - windowPosition.x = controller._canvas.clientWidth / 2; - windowPosition.y = controller._canvas.clientHeight / 2; - var ray = controller._camera.getPickRay(windowPosition, rotateCVWindowRay); + windowPosition.x = canvas.clientWidth / 2; + windowPosition.y = canvas.clientHeight / 2; + var ray = camera.getPickRay(windowPosition, rotateCVWindowRay); var normal = Cartesian3.UNIT_X; var position = ray.origin; @@ -594,63 +647,237 @@ define([ var center = Cartesian3.multiplyByScalar(direction, scalar, rotateCVCenter); Cartesian3.add(position, center, center); - var projection = controller._camera._projection; + var projection = controller._scene.mapProjection; var ellipsoid = projection.ellipsoid; Cartesian3.fromElements(center.y, center.z, center.x, center); var cart = projection.unproject(center, rotateCVCart); ellipsoid.cartographicToCartesian(cart, center); - var transform = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, rotateTransform); + var transform = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, rotateCVTransform); + + var oldGlobe = controller._globe; + var oldEllipsoid = controller._ellipsoid; + controller._globe = undefined; + controller._ellipsoid = Ellipsoid.UNIT_SPHERE; + controller._rotateFactor = 1.0; + controller._rotateRateRangeAdjustment = 1.0; + + var oldTransform = Matrix4.clone(camera.transform, rotateCVOldTransform); + camera.setTransform(transform); + + rotate3D(controller, startPosition, movement, frameState, Cartesian3.UNIT_Z); + + camera.setTransform(oldTransform); + controller._globe = oldGlobe; + controller._ellipsoid = oldEllipsoid; + + var radius = oldEllipsoid.maximumRadius; + controller._rotateFactor = 1.0 / radius; + controller._rotateRateRangeAdjustment = radius; + } + + function rotateCVOnTerrain(controller, startPosition, movement, frameState) { + var ellipsoid = controller._ellipsoid; + var camera = controller._scene.camera; + + var center; + var ray; + var intersection; + var normal = Cartesian3.UNIT_X; + + if (Cartesian2.equals(startPosition, controller._tiltCenterMousePosition)) { + center = Cartesian3.clone(controller._tiltCenter, rotateCVCenter); + } else { + ray = camera.getPickRay(startPosition, rotateCVWindowRay); + if (defined(controller._globe) && camera.position.z < controller.minimumPickingTerrainHeight) { + center = controller._globe.pick(ray, frameState, rotateCVCenter); + } + + if (!defined(center)) { + var position = ray.origin; + var direction = ray.direction; + var scalar = -Cartesian3.dot(normal, position) / Cartesian3.dot(normal, direction); + center = Cartesian3.multiplyByScalar(direction, scalar, rotateCVCenter); + Cartesian3.add(position, center, center); + } + + Cartesian2.clone(startPosition, controller._tiltCenterMousePosition); + Cartesian3.clone(center, controller._tiltCenter); + } + + var windowPosition = rotateCVWindowPos; + windowPosition.x = controller._scene.canvas.clientWidth / 2; + windowPosition.y = controller._tiltCenterMousePosition.y; + ray = camera.getPickRay(windowPosition, rotateCVWindowRay); + + var origin = Cartesian3.clone(Cartesian3.ZERO, rotateCVOrigin); + origin.x = center.x; + + var plane = Plane.fromPointNormal(origin, normal, rotateCVPlane); + var verticalCenter = IntersectionTests.rayPlane(ray, plane, rotateCVVerticalCenter); + + var projection = controller._scene.camera._projection; + ellipsoid = projection.ellipsoid; + + Cartesian3.fromElements(center.y, center.z, center.x, center); + var cart = projection.unproject(center, rotateCVCart); + ellipsoid.cartographicToCartesian(cart, center); + + var transform = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, rotateCVTransform); + var verticalTransform; + if (defined(verticalCenter)) { + Cartesian3.fromElements(verticalCenter.y, verticalCenter.z, verticalCenter.x, verticalCenter); + cart = projection.unproject(verticalCenter, rotateCVCart); + ellipsoid.cartographicToCartesian(cart, verticalCenter); + + verticalTransform = Transforms.eastNorthUpToFixedFrame(verticalCenter, ellipsoid, rotateCVVerticalTransform); + } else { + verticalTransform = transform; + } + + var oldGlobe = controller._globe; var oldEllipsoid = controller._ellipsoid; - controller.ellipsoid = Ellipsoid.UNIT_SPHERE; + controller._globe = undefined; + controller._ellipsoid = Ellipsoid.UNIT_SPHERE; + controller._rotateFactor = 1.0; + controller._rotateRateRangeAdjustment = 1.0; + + var constrainedAxis = Cartesian3.UNIT_Z; + + var oldTransform = Matrix4.clone(camera.transform, rotateCVOldTransform); + camera.setTransform(transform); + + var tangent = Cartesian3.cross(Cartesian3.UNIT_Z, Cartesian3.normalize(camera.position, rotateCVCartesian3), rotateCVCartesian3); + var dot = Cartesian3.dot(camera.right, tangent); + + rotate3D(controller, startPosition, movement, frameState, constrainedAxis, false, true); + + camera.setTransform(verticalTransform); + if (dot < 0.0) { + if (movement.startPosition.y > movement.endPosition.y) { + constrainedAxis = undefined; + } + + var oldConstrainedAxis = camera.constrainedAxis; + camera.constrainedAxis = undefined; + + rotate3D(controller, startPosition, movement, frameState, constrainedAxis, true, false); + + camera.constrainedAxis = oldConstrainedAxis; + } else { + rotate3D(controller, startPosition, movement, frameState, constrainedAxis, true, false); + } + + if (defined(camera.constrainedAxis)) { + var right = Cartesian3.cross(camera.direction, camera.constrainedAxis, tilt3DCartesian3); + if (!Cartesian3.equalsEpsilon(right, Cartesian3.ZERO, CesiumMath.EPSILON6)) { + if (Cartesian3.dot(right, camera.right) < 0.0) { + Cartesian3.negate(right, right); + } + + Cartesian3.cross(right, camera.direction, camera.up); + Cartesian3.cross(camera.direction, camera.up, camera.right); + + Cartesian3.normalize(camera.up, camera.up); + Cartesian3.normalize(camera.right, camera.right); + } + } - rotate3D(controller, movement, transform, Cartesian3.UNIT_Z); + camera.setTransform(oldTransform); + controller._globe = oldGlobe; + controller._ellipsoid = oldEllipsoid; - controller.ellipsoid = oldEllipsoid; + var radius = oldEllipsoid.maximumRadius; + controller._rotateFactor = 1.0 / radius; + controller._rotateRateRangeAdjustment = radius; + + var originalPosition = Cartesian3.clone(camera.positionWC, rotateCVCartesian3); + adjustHeightForTerrain(controller, frameState); + + if (!Cartesian3.equals(camera.positionWC, originalPosition)) { + camera.setTransform(verticalTransform); + camera.worldToCameraCoordinatesPoint(originalPosition, originalPosition); + + var magSqrd = Cartesian3.magnitudeSquared(originalPosition); + if (Cartesian3.magnitudeSquared(camera.position) > magSqrd) { + Cartesian3.normalize(camera.position, camera.position); + Cartesian3.multiplyByScalar(camera.position, Math.sqrt(magSqrd), camera.position); + } + + var angle = Cartesian3.angleBetween(originalPosition, camera.position); + var axis = Cartesian3.cross(originalPosition, camera.position, originalPosition); + Cartesian3.normalize(axis, axis); + + var quaternion = Quaternion.fromAxisAngle(axis, angle, rotateCVQuaternion); + var rotation = Matrix3.fromQuaternion(quaternion, rotateCVMatrix); + Matrix3.multiplyByVector(rotation, camera.direction, camera.direction); + Matrix3.multiplyByVector(rotation, camera.up, camera.up); + Cartesian3.cross(camera.direction, camera.up, camera.right); + Cartesian3.cross(camera.right, camera.direction, camera.up); + + camera.setTransform(oldTransform); + } } var zoomCVWindowPos = new Cartesian2(); var zoomCVWindowRay = new Ray(); - function zoomCV(controller, movement) { + var zoomCVIntersection = new Cartesian3(); + + function zoomCV(controller, startPosition, movement, frameState) { if (defined(movement.distance)) { movement = movement.distance; } + var canvas = controller._scene.canvas; + var camera = controller._scene.camera; + var windowPosition = zoomCVWindowPos; - windowPosition.x = controller._canvas.clientWidth / 2; - windowPosition.y = controller._canvas.clientHeight / 2; - var ray = controller._camera.getPickRay(windowPosition, zoomCVWindowRay); - var normal = Cartesian3.UNIT_X; + windowPosition.x = canvas.clientWidth / 2; + windowPosition.y = canvas.clientHeight / 2; + var ray = camera.getPickRay(windowPosition, zoomCVWindowRay); - var position = ray.origin; - var direction = ray.direction; - var scalar = -Cartesian3.dot(normal, position) / Cartesian3.dot(normal, direction); + var intersection; + if (defined(controller._globe) && camera.position.z < controller.minimumPickingTerrainHeight) { + intersection = controller._globe.pick(ray, frameState, zoomCVIntersection); + } - handleZoom(controller, movement, controller._zoomFactor, scalar); + var distance; + if (defined(intersection)) { + distance = Cartesian3.distance(ray.origin, intersection); + } else { + var normal = Cartesian3.UNIT_X; + var position = ray.origin; + var direction = ray.direction; + distance = -Cartesian3.dot(normal, position) / Cartesian3.dot(normal, direction); + } + + handleZoom(controller, startPosition, movement, frameState, controller._zoomFactor, distance); } - function updateCV(controller) { - if (!Matrix4.equals(Matrix4.IDENTITY, controller._camera.transform)) { - reactToInput(controller, controller.enableRotate, controller.rotateEventTypes, rotate3D, controller.inertiaSpin, '_lastInertiaSpinMovement'); - reactToInput(controller, controller.enableZoom, controller.zoomEventTypes, zoom3D, controller.inertiaZoom, '_lastInertiaZoomMovement'); + function updateCV(controller, frameState) { + var camera = controller._scene.camera; + + if (!Matrix4.equals(Matrix4.IDENTITY, camera.transform)) { + reactToInput(controller, frameState, controller.enableRotate, controller.rotateEventTypes, rotate3D, controller.inertiaSpin, '_lastInertiaSpinMovement'); + reactToInput(controller, frameState, controller.enableZoom, controller.zoomEventTypes, zoom3D, controller.inertiaZoom, '_lastInertiaZoomMovement'); } else { var tweens = controller._tweens; - if (controller._aggregator.anyButtonDown()) { + if (controller._aggregator.anyButtonDown) { tweens.removeAll(); } - reactToInput(controller, controller.enableTilt, controller.tiltEventTypes, rotateCV, controller.inertiaSpin, '_lastInertiaTiltMovement'); - reactToInput(controller, controller.enableTranslate, controller.translateEventTypes, translateCV, controller.inertiaTranslate, '_lastInertiaTranslateMovement'); - reactToInput(controller, controller.enableZoom, controller.zoomEventTypes, zoomCV, controller.inertiaZoom, '_lastInertiaZoomMovement'); - reactToInput(controller, controller.enableLook, controller.lookEventTypes, look3D); + reactToInput(controller, frameState, controller.enableTilt, controller.tiltEventTypes, rotateCV, controller.inertiaSpin, '_lastInertiaTiltMovement'); + reactToInput(controller, frameState, controller.enableTranslate, controller.translateEventTypes, translateCV, controller.inertiaTranslate, '_lastInertiaTranslateMovement'); + reactToInput(controller, frameState, controller.enableZoom, controller.zoomEventTypes, zoomCV, controller.inertiaZoom, '_lastInertiaZoomMovement'); + reactToInput(controller, frameState, controller.enableLook, controller.lookEventTypes, look3D); - if (!controller._aggregator.anyButtonDown() && (!defined(controller._lastInertiaZoomMovement) || !controller._lastInertiaZoomMovement.active) && + if (!controller._aggregator.anyButtonDown && (!defined(controller._lastInertiaZoomMovement) || !controller._lastInertiaZoomMovement.active) && (!defined(controller._lastInertiaTranslateMovement) || !controller._lastInertiaTranslateMovement.active) && !tweens.contains(controller._tween)) { - var tween = controller._camera.createCorrectPositionTween(controller.bounceAnimationTime); + var tween = camera.createCorrectPositionTween(controller.bounceAnimationTime); if (defined(tween)) { controller._tween = tweens.add(tween); } @@ -661,19 +888,59 @@ define([ } var spin3DPick = new Cartesian3(); - function spin3D(controller, movement) { - if (defined(controller._camera.pickEllipsoid(movement.startPosition, controller._ellipsoid, spin3DPick))) { - pan3D(controller, movement); - } else { - rotate3D(controller, movement); + var scratchStartRay = new Ray(); + var scratchCartographic = new Cartographic(); + var scratchMousePos = new Cartesian3(); + var scratchRadii = new Cartesian3(); + var scratchEllipsoid = new Ellipsoid(); + + function spin3D(controller, startPosition, movement, frameState) { + var camera = controller._scene.camera; + if (!Matrix4.equals(camera.transform, Matrix4.IDENTITY)) { + rotate3D(controller, startPosition, movement, frameState); + return; + } + + var magnitude; + var radii; + var ellipsoid; + + if (Cartesian2.equals(startPosition, controller._rotateMousePosition)) { + magnitude = Cartesian3.magnitude(controller._rotateStartPosition); + radii = scratchRadii; + radii.x = radii.y = radii.z = magnitude; + ellipsoid = Ellipsoid.fromCartesian3(radii, scratchEllipsoid); + pan3D(controller, startPosition, movement, frameState, ellipsoid); + return; + } + + var height = controller._ellipsoid.cartesianToCartographic(camera.positionWC, scratchCartographic).height; + if (defined(controller._globe) && height < controller.minimumPickingTerrainHeight) { + var startRay = camera.getPickRay(movement.startPosition, scratchStartRay); + var mousePos = controller._globe.pick(startRay, frameState, scratchMousePos); + if (defined(mousePos)) { + magnitude = Cartesian3.magnitude(mousePos); + radii = scratchRadii; + radii.x = radii.y = radii.z = magnitude; + ellipsoid = Ellipsoid.fromCartesian3(radii, scratchEllipsoid); + pan3D(controller, startPosition, movement, frameState, ellipsoid); + + Cartesian2.clone(startPosition, controller._rotateMousePosition); + Cartesian3.clone(mousePos, controller._rotateStartPosition); + } + } else if (defined(camera.pickEllipsoid(movement.startPosition, controller._ellipsoid, spin3DPick))) { + pan3D(controller, startPosition, movement, frameState, controller._ellipsoid); + + Cartesian2.clone(startPosition, controller._rotateMousePosition); + Cartesian3.clone(spin3DPick, controller._rotateStartPosition); } } - var rotate3DRestrictedDirection = Cartesian3.clone(Cartesian3.ZERO); - var rotate3DInverseMatrixScratch = new Matrix4(); + function rotate3D(controller, startPosition, movement, frameState, constrainedAxis, rotateOnlyVertical, rotateOnlyHorizontal) { + rotateOnlyVertical = defaultValue(rotateOnlyVertical, false); + rotateOnlyHorizontal = defaultValue(rotateOnlyHorizontal, false); - function rotate3D(controller, movement, transform, constrainedAxis, restrictedAngle) { - var camera = controller._camera; + var camera = controller._scene.camera; var oldAxis = camera.constrainedAxis; if (defined(constrainedAxis)) { camera.constrainedAxis = constrainedAxis; @@ -690,28 +957,21 @@ define([ rotateRate = controller._minimumRotateRate; } - var phiWindowRatio = (movement.startPosition.x - movement.endPosition.x) / controller._canvas.clientWidth; - var thetaWindowRatio = (movement.startPosition.y - movement.endPosition.y) / controller._canvas.clientHeight; + var canvas = controller._scene.canvas; + var phiWindowRatio = (movement.startPosition.x - movement.endPosition.x) / canvas.clientWidth; + var thetaWindowRatio = (movement.startPosition.y - movement.endPosition.y) / canvas.clientHeight; phiWindowRatio = Math.min(phiWindowRatio, controller.maximumMovementRatio); thetaWindowRatio = Math.min(thetaWindowRatio, controller.maximumMovementRatio); var deltaPhi = rotateRate * phiWindowRatio * Math.PI * 2.0; var deltaTheta = rotateRate * thetaWindowRatio * Math.PI; - camera.rotateRight(deltaPhi, transform); - camera.rotateUp(deltaTheta, transform); - - if (defined(restrictedAngle)) { - var direction = Cartesian3.clone(camera.directionWC, rotate3DRestrictedDirection); - var invTransform = Matrix4.inverseTransformation(transform, rotate3DInverseMatrixScratch); - direction = Matrix4.multiplyByPointAsVector(invTransform, direction, direction); + if (!rotateOnlyVertical) { + camera.rotateRight(deltaPhi); + } - var dot = -Cartesian3.dot(direction, constrainedAxis); - var angle = Math.acos(dot); - if (angle > restrictedAngle) { - angle -= restrictedAngle; - camera.rotateUp(-angle, transform); - } + if (!rotateOnlyHorizontal) { + camera.rotateUp(deltaTheta); } camera.constrainedAxis = oldAxis; @@ -723,17 +983,32 @@ define([ var pan3DTemp1 = new Cartesian3(); var pan3DTemp2 = new Cartesian3(); var pan3DTemp3 = new Cartesian3(); - var basis1Scratch = new Cartesian3(); - function pan3D(controller, movement) { - var camera = controller._camera; - var p0 = camera.pickEllipsoid(movement.startPosition, controller._ellipsoid, pan3DP0); - var p1 = camera.pickEllipsoid(movement.endPosition, controller._ellipsoid, pan3DP1); + var pan3DStartMousePosition = new Cartesian2(); + var pan3DEndMousePosition = new Cartesian2(); + + function pan3D(controller, startPosition, movement, frameState, ellipsoid) { + var camera = controller._scene.camera; + var cameraPosMag = Cartesian3.magnitude(camera.position); + + var startMousePosition = Cartesian2.clone(movement.startPosition, pan3DStartMousePosition); + var endMousePosition = Cartesian2.clone(movement.endPosition, pan3DEndMousePosition); + if (cameraPosMag < ellipsoid.maximumRadius) { + startMousePosition.y = endMousePosition.y; + endMousePosition.y = movement.startPosition.y; + + var magnitude = cameraPosMag + (ellipsoid.maximumRadius - cameraPosMag) * 2.0; + var radii = scratchRadii; + radii.x = radii.y = radii.z = magnitude; + ellipsoid = Ellipsoid.fromCartesian3(radii, ellipsoid); + } + + var p0 = camera.pickEllipsoid(startMousePosition, ellipsoid, pan3DP0); + var p1 = camera.pickEllipsoid(endMousePosition, ellipsoid, pan3DP1); if (!defined(p0) || !defined(p1)) { return; } - // CAMERA TODO: remove access to camera p0 = camera.worldToCameraCoordinates(p0, p0); p1 = camera.worldToCameraCoordinates(p1, p1); @@ -749,7 +1024,7 @@ define([ } } else { var basis0 = camera.constrainedAxis; - var basis1 = Cartesian3.mostOrthogonalAxis(basis0, pan3DTemp0, basis1Scratch); + var basis1 = Cartesian3.mostOrthogonalAxis(basis0, pan3DTemp0); Cartesian3.cross(basis1, basis0, basis1); Cartesian3.normalize(basis1, basis1); var basis2 = Cartesian3.cross(basis0, basis1, pan3DTemp1); @@ -810,33 +1085,77 @@ define([ } var zoom3DUnitPosition = new Cartesian3(); - function zoom3D(controller, movement) { + function zoom3D(controller, startPosition, movement, frameState) { if (defined(movement.distance)) { movement = movement.distance; } - var camera = controller._camera; + var camera = controller._scene.camera; var ellipsoid = controller._ellipsoid; + var canvas = controller._scene.canvas; + var windowPosition = zoomCVWindowPos; + windowPosition.x = canvas.clientWidth / 2; + windowPosition.y = canvas.clientHeight / 2; + var ray = camera.getPickRay(windowPosition, zoomCVWindowRay); + + var intersection; var height = ellipsoid.cartesianToCartographic(camera.position).height; - var unitPosition = Cartesian3.normalize(camera.position, zoom3DUnitPosition); + if (defined(controller._globe) && height < controller.minimumPickingTerrainHeight) { + intersection = controller._globe.pick(ray, frameState, zoomCVIntersection); + } - handleZoom(controller, movement, controller._zoomFactor, height, Cartesian3.dot(unitPosition, camera.direction)); + var distance; + if (defined(intersection)) { + distance = Cartesian3.distance(ray.origin, intersection); + } else { + distance = height; + } + + var unitPosition = Cartesian3.normalize(camera.position, zoom3DUnitPosition); + handleZoom(controller, startPosition, movement, frameState, controller._zoomFactor, distance, Cartesian3.dot(unitPosition, camera.direction)); } var tilt3DWindowPos = new Cartesian2(); var tilt3DRay = new Ray(); - var tilt3DCart = new Cartographic(); - var tilt3DCenter = Cartesian4.clone(Cartesian4.UNIT_W); + var tilt3DCenter = new Cartesian3(); + var tilt3DVerticalCenter = new Cartesian3(); var tilt3DTransform = new Matrix4(); + var tilt3DVerticalTransform = new Matrix4(); + var tilt3DNormal = new Cartesian3(); + var tilt3DCartesian3 = new Cartesian3(); + var tilt3DOldTransform = new Matrix4(); + var tilt3DQuaternion = new Quaternion(); + var tilt3DMatrix = new Matrix3(); + var tilt3DCart = new Cartographic(); + + function tilt3D(controller, startPosition, movement, frameState) { + if (!Matrix4.equals(controller._scene.camera.transform, Matrix4.IDENTITY)) { + return; + } - function tilt3D(controller, movement) { if (defined(movement.angleAndHeight)) { movement = movement.angleAndHeight; } - var camera = controller._camera; + if (!Cartesian2.equals(startPosition, controller._tiltCenterMousePosition)) { + controller._tiltOnEllipsoid = false; + } + + var camera = controller._scene.camera; + var ellipsoid = controller._ellipsoid; + var cartographic = ellipsoid.cartesianToCartographic(camera.position, tilt3DCart); + + if (controller._tiltOnEllipsoid || cartographic.height > controller.minimumCollisionTerrainHeight) { + controller._tiltOnEllipsoid = true; + tilt3DOnEllipsoid(controller, startPosition, movement, frameState); + } else { + tilt3DOnTerrain(controller, startPosition, movement, frameState); + } + } + function tilt3DOnEllipsoid(controller, startPosition, movement, frameState) { + var camera = controller._scene.camera; var ellipsoid = controller._ellipsoid; var minHeight = controller.minimumZoomDistance * 0.25; var height = ellipsoid.cartesianToCartographic(camera.positionWC).height; @@ -846,8 +1165,8 @@ define([ } var windowPosition = tilt3DWindowPos; - windowPosition.x = controller._canvas.clientWidth / 2; - windowPosition.y = controller._canvas.clientHeight / 2; + windowPosition.x = controller._scene.canvas.clientWidth / 2; + windowPosition.y = controller._scene.canvas.clientHeight / 2; var ray = camera.getPickRay(windowPosition, tilt3DRay); var center; @@ -866,21 +1185,167 @@ define([ var transform = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, tilt3DTransform); + var oldGlobe = controller._globe; + var oldEllipsoid = controller._ellipsoid; + controller._globe = undefined; + controller._ellipsoid = Ellipsoid.UNIT_SPHERE; + controller._rotateFactor = 1.0; + controller._rotateRateRangeAdjustment = 1.0; + + var oldTransform = Matrix4.clone(camera.transform, tilt3DOldTransform); + camera.setTransform(transform); + + rotate3D(controller, startPosition, movement, frameState, Cartesian3.UNIT_Z); + + camera.setTransform(oldTransform); + controller._globe = oldGlobe; + controller._ellipsoid = oldEllipsoid; + + var radius = oldEllipsoid.maximumRadius; + controller._rotateFactor = 1.0 / radius; + controller._rotateRateRangeAdjustment = radius; + } + + function tilt3DOnTerrain(controller, startPosition, movement, frameState) { + var camera = controller._scene.camera; + var ellipsoid = controller._ellipsoid; + + var center; + var ray; + var intersection; + + if (Cartesian2.equals(startPosition, controller._tiltCenterMousePosition)) { + center = Cartesian3.clone(controller._tiltCenter, tilt3DCenter); + } else { + ray = camera.getPickRay(startPosition, tilt3DRay); + if (defined(controller._globe)) { + center = controller._globe.pick(ray, frameState, tilt3DCenter); + } + + if (!defined(center)) { + intersection = IntersectionTests.rayEllipsoid(ray, ellipsoid); + if (!defined(intersection)) { + return; + } + center = Ray.getPoint(ray, intersection.start, tilt3DCenter); + } + + Cartesian2.clone(startPosition, controller._tiltCenterMousePosition); + Cartesian3.clone(center, controller._tiltCenter); + } + + + var windowPosition = tilt3DWindowPos; + windowPosition.x = controller._scene.canvas.clientWidth / 2; + windowPosition.y = controller._tiltCenterMousePosition.y; + ray = camera.getPickRay(windowPosition, tilt3DRay); + + var mag = Cartesian3.magnitude(center); + var radii = Cartesian3.fromElements(mag, mag, mag, scratchRadii); + var newEllipsoid = Ellipsoid.fromCartesian3(radii, scratchEllipsoid); + + intersection = IntersectionTests.rayEllipsoid(ray, newEllipsoid); + if (!defined(intersection)) { + return; + } + + var t = Cartesian3.magnitude(ray.origin) > mag ? intersection.start : intersection.stop; + var verticalCenter = Ray.getPoint(ray, t, tilt3DVerticalCenter); + + var transform = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, tilt3DTransform); + var verticalTransform = Transforms.eastNorthUpToFixedFrame(verticalCenter, newEllipsoid, tilt3DVerticalTransform); + + var oldGlobe = controller._globe; var oldEllipsoid = controller._ellipsoid; - controller.ellipsoid = Ellipsoid.UNIT_SPHERE; + controller._globe = undefined; + controller._ellipsoid = Ellipsoid.UNIT_SPHERE; + controller._rotateFactor = 1.0; + controller._rotateRateRangeAdjustment = 1.0; + + var constrainedAxis = Cartesian3.UNIT_Z; + + var oldTransform = Matrix4.clone(camera.transform, tilt3DOldTransform); + camera.setTransform(transform); + + var tangent = Cartesian3.cross(verticalCenter, camera.positionWC, tilt3DCartesian3); + var dot = Cartesian3.dot(camera.rightWC, tangent); + + rotate3D(controller, startPosition, movement, frameState, constrainedAxis, false, true); + + camera.setTransform(verticalTransform); + + if (dot < 0.0) { + if (movement.startPosition.y > movement.endPosition.y) { + constrainedAxis = undefined; + } + + var oldConstrainedAxis = camera.constrainedAxis; + camera.constrainedAxis = undefined; + + rotate3D(controller, startPosition, movement, frameState, constrainedAxis, true, false); + + camera.constrainedAxis = oldConstrainedAxis; + } else { + rotate3D(controller, startPosition, movement, frameState, constrainedAxis, true, false); + } + + if (defined(camera.constrainedAxis)) { + var right = Cartesian3.cross(camera.direction, camera.constrainedAxis, tilt3DCartesian3); + if (!Cartesian3.equalsEpsilon(right, Cartesian3.ZERO, CesiumMath.EPSILON6)) { + if (Cartesian3.dot(right, camera.right) < 0.0) { + Cartesian3.negate(right, right); + } - var angle = (minHeight * 0.25) / Cartesian3.distance(center, camera.position); - rotate3D(controller, movement, transform, Cartesian3.UNIT_Z, CesiumMath.PI_OVER_TWO - angle); + Cartesian3.cross(right, camera.direction, camera.up); + Cartesian3.cross(camera.direction, camera.up, camera.right); - controller.ellipsoid = oldEllipsoid; + Cartesian3.normalize(camera.up, camera.up); + Cartesian3.normalize(camera.right, camera.right); + } + } + + camera.setTransform(oldTransform); + controller._globe = oldGlobe; + controller._ellipsoid = oldEllipsoid; + + var radius = oldEllipsoid.maximumRadius; + controller._rotateFactor = 1.0 / radius; + controller._rotateRateRangeAdjustment = radius; + + var originalPosition = Cartesian3.clone(camera.positionWC, tilt3DCartesian3); + adjustHeightForTerrain(controller, frameState); + + if (!Cartesian3.equals(camera.positionWC, originalPosition)) { + camera.setTransform(verticalTransform); + camera.worldToCameraCoordinatesPoint(originalPosition, originalPosition); + + var magSqrd = Cartesian3.magnitudeSquared(originalPosition); + if (Cartesian3.magnitudeSquared(camera.position) > magSqrd) { + Cartesian3.normalize(camera.position, camera.position); + Cartesian3.multiplyByScalar(camera.position, Math.sqrt(magSqrd), camera.position); + } + + var angle = Cartesian3.angleBetween(originalPosition, camera.position); + var axis = Cartesian3.cross(originalPosition, camera.position, originalPosition); + Cartesian3.normalize(axis, axis); + + var quaternion = Quaternion.fromAxisAngle(axis, angle, tilt3DQuaternion); + var rotation = Matrix3.fromQuaternion(quaternion, tilt3DMatrix); + Matrix3.multiplyByVector(rotation, camera.direction, camera.direction); + Matrix3.multiplyByVector(rotation, camera.up, camera.up); + Cartesian3.cross(camera.direction, camera.up, camera.right); + Cartesian3.cross(camera.right, camera.direction, camera.up); + + camera.setTransform(oldTransform); + } } var look3DStartPos = new Cartesian2(); var look3DEndPos = new Cartesian2(); var look3DStartRay = new Ray(); var look3DEndRay = new Ray(); - function look3D(controller, movement) { - var camera = controller._camera; + function look3D(controller, startPosition, movement, frameState) { + var camera = controller._scene.camera; var startPos = look3DStartPos; startPos.x = movement.startPosition.x; @@ -920,27 +1385,85 @@ define([ camera.lookUp(angle); } - function update3D(controller) { - reactToInput(controller, controller.enableRotate, controller.rotateEventTypes, spin3D, controller.inertiaSpin, '_lastInertiaSpinMovement'); - reactToInput(controller, controller.enableZoom, controller.zoomEventTypes, zoom3D, controller.inertiaZoom, '_lastInertiaZoomMovement'); - reactToInput(controller, controller.enableTilt, controller.tiltEventTypes, tilt3D, controller.inertiaSpin, '_lastInertiaTiltMovement'); - reactToInput(controller, controller.enableLook, controller.lookEventTypes, look3D); + function update3D(controller, frameState) { + reactToInput(controller, frameState, controller.enableRotate, controller.rotateEventTypes, spin3D, controller.inertiaSpin, '_lastInertiaSpinMovement'); + reactToInput(controller, frameState, controller.enableZoom, controller.zoomEventTypes, zoom3D, controller.inertiaZoom, '_lastInertiaZoomMovement'); + reactToInput(controller, frameState, controller.enableTilt, controller.tiltEventTypes, tilt3D, controller.inertiaSpin, '_lastInertiaTiltMovement'); + reactToInput(controller, frameState, controller.enableLook, controller.lookEventTypes, look3D); + } + + var scratchAdjustHeightCartographic = new Cartographic(); + + function adjustHeightForTerrain(controller, frameState) { + var mode = frameState.mode; + var globe = controller._globe; + + if (!defined(globe) || mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) { + return; + } + + var camera = controller._scene.camera; + var ellipsoid = controller._ellipsoid; + var projection = frameState.mapProjection; + + var cartographic = scratchAdjustHeightCartographic; + if (mode === SceneMode.SCENE3D) { + ellipsoid.cartesianToCartographic(camera.position, cartographic); + } else { + projection.unproject(camera.position, cartographic); + } + + if (cartographic.height > controller.minimumCollisionTerrainHeight) { + return; + } + + var height = globe.getHeight(cartographic, frameState); + if (!defined(height)) { + return; + } + + height += controller.minimumZoomDistance; + if (cartographic.height >= height) { + return; + } + + cartographic.height = height; + if (mode === SceneMode.SCENE3D) { + ellipsoid.cartographicToCartesian(cartographic, camera.position); + } else { + projection.project(cartographic, camera.position); + } } /** * @private */ - ScreenSpaceCameraController.prototype.update = function(mode) { + ScreenSpaceCameraController.prototype.update = function(frameState) { + if (!Matrix4.equals(this._scene.camera.transform, Matrix4.IDENTITY)) { + this._globe = undefined; + this._ellipsoid = Ellipsoid.UNIT_SPHERE; + } else { + this._globe = this._scene.globe; + this._ellipsoid = defined(this._globe) ? this._globe.ellipsoid : this._scene.mapProjection.ellipsoid; + } + + var radius = this._ellipsoid.maximumRadius; + this._rotateFactor = 1.0 / radius; + this._rotateRateRangeAdjustment = radius; + + var mode = frameState.mode; if (mode === SceneMode.SCENE2D) { - update2D(this); + update2D(this, frameState); } else if (mode === SceneMode.COLUMBUS_VIEW) { this._horizontalRotationAxis = Cartesian3.UNIT_Z; - updateCV(this); + updateCV(this, frameState); } else if (mode === SceneMode.SCENE3D) { this._horizontalRotationAxis = undefined; - update3D(this); + update3D(this, frameState); } + adjustHeightForTerrain(this, frameState); + this._aggregator.reset(); }; diff --git a/Source/Widgets/Geocoder/Geocoder.js b/Source/Widgets/Geocoder/Geocoder.js index 15157ed91702..f9bdc5f2798f 100644 --- a/Source/Widgets/Geocoder/Geocoder.js +++ b/Source/Widgets/Geocoder/Geocoder.js @@ -38,7 +38,6 @@ 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 {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The Scene's primary ellipsoid. * @param {Number} [options.flightDuration=1.5] The duration of the camera flight to an entered location, in seconds. */ var Geocoder = function(options) { @@ -155,4 +154,4 @@ cesiumSvgPath: { path: isSearchInProgress ? _stopSearchPath : _startSearchPath, }; return Geocoder; -}); \ No newline at end of file +}); diff --git a/Source/Widgets/Geocoder/GeocoderViewModel.js b/Source/Widgets/Geocoder/GeocoderViewModel.js index 4ecc7f6f3222..51606340f045 100644 --- a/Source/Widgets/Geocoder/GeocoderViewModel.js +++ b/Source/Widgets/Geocoder/GeocoderViewModel.js @@ -5,7 +5,6 @@ define([ '../../Core/defined', '../../Core/defineProperties', '../../Core/DeveloperError', - '../../Core/Ellipsoid', '../../Core/jsonp', '../../Core/Matrix4', '../../Core/Rectangle', @@ -19,7 +18,6 @@ define([ defined, defineProperties, DeveloperError, - Ellipsoid, jsonp, Matrix4, Rectangle, @@ -44,7 +42,6 @@ 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 {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The Scene's primary ellipsoid. * @param {Number} [options.flightDuration=1.5] The duration of the camera flight to an entered location, in seconds. */ var GeocoderViewModel = function(options) { @@ -61,7 +58,6 @@ define([ this._key = BingMapsApi.getKey(options.key); this._scene = options.scene; - this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84); this._flightDuration = defaultValue(options.flightDuration, 1.5); this._searchText = ''; this._isSearchInProgress = false; @@ -175,18 +171,6 @@ define([ } }, - /** - * Gets the ellipsoid to be viewed. - * @memberof GeocoderViewModel.prototype - * - * @type {Ellipsoid} - */ - ellipsoid : { - get : function() { - return this._ellipsoid; - } - }, - /** * Gets the Command that is executed when the button is clicked. * @memberof GeocoderViewModel.prototype @@ -256,10 +240,6 @@ define([ viewModel._scene.camera.flyTo({ destination : position, duration : viewModel._flightDuration, - complete : function() { - var screenSpaceCameraController = viewModel._scene.screenSpaceCameraController; - screenSpaceCameraController.ellipsoid = viewModel._ellipsoid; - }, endTransform : Matrix4.IDENTITY, convert : false }); diff --git a/Source/Widgets/HomeButton/HomeButton.js b/Source/Widgets/HomeButton/HomeButton.js index f77f80c5cd19..160bf38fa358 100644 --- a/Source/Widgets/HomeButton/HomeButton.js +++ b/Source/Widgets/HomeButton/HomeButton.js @@ -25,10 +25,9 @@ define([ * * @param {Element|String} container The DOM element or ID that will contain the widget. * @param {Scene} scene The Scene instance to use. - * @param {Ellipsoid} [ellipsoid] The Scene's primary ellipsoid. * @param {Number} [duration] The time, in seconds, it takes to complete the camera flight home. */ - var HomeButton = function(container, scene, ellipsoid, duration) { + var HomeButton = function(container, scene, duration) { //>>includeStart('debug', pragmas.debug); if (!defined(container)) { throw new DeveloperError('container is required.'); @@ -37,7 +36,7 @@ define([ container = getElement(container); - var viewModel = new HomeButtonViewModel(scene, ellipsoid, duration); + var viewModel = new HomeButtonViewModel(scene, duration); viewModel._svgPath = 'M14,4l-10,8.75h20l-4.25-3.7188v-4.6562h-2.812v2.1875l-2.938-2.5625zm-7.0938,9.906v10.094h14.094v-10.094h-14.094zm2.1876,2.313h3.3122v4.25h-3.3122v-4.25zm5.8442,1.281h3.406v6.438h-3.406v-6.438z'; diff --git a/Source/Widgets/HomeButton/HomeButtonViewModel.js b/Source/Widgets/HomeButton/HomeButtonViewModel.js index 85a0e3e29fa5..fb967432984b 100644 --- a/Source/Widgets/HomeButton/HomeButtonViewModel.js +++ b/Source/Widgets/HomeButton/HomeButtonViewModel.js @@ -5,7 +5,6 @@ define([ '../../Core/defined', '../../Core/defineProperties', '../../Core/DeveloperError', - '../../Core/Ellipsoid', '../../Core/Matrix4', '../../Core/Rectangle', '../../Scene/Camera', @@ -18,7 +17,6 @@ define([ defined, defineProperties, DeveloperError, - Ellipsoid, Matrix4, Rectangle, Camera, @@ -27,11 +25,8 @@ define([ createCommand) { "use strict"; - function viewHome(scene, ellipsoid, duration) { + function viewHome(scene, duration) { var mode = scene.mode; - var controller = scene.screenSpaceCameraController; - - controller.ellipsoid = ellipsoid; if (defined(scene) && mode === SceneMode.MORPHING) { scene.completeMorph(); @@ -68,7 +63,7 @@ define([ endTransform : Matrix4.IDENTITY }); } else if (mode === SceneMode.COLUMBUS_VIEW) { - var maxRadii = ellipsoid.maximumRadius; + 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(); @@ -93,26 +88,23 @@ define([ * @constructor * * @param {Scene} scene The scene instance to use. - * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to be viewed when in home position. * @param {Number} [duration=1.5] The duration of the camera flight in seconds. */ - var HomeButtonViewModel = function(scene, ellipsoid, duration) { + var HomeButtonViewModel = function(scene, duration) { //>>includeStart('debug', pragmas.debug); if (!defined(scene)) { throw new DeveloperError('scene is required.'); } //>>includeEnd('debug'); - ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84); duration = defaultValue(duration, 1.5); this._scene = scene; - this._ellipsoid = ellipsoid; this._duration = duration; var that = this; this._command = createCommand(function() { - viewHome(that._scene, that._ellipsoid, that._duration); + viewHome(that._scene, that._duration); }); /** @@ -138,18 +130,6 @@ define([ } }, - /** - * Gets the ellipsoid to be viewed when in home position. - * @memberof HomeButtonViewModel.prototype - * - * @type {Ellipsoid} - */ - ellipsoid : { - get : function() { - return this._ellipsoid; - } - }, - /** * Gets the Command that is executed when the button is clicked. * @memberof HomeButtonViewModel.prototype diff --git a/Source/Widgets/Viewer/Viewer.js b/Source/Widgets/Viewer/Viewer.js index 84ae3d02c354..ea34cee4c41a 100644 --- a/Source/Widgets/Viewer/Viewer.js +++ b/Source/Widgets/Viewer/Viewer.js @@ -288,15 +288,14 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to toolbar.appendChild(geocoderContainer); geocoder = new Geocoder({ container : geocoderContainer, - scene : cesiumWidget.scene, - ellipsoid : cesiumWidget.scene.globe.ellipsoid + scene : cesiumWidget.scene }); } // HomeButton var homeButton; if (!defined(options.homeButton) || options.homeButton !== false) { - homeButton = new HomeButton(toolbar, cesiumWidget.scene, cesiumWidget.scene.globe.ellipsoid); + homeButton = new HomeButton(toolbar, cesiumWidget.scene); if (defined(geocoder)) { eventHelper.add(homeButton.viewModel.command.afterExecute, function() { var viewModel = geocoder.viewModel; diff --git a/Specs/Core/IntersectionTestsSpec.js b/Specs/Core/IntersectionTestsSpec.js index cb31398f69e2..17d30a936e1f 100644 --- a/Specs/Core/IntersectionTestsSpec.js +++ b/Specs/Core/IntersectionTestsSpec.js @@ -1,6 +1,7 @@ /*global defineSuite*/ defineSuite([ 'Core/IntersectionTests', + 'Core/BoundingSphere', 'Core/Cartesian3', 'Core/Ellipsoid', 'Core/Math', @@ -8,6 +9,7 @@ defineSuite([ 'Core/Ray' ], function( IntersectionTests, + BoundingSphere, Cartesian3, Ellipsoid, CesiumMath, @@ -55,6 +57,440 @@ defineSuite([ }).toThrowDeveloperError(); }); + it('rayTriangle throws without ray', function() { + expect(function() { + IntersectionTests.rayTriangle(); + }).toThrowDeveloperError(); + }); + + it('rayTriangle throws without p0', function() { + expect(function() { + IntersectionTests.rayTriangle(new Ray()); + }).toThrowDeveloperError(); + }); + + it('rayTriangle throws without p1', function() { + expect(function() { + IntersectionTests.rayTriangle(new Ray(), new Cartesian3()); + }).toThrowDeveloperError(); + }); + + it('rayTriangle throws without p2', function() { + expect(function() { + IntersectionTests.rayTriangle(new Ray(), new Cartesian3(), new Cartesian3()); + }).toThrowDeveloperError(); + }); + + it('rayTriangle intersects front face', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var ray = new Ray(Cartesian3.UNIT_Z, Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3())); + + var intersection = IntersectionTests.rayTriangle(ray, p0, p1, p2); + expect(intersection).toEqual(Cartesian3.ZERO); + }); + + it('rayTriangle intersects back face without culling', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var ray = new Ray(Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), Cartesian3.UNIT_Z); + + var intersection = IntersectionTests.rayTriangle(ray, p0, p1, p2); + expect(intersection).toEqual(Cartesian3.ZERO); + }); + + it('rayTriangle does not intersect back face with culling', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var ray = new Ray(Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), Cartesian3.UNIT_Z); + + var intersection = IntersectionTests.rayTriangle(ray, p0, p1, p2, true); + expect(intersection).not.toBeDefined(); + }); + + it('rayTriangle does not intersect outside the 0-1 edge', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var ray = new Ray(new Cartesian3(0.0, -1.0, 1.0), Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3())); + + var intersection = IntersectionTests.rayTriangle(ray, p0, p1, p2); + expect(intersection).not.toBeDefined(); + }); + + it('rayTriangle does not intersect outside the 1-2 edge', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var ray = new Ray(new Cartesian3(1.0, 1.0, 1.0), Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3())); + + var intersection = IntersectionTests.rayTriangle(ray, p0, p1, p2); + expect(intersection).not.toBeDefined(); + }); + + it('rayTriangle does not intersect outside the 2-0 edge', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var ray = new Ray(new Cartesian3(-1.0, 1.0, 1.0), Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3())); + + var intersection = IntersectionTests.rayTriangle(ray, p0, p1, p2); + expect(intersection).not.toBeDefined(); + }); + + it('rayTriangle does not intersect parallel ray and triangle', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var ray = new Ray(new Cartesian3(-1.0, 0.0, 1.0), Cartesian3.UNIT_X); + + var intersection = IntersectionTests.rayTriangle(ray, p0, p1, p2); + expect(intersection).not.toBeDefined(); + }); + + it('rayTriangle does not intersect behind the ray origin', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var ray = new Ray(Cartesian3.UNIT_Z, Cartesian3.UNIT_Z); + + var intersection = IntersectionTests.rayTriangle(ray, p0, p1, p2); + expect(intersection).not.toBeDefined(); + }); + + it('lineSegmentTriangle throws without v0', function() { + expect(function() { + IntersectionTests.lineSegmentTriangle(); + }).toThrowDeveloperError(); + }); + + it('lineSegmentTriangle throws without v1', function() { + expect(function() { + IntersectionTests.lineSegmentTriangle(new Cartesian3()); + }).toThrowDeveloperError(); + }); + + it('lineSegmentTriangle throws without p0', function() { + expect(function() { + IntersectionTests.lineSegmentTriangle(new Cartesian3(), new Cartesian3()); + }).toThrowDeveloperError(); + }); + + it('lineSegmentTriangle throws without p1', function() { + expect(function() { + IntersectionTests.lineSegmentTriangle(new Cartesian3(), new Cartesian3(), new Cartesian3()); + }).toThrowDeveloperError(); + }); + + it('lineSegmentTriangle throws without p2', function() { + expect(function() { + IntersectionTests.lineSegmentTriangle(new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()); + }).toThrowDeveloperError(); + }); + + it('lineSegmentTriangle intersects front face', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var v0 = Cartesian3.UNIT_Z; + var v1 = Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()); + + var intersection = IntersectionTests.lineSegmentTriangle(v0, v1, p0, p1, p2); + expect(intersection).toEqual(Cartesian3.ZERO); + }); + + it('lineSegmentTriangle intersects back face without culling', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var v0 = Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()); + var v1 = Cartesian3.UNIT_Z; + + var intersection = IntersectionTests.lineSegmentTriangle(v0, v1, p0, p1, p2); + expect(intersection).toEqual(Cartesian3.ZERO); + }); + + it('lineSegmentTriangle does not intersect back face with culling', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var v0 = Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()); + var v1 = Cartesian3.UNIT_Z; + + var intersection = IntersectionTests.lineSegmentTriangle(v0, v1, p0, p1, p2, true); + expect(intersection).not.toBeDefined(); + }); + + it('lineSegmentTriangle does not intersect outside the 0-1 edge', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var v0 = new Cartesian3(0.0, -1.0, 1.0); + var v1 = Cartesian3.add(v0, Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), new Cartesian3()); + + var intersection = IntersectionTests.lineSegmentTriangle(v0, v1, p0, p1, p2); + expect(intersection).not.toBeDefined(); + }); + + it('lineSegmentTriangle does not intersect outside the 1-2 edge', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var v0 = new Cartesian3(1.0, 1.0, 1.0); + var v1 = Cartesian3.add(v0, Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), new Cartesian3()); + + var intersection = IntersectionTests.lineSegmentTriangle(v0, v1, p0, p1, p2); + expect(intersection).not.toBeDefined(); + }); + + it('lineSegmentTriangle does not intersect outside the 2-0 edge', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var v0 = new Cartesian3(-1.0, 1.0, 1.0); + var v1 = Cartesian3.add(v0, Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), new Cartesian3()); + + var intersection = IntersectionTests.lineSegmentTriangle(v0, v1, p0, p1, p2); + expect(intersection).not.toBeDefined(); + }); + + it('lineSegmentTriangle does not intersect parallel ray and triangle', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var v0 = new Cartesian3(-1.0, 0.0, 1.0); + var v1 = Cartesian3.add(v0, Cartesian3.UNIT_X, new Cartesian3()); + + var intersection = IntersectionTests.lineSegmentTriangle(v0, v1, p0, p1, p2); + expect(intersection).not.toBeDefined(); + }); + + it('lineSegmentTriangle does not intersect behind the v0', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var v0 = Cartesian3.UNIT_Z; + var v1 = Cartesian3.multiplyByScalar(Cartesian3.UNIT_Z, 2.0, new Cartesian3()); + + var intersection = IntersectionTests.lineSegmentTriangle(v0, v1, p0, p1, p2); + expect(intersection).not.toBeDefined(); + }); + + it('lineSegmentTriangle does not intersect behind the v1', function() { + var p0 = new Cartesian3(-1.0, 0.0, 0.0); + var p1 = new Cartesian3(1.0, 0.0, 0.0); + var p2 = new Cartesian3(0.0, 1.0, 0.0); + + var v0 = Cartesian3.multiplyByScalar(Cartesian3.UNIT_Z, 2.0, new Cartesian3()); + var v1 = Cartesian3.UNIT_Z; + + var intersection = IntersectionTests.lineSegmentTriangle(v0, v1, p0, p1, p2); + expect(intersection).not.toBeDefined(); + }); + + it('raySphere throws without ray', function() { + expect(function() { + IntersectionTests.raySphere(); + }).toThrowDeveloperError(); + }); + + it('raySphere throws without ellipsoid', function() { + expect(function() { + IntersectionTests.raySphere(new Ray()); + }).toThrowDeveloperError(); + }); + + it('raySphere outside intersections', function() { + var unitSphere = new BoundingSphere(Cartesian3.ZERO, 1.0); + + var ray = new Ray(new Cartesian3(2.0, 0.0, 0.0), new Cartesian3(-1.0, 0.0, 0.0)); + var intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(0.0, 2.0, 0.0), new Cartesian3(0.0, -1.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(0.0, 0.0, 2.0), new Cartesian3(0.0, 0.0, -1.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(1.0, 1.0, 0.0), new Cartesian3(-1.0, 0.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(-2.0, 0.0, 0.0), new Cartesian3(1.0, 0.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(0.0, -2.0, 0.0), new Cartesian3(0.0, 1.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(0.0, 0.0, -2.0), new Cartesian3(0.0, 0.0, 1.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(-1.0, -1.0, 0.0), new Cartesian3(1.0, 0.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(-2.0, 0.0, 0.0), new Cartesian3(-1.0, 0.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections).toBeUndefined(); + + ray = new Ray(new Cartesian3(0.0, -2.0, 0.0), new Cartesian3(0.0, -1.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections).toBeUndefined(); + + ray = new Ray(new Cartesian3(0.0, 0.0, -2.0), new Cartesian3(0.0, 0.0, -1.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections).toBeUndefined(); + }); + + it('raySphere ray inside pointing in intersection', function() { + var sphere = new BoundingSphere(Cartesian3.ZERO, 5000.0); + + var origin = new Cartesian3(200.0, 0.0, 0.0); + var direction = Cartesian3.negate(Cartesian3.normalize(origin, new Cartesian3()), new Cartesian3()); + var ray = new Ray(origin, direction); + + var expected = { + start : 0.0, + stop : sphere.radius + origin.x + }; + var actual = IntersectionTests.raySphere(ray, sphere); + + expect(actual).toBeDefined(); + expect(actual.start).toEqual(expected.start); + expect(actual.stop).toEqual(expected.stop); + }); + + it('raySphere ray inside pointing out intersection', function() { + var sphere = new BoundingSphere(Cartesian3.ZERO, 5000.0); + + var origin = new Cartesian3(200.0, 0.0, 0.0); + var direction = Cartesian3.normalize(origin, new Cartesian3()); + var ray = new Ray(origin, direction); + + var expected = { + start : 0.0, + stop : sphere.radius - origin.x + }; + var actual = IntersectionTests.raySphere(ray, sphere); + + expect(actual).toBeDefined(); + expect(actual.start).toEqual(expected.start); + expect(actual.stop).toEqual(expected.stop); + }); + + it('raySphere tangent intersections', function() { + var unitSphere = new BoundingSphere(Cartesian3.ZERO, 1.0); + + var ray = new Ray(Cartesian3.UNIT_X, Cartesian3.UNIT_Z); + var intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections).not.toBeDefined(); + }); + + it('raySphere no intersections', function() { + var unitSphere = new BoundingSphere(Cartesian3.ZERO, 1.0); + + var ray = new Ray(new Cartesian3(2.0, 0.0, 0.0), new Cartesian3(0.0, 0.0, 1.0)); + var intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections).not.toBeDefined(); + + ray = new Ray(new Cartesian3(2.0, 0.0, 0.0), new Cartesian3(0.0, 0.0, -1.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections).not.toBeDefined(); + + ray = new Ray(new Cartesian3(2.0, 0.0, 0.0), new Cartesian3(0.0, 1.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections).not.toBeDefined(); + + ray = new Ray(new Cartesian3(2.0, 0.0, 0.0), new Cartesian3(0.0, -1.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections).not.toBeDefined(); + }); + + it('raySphere intersection with sphere center not the origin', function() { + var unitSphere = new BoundingSphere(new Cartesian3(200.0, 0.0, 0.0), 1.0); + + var ray = new Ray(new Cartesian3(202.0, 0.0, 0.0), new Cartesian3(-1.0, 0.0, 0.0)); + var intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(200.0, 2.0, 0.0), new Cartesian3(0.0, -1.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(200.0, 0.0, 2.0), new Cartesian3(0.0, 0.0, -1.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(201.0, 1.0, 0.0), new Cartesian3(-1.0, 0.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(198.0, 0.0, 0.0), new Cartesian3(1.0, 0.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(200.0, -2.0, 0.0), new Cartesian3(0.0, 1.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(200.0, 0.0, -2.0), new Cartesian3(0.0, 0.0, 1.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(intersections.stop).toEqualEpsilon(3.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(199.0, -1.0, 0.0), new Cartesian3(1.0, 0.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections.start).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + + ray = new Ray(new Cartesian3(198.0, 0.0, 0.0), new Cartesian3(-1.0, 0.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections).toBeUndefined(); + + ray = new Ray(new Cartesian3(200.0, -2.0, 0.0), new Cartesian3(0.0, -1.0, 0.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections).toBeUndefined(); + + ray = new Ray(new Cartesian3(200.0, 0.0, -2.0), new Cartesian3(0.0, 0.0, -1.0)); + intersections = IntersectionTests.raySphere(ray, unitSphere); + expect(intersections).toBeUndefined(); + }); + it('rayEllipsoid throws without ray', function() { expect(function() { IntersectionTests.rayEllipsoid(); diff --git a/Specs/Scene/CameraEventAggregatorSpec.js b/Specs/Scene/CameraEventAggregatorSpec.js index 9fc63f0fea6e..12efde53c63c 100644 --- a/Specs/Scene/CameraEventAggregatorSpec.js +++ b/Specs/Scene/CameraEventAggregatorSpec.js @@ -137,7 +137,7 @@ defineSuite([ }); it('anyButtonDown', function() { - expect(handler.anyButtonDown(CameraEventType.LEFT_DRAG)).toEqual(false); + expect(handler.anyButtonDown).toEqual(false); var args = { button : MouseButtons.LEFT, @@ -145,18 +145,18 @@ defineSuite([ clientY : 0 }; canvas.fireEvents('mousedown', args); - expect(handler.anyButtonDown(CameraEventType.LEFT_DRAG)).toEqual(true); + expect(handler.anyButtonDown).toEqual(true); args.button = MouseButtons.RIGHT; canvas.fireEvents('mousedown', args); - expect(handler.anyButtonDown(CameraEventType.LEFT_DRAG)).toEqual(true); + expect(handler.anyButtonDown).toEqual(true); canvas.fireEvents('mouseup', args); - expect(handler.anyButtonDown(CameraEventType.LEFT_DRAG)).toEqual(true); + expect(handler.anyButtonDown).toEqual(true); args.button = MouseButtons.LEFT; canvas.fireEvents('mouseup', args); - expect(handler.anyButtonDown(CameraEventType.LEFT_DRAG)).toEqual(false); + expect(handler.anyButtonDown).toEqual(false); }); it('getButtonPressTime', function() { diff --git a/Specs/Scene/GeometryRenderingSpec.js b/Specs/Scene/GeometryRenderingSpec.js index 3a7ba3f5eccc..227907b4a620 100644 --- a/Specs/Scene/GeometryRenderingSpec.js +++ b/Specs/Scene/GeometryRenderingSpec.js @@ -576,7 +576,8 @@ defineSuite([ var transform = Matrix4.multiplyByTranslation( Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center), new Cartesian3(0.0, 0.0, height), new Matrix4()); - frameState.camera.rotateDown(CesiumMath.PI, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(CesiumMath.PI); }; render3D(instance, afterView); }); @@ -584,7 +585,8 @@ defineSuite([ it('renders wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateDown(CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -797,7 +799,8 @@ defineSuite([ it('renders bottom', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateDown(CesiumMath.PI, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(CesiumMath.PI); }; render3D(instance, afterView); }); @@ -805,7 +808,8 @@ defineSuite([ it('renders north wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -813,7 +817,8 @@ defineSuite([ it('renders south wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateDown(CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -821,7 +826,8 @@ defineSuite([ it('renders west wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateRight(-CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateRight(-CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -829,7 +835,8 @@ defineSuite([ it('renders east wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateRight(CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateRight(CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -991,7 +998,8 @@ defineSuite([ var transform = Matrix4.multiplyByTranslation( Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center), new Cartesian3(0.0, 0.0, height), new Matrix4()); - frameState.camera.rotateDown(CesiumMath.PI, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(CesiumMath.PI); }; render3D(instance, afterView); }); @@ -999,7 +1007,8 @@ defineSuite([ it('renders wall 1', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateUp(CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateUp(CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -1007,7 +1016,8 @@ defineSuite([ it('renders wall 2', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -1015,7 +1025,8 @@ defineSuite([ it('renders wall 3', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateRight(-CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateRight(-CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -1023,7 +1034,8 @@ defineSuite([ it('renders wall 4', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateRight(CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateRight(CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -1060,7 +1072,8 @@ defineSuite([ viewSphere3D(frameState.camera, primitive._boundingSphere, primitive.modelMatrix); var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO); frameState.camera.moveForward(primitive._boundingSphere.radius * 0.75); context.uniformState.update(context, frameState); @@ -1100,7 +1113,8 @@ defineSuite([ afterView3D = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO); frameState.camera.zoomIn(primitive._boundingSphere.radius * 0.99); }; @@ -1251,7 +1265,8 @@ defineSuite([ var transform = Matrix4.multiplyByTranslation( Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center), new Cartesian3(0.0, 0.0, height), new Matrix4()); - frameState.camera.rotateDown(CesiumMath.PI, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(CesiumMath.PI); }; render3D(instance, afterView); }); @@ -1259,7 +1274,8 @@ defineSuite([ it('renders north wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -1267,7 +1283,8 @@ defineSuite([ it('renders south wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateDown(CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -1275,7 +1292,8 @@ defineSuite([ it('renders west wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateRight(-CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateRight(-CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -1283,7 +1301,8 @@ defineSuite([ it('renders east wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateRight(CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateRight(CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -1343,7 +1362,8 @@ defineSuite([ var transform = Matrix4.multiplyByTranslation( Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center), new Cartesian3(0.0, 0.0, height), new Matrix4()); - frameState.camera.rotateDown(CesiumMath.PI, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(CesiumMath.PI); }; render3D(instance, afterView); }); @@ -1351,7 +1371,8 @@ defineSuite([ it('renders north wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(-CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -1359,7 +1380,8 @@ defineSuite([ it('renders south wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateDown(CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateDown(CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -1367,7 +1389,8 @@ defineSuite([ it('renders west wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateRight(-CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateRight(-CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); @@ -1375,7 +1398,8 @@ defineSuite([ it('renders east wall', function() { var afterView = function(frameState, primitive) { var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); - frameState.camera.rotateRight(CesiumMath.PI_OVER_TWO, transform); + frameState.camera.setTransform(transform); + frameState.camera.rotateRight(CesiumMath.PI_OVER_TWO); }; render3D(instance, afterView); }); diff --git a/Specs/Scene/ModelSpec.js b/Specs/Scene/ModelSpec.js index a227f2307df5..67e023a9f3e2 100644 --- a/Specs/Scene/ModelSpec.js +++ b/Specs/Scene/ModelSpec.js @@ -88,10 +88,6 @@ defineSuite([ camera.transform = transform; camera.constrainedAxis = Cartesian3.UNIT_Z; - var controller = scene.screenSpaceCameraController; - controller.ellipsoid = Ellipsoid.UNIT_SPHERE; - controller.enableTilt = false; - // Zoom in var r = Math.max(model.boundingSphere.radius, camera.frustum.near); camera.lookAt( diff --git a/Specs/Scene/ScreenSpaceCameraControllerSpec.js b/Specs/Scene/ScreenSpaceCameraControllerSpec.js index 21f51bde8e68..1e44f6f231f2 100644 --- a/Specs/Scene/ScreenSpaceCameraControllerSpec.js +++ b/Specs/Scene/ScreenSpaceCameraControllerSpec.js @@ -40,12 +40,20 @@ defineSuite([ "use strict"; /*global jasmine,describe,xdescribe,it,xit,expect,beforeEach,afterEach,beforeAll,afterAll,spyOn,runs,waits,waitsFor*/ + var scene; var canvas; var camera; var controller; var MouseButtons = MockCanvas.MouseButtons; + var MockScene = function(canvas, camera, ellipsoid) { + this.canvas = canvas; + this.camera = camera; + this.globe = undefined; + this.mapProjection = new GeographicProjection(ellipsoid); + }; + beforeEach(function() { // create a mock canvas object to add events to so they are callable. canvas = new MockCanvas(); @@ -64,34 +72,24 @@ defineSuite([ near : 1.0, far : 500000000.0 }); - controller = new ScreenSpaceCameraController(canvas, camera); + + scene = new MockScene(canvas, camera, Ellipsoid.WGS84); + controller = new ScreenSpaceCameraController(scene); }); afterEach(function() { controller = controller && !controller.isDestroyed() && controller.destroy(); }); - it('constructor throws without a canvas', function() { + it('constructor throws without a scene', function() { expect(function() { return new ScreenSpaceCameraController(); }).toThrowDeveloperError(); }); - it('constructor throws without a camera', function() { - expect(function() { - return new ScreenSpaceCameraController(new MockCanvas()); - }).toThrowDeveloperError(); - }); - - it('get/set ellipsoid', function() { - expect(controller.ellipsoid).toEqual(Ellipsoid.WGS84); - controller.ellipsoid = Ellipsoid.UNIT_SPHERE; - expect(controller.ellipsoid).toEqual(Ellipsoid.UNIT_SPHERE); - }); - function updateController(frameState) { camera.update(frameState.mode); - controller.update(frameState.mode); + controller.update(frameState); } function setUp2D() { @@ -540,12 +538,14 @@ defineSuite([ var startPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2); var endPosition = new Cartesian2(3 * canvas.clientWidth / 8, 3 * canvas.clientHeight / 8); + camera.position.y = -100.0; + MockCanvas.moveMouse(canvas, MouseButtons.MIDDLE, startPosition, endPosition); updateController(frameState); expect(Cartesian3.dot(Cartesian3.normalize(camera.position, new Cartesian3()), Cartesian3.UNIT_Z)).toBeGreaterThan(0.0); expect(Cartesian3.dot(camera.direction, Cartesian3.UNIT_Z)).toBeLessThan(0.0); expect(Cartesian3.dot(camera.up, Cartesian3.UNIT_Z)).toBeGreaterThan(0.0); - expect(Cartesian3.dot(camera.right, Cartesian3.UNIT_Z)).toBeLessThan(CesiumMath.EPSILON7); + expect(Cartesian3.dot(camera.right, Cartesian3.UNIT_Z)).toBeLessThan(CesiumMath.EPSILON6); }); it('rotates in Columus view with camera transform set', function() { @@ -669,21 +669,6 @@ defineSuite([ expect(Cartesian3.cross(camera.right, camera.direction, new Cartesian3())).toEqualEpsilon(camera.up, CesiumMath.EPSILON14); }); - it('rotates in 3D', function() { - var frameState = setUp3D(); - var position = Cartesian3.clone(camera.position); - var startPosition = new Cartesian2(0, 0); - var endPosition = new Cartesian2(canvas.clientWidth / 4, canvas.clientHeight / 4); - - MockCanvas.moveMouse(canvas, MouseButtons.LEFT, startPosition, endPosition); - updateController(frameState); - - expect(camera.position).not.toEqual(position); - expect(camera.direction).toEqualEpsilon(Cartesian3.normalize(Cartesian3.negate(camera.position, new Cartesian3()), new Cartesian3()), CesiumMath.EPSILON15); - expect(Cartesian3.cross(camera.direction, camera.up, new Cartesian3())).toEqualEpsilon(camera.right, CesiumMath.EPSILON15); - expect(Cartesian3.cross(camera.right, camera.direction, new Cartesian3())).toEqualEpsilon(camera.up, CesiumMath.EPSILON15); - }); - it('zoom in 3D', function() { var frameState = setUp3D(); var position = Cartesian3.clone(camera.position); @@ -767,25 +752,6 @@ defineSuite([ expect(intersection).toBeDefined(); }); - it('tilts when the view direction does not intersect the ellipsoid', function() { - var frameState = setUp3D(); - var position = Cartesian3.clone(camera.position); - var startPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2); - var endPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 4); - - camera.lookRight(CesiumMath.PI_OVER_TWO); - var ray = new Ray(camera.positionWC, camera.directionWC); - var intersection = IntersectionTests.rayEllipsoid(ray, frameState.mapProjection.ellipsoid); - expect(intersection).not.toBeDefined(); - - MockCanvas.moveMouse(canvas, MouseButtons.MIDDLE, startPosition, endPosition); - updateController(frameState); - expect(camera.position).not.toEqual(position); - expect(camera.direction).not.toEqualEpsilon(Cartesian3.normalize(Cartesian3.negate(camera.position, new Cartesian3()), new Cartesian3()), CesiumMath.EPSILON14); - expect(Cartesian3.cross(camera.direction, camera.up, new Cartesian3())).toEqualEpsilon(camera.right, CesiumMath.EPSILON14); - expect(Cartesian3.cross(camera.right, camera.direction, new Cartesian3())).toEqualEpsilon(camera.up, CesiumMath.EPSILON14); - }); - it('does not tilt in the wrong direction', function() { var frameState = setUp3D(); var position = Cartesian3.clone(camera.position); @@ -814,7 +780,7 @@ defineSuite([ updateController(frameState); var height = Ellipsoid.WGS84.cartesianToCartographic(camera.position).height; - expect(height).toBeLessThan(controller.minimumZoomDistance); + expect(height).toBeLessThan(controller.minimumZoomDistance + 10.0); expect(Cartesian3.cross(camera.direction, camera.up, new Cartesian3())).toEqualEpsilon(camera.right, CesiumMath.EPSILON14); expect(Cartesian3.cross(camera.right, camera.direction, new Cartesian3())).toEqualEpsilon(camera.up, CesiumMath.EPSILON14); }); @@ -855,24 +821,6 @@ defineSuite([ expect(camera.up).toEqualEpsilon(Cartesian3.cross(camera.right, camera.direction, new Cartesian3()), CesiumMath.EPSILON14); }); - it('rotates with constrained axis', function() { - var frameState = setUp3D(); - - var axis = Cartesian3.clone(Cartesian3.UNIT_Z); - camera.constrainedAxis = axis; - - var startPosition = new Cartesian2(0.0, 0.0); - var endPosition = new Cartesian2(0.0, canvas.clientHeight); - - MockCanvas.moveMouse(canvas, MouseButtons.LEFT, startPosition, endPosition); - updateController(frameState); - - expect(camera.position.z).toEqualEpsilon(Cartesian3.magnitude(camera.position), CesiumMath.EPSILON1); - expect(camera.direction).toEqualEpsilon(Cartesian3.negate(axis, new Cartesian3()), CesiumMath.EPSILON4); - expect(Cartesian3.dot(camera.up, axis)).toBeLessThan(CesiumMath.EPSILON2); - expect(camera.right).toEqualEpsilon(Cartesian3.cross(camera.direction, camera.up, new Cartesian3()), CesiumMath.EPSILON4); - }); - it('pans with constrained axis and is tilted', function() { var frameState = setUp3D(); camera.position = new Cartesian3(0.0, 2.0 * Ellipsoid.WGS84.maximumRadius, 0.0); @@ -895,28 +843,6 @@ defineSuite([ expect(camera.up).toEqualEpsilon(Cartesian3.cross(camera.right, camera.direction, new Cartesian3()), CesiumMath.EPSILON12); }); - it('rotates with constrained axis and is tilted', function() { - var frameState = setUp3D(); - camera.position = new Cartesian3(0.0, 2.0 * Ellipsoid.WGS84.maximumRadius, 0.0); - camera.direction = Cartesian3.negate(Cartesian3.normalize(camera.position, new Cartesian3()), new Cartesian3()); - camera.up = Cartesian3.clone(Cartesian3.UNIT_X); - camera.right = Cartesian3.cross(camera.direction, camera.up, new Cartesian3()); - - var axis = Cartesian3.clone(Cartesian3.UNIT_Z); - camera.constrainedAxis = axis; - - var startPosition = new Cartesian2(0.0, 0.0); - var endPosition = new Cartesian2(0.0, canvas.clientHeight); - - MockCanvas.moveMouse(canvas, MouseButtons.LEFT, startPosition, endPosition); - updateController(frameState); - - expect(Cartesian3.dot(Cartesian3.normalize(camera.position, new Cartesian3()), axis)).toEqualEpsilon(1.0, CesiumMath.EPSILON2); - expect(camera.direction).toEqualEpsilon(Cartesian3.negate(Cartesian3.normalize(camera.position, new Cartesian3()), new Cartesian3()), CesiumMath.EPSILON15); - expect(camera.right).toEqualEpsilon(Cartesian3.negate(Cartesian3.UNIT_Y, new Cartesian3()), CesiumMath.EPSILON4); - expect(camera.up).toEqualEpsilon(Cartesian3.cross(camera.right, camera.direction, new Cartesian3()), CesiumMath.EPSILON15); - }); - it('controller does not modify the camera after re-enabling motion', function() { var frameState = setUp3D(); var position = Cartesian3.clone(camera.position); diff --git a/Specs/Widgets/Geocoder/GeocoderSpec.js b/Specs/Widgets/Geocoder/GeocoderSpec.js index 92d550cb2ff7..d4b133cc62b9 100644 --- a/Specs/Widgets/Geocoder/GeocoderSpec.js +++ b/Specs/Widgets/Geocoder/GeocoderSpec.js @@ -1,12 +1,10 @@ /*global defineSuite*/ defineSuite([ 'Widgets/Geocoder/Geocoder', - 'Core/Ellipsoid', 'Specs/createScene', 'Specs/destroyScene' ], function( Geocoder, - Ellipsoid, createScene, destroyScene) { "use strict"; @@ -22,7 +20,6 @@ defineSuite([ }); it('constructor sets expected properties', function() { - var ellipsoid = new Ellipsoid(); var flightDuration = 1234; var url = 'bing.invalid/'; var key = 'testKey'; @@ -30,7 +27,6 @@ defineSuite([ var geocoder = new Geocoder({ container : document.body, scene : scene, - ellipsoid : ellipsoid, flightDuration : flightDuration, url : url, key : key @@ -38,7 +34,6 @@ defineSuite([ var viewModel = geocoder.viewModel; expect(viewModel.scene).toBe(scene); - expect(viewModel.ellipsoid).toBe(ellipsoid); expect(viewModel.flightDuration).toBe(flightDuration); expect(viewModel.url).toBe(url); expect(viewModel.key).toBe(key); @@ -88,4 +83,4 @@ defineSuite([ }); }).toThrowDeveloperError(); }); -}, 'WebGL'); \ No newline at end of file +}, 'WebGL'); diff --git a/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js b/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js index 2b12e8e85a22..52d1db14b68f 100644 --- a/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js +++ b/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js @@ -2,13 +2,11 @@ defineSuite([ 'Widgets/Geocoder/GeocoderViewModel', 'Core/Cartesian3', - 'Core/Ellipsoid', 'Specs/createScene', 'Specs/destroyScene' ], function( GeocoderViewModel, Cartesian3, - Ellipsoid, createScene, destroyScene) { "use strict"; @@ -24,21 +22,18 @@ defineSuite([ }); it('constructor sets expected properties', function() { - var ellipsoid = new Ellipsoid(); var flightDuration = 1234; var url = 'bing.invalid/'; var key = 'testKey'; var viewModel = new GeocoderViewModel({ scene : scene, - ellipsoid : ellipsoid, flightDuration : flightDuration, url : url, key : key }); expect(viewModel.scene).toBe(scene); - expect(viewModel.ellipsoid).toBe(ellipsoid); expect(viewModel.flightDuration).toBe(flightDuration); expect(viewModel.url).toBe(url); expect(viewModel.key).toBe(key); @@ -86,4 +81,4 @@ defineSuite([ return new GeocoderViewModel(); }).toThrowDeveloperError(); }); -}, 'WebGL'); \ No newline at end of file +}, 'WebGL'); diff --git a/Specs/Widgets/HomeButton/HomeButtonSpec.js b/Specs/Widgets/HomeButton/HomeButtonSpec.js index f775b4263a45..4b257962146f 100644 --- a/Specs/Widgets/HomeButton/HomeButtonSpec.js +++ b/Specs/Widgets/HomeButton/HomeButtonSpec.js @@ -1,12 +1,10 @@ /*global defineSuite*/ defineSuite([ 'Widgets/HomeButton/HomeButton', - 'Core/Ellipsoid', 'Specs/createScene', 'Specs/destroyScene' ], function( HomeButton, - Ellipsoid, createScene, destroyScene) { "use strict"; @@ -25,18 +23,15 @@ defineSuite([ var homeButton = new HomeButton(document.body, scene); expect(homeButton.container).toBe(document.body); expect(homeButton.viewModel.scene).toBe(scene); - expect(homeButton.viewModel.ellipsoid).toBe(Ellipsoid.WGS84); expect(homeButton.isDestroyed()).toEqual(false); homeButton.destroy(); expect(homeButton.isDestroyed()).toEqual(true); }); it('constructor sets expected values', function() { - var ellipsoid = new Ellipsoid(); - var homeButton = new HomeButton(document.body, scene, ellipsoid); + var homeButton = new HomeButton(document.body, scene); expect(homeButton.container).toBe(document.body); expect(homeButton.viewModel.scene).toBe(scene); - expect(homeButton.viewModel.ellipsoid).toBe(ellipsoid); homeButton.destroy(); }); @@ -61,4 +56,4 @@ defineSuite([ return new HomeButton('testElement', scene); }).toThrowDeveloperError(); }); -}, 'WebGL'); \ No newline at end of file +}, 'WebGL'); diff --git a/Specs/Widgets/HomeButton/HomeButtonViewModelSpec.js b/Specs/Widgets/HomeButton/HomeButtonViewModelSpec.js index f44e306a3535..b0ede7faa302 100644 --- a/Specs/Widgets/HomeButton/HomeButtonViewModelSpec.js +++ b/Specs/Widgets/HomeButton/HomeButtonViewModelSpec.js @@ -29,14 +29,6 @@ defineSuite([ it('constructor sets default values', function() { var viewModel = new HomeButtonViewModel(scene); expect(viewModel.scene).toBe(scene); - expect(viewModel.ellipsoid).toBe(Ellipsoid.WGS84); - }); - - it('constructor sets expected values', function() { - var ellipsoid = new Ellipsoid(); - var viewModel = new HomeButtonViewModel(scene, ellipsoid); - expect(viewModel.scene).toBe(scene); - expect(viewModel.ellipsoid).toBe(ellipsoid); }); it('throws if scene is undefined', function() {