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() {