diff --git a/CHANGES.md b/CHANGES.md index c3436b393378..66d260087f3f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,7 @@ Change Log * Fix "Cannot read property 'x' of undefined" error when calling SceneTransforms.wgs84ToWindowCoordinates in certain cases. [#4022](https://github.com/AnalyticalGraphicsInc/cesium/pull/4022) * Exposed a parametric ray-triangle intersection test to the API as `IntersectionTests.rayTriangleParametric`. * Added `unsupportedNodeEvent` to `KmlDataSource` that is fired whenever an unsupported node is encountered. +* Zooming in toward some target point now keeps the target point at the same screen position. [#4016](https://github.com/AnalyticalGraphicsInc/cesium/pull/4016) ### 1.22.2 - 2016-06-14 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 78c1f57d3aa8..86c648d1c9b9 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -56,6 +56,8 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu * [Sergio Flores](https://github.com/relfos) * [CubeWerx Inc.](http://www.cubewerx.com/) * [Keith Pomakis](https://github.com/pomakis) +* [Vricon](https://www.vricon.com/) + * [Erik Andersson](https://github.com/e-andersson) ## [Individual CLA](http://www.agi.com/licenses/individual-cla-agi-v1.0.txt) * [Victor Berchet](https://github.com/vicb) @@ -94,4 +96,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu * [Mati Ostrovsky](https://github.com/mati-o) * [Tom Novacek](https://github.com/novacto2) * [Olivier Guyot-Roullot](https://github.com/theOgrable) -* [Dave Whipps](https://github.com/dwhipps) \ No newline at end of file +* [Dave Whipps](https://github.com/dwhipps) diff --git a/Source/Scene/ScreenSpaceCameraController.js b/Source/Scene/ScreenSpaceCameraController.js index 07516af37da1..23af144ee69d 100644 --- a/Source/Scene/ScreenSpaceCameraController.js +++ b/Source/Scene/ScreenSpaceCameraController.js @@ -430,6 +430,21 @@ define([ var scratchZoomAxis = new Cartesian3(); var scratchCameraPositionNormal = new Cartesian3(); + // Scratch variables used in zooming algorithm + var scratchTargetNormal = new Cartesian3(); + var scratchCameraPosition = new Cartesian3(); + var scratchCameraUpNormal = new Cartesian3(); + var scratchCameraRightNormal = new Cartesian3(); + var scratchForwardNormal = new Cartesian3(); + var scratchPositionToTarget = new Cartesian3(); + var scratchPositionToTargetNormal = new Cartesian3(); + var scratchPan = new Cartesian3(); + var scratchCenterMovement = new Cartesian3(); + var scratchCenter = new Cartesian3(); + var scratchCartesian = new Cartesian3(); + var scratchCartesianTwo = new Cartesian3(); + var scratchCartesianThree = new Cartesian3(); + function handleZoom(object, startPosition, movement, zoomFactor, distanceMeasure, unitPositionDotDirection) { var percentage = 1.0; if (defined(unitPositionDotDirection)) { @@ -492,6 +507,10 @@ define([ var zoomOnVector = mode === SceneMode.COLUMBUS_VIEW; + if (camera.positionCartographic.height < 2000000) { + rotatingZoom = true; + } + if (!sameStartPosition || rotatingZoom) { if (mode === SceneMode.SCENE2D) { var worldPosition = object._zoomWorldPosition; @@ -522,7 +541,92 @@ define([ centerPixel.x = canvas.clientWidth / 2; centerPixel.y = canvas.clientHeight / 2; var centerPosition = pickGlobe(object, centerPixel, scratchCenterPosition); - if (defined(centerPosition)) { + // If centerPosition is not defined, it means the globe does not cover the center position of screen + + if (defined(centerPosition) && camera.positionCartographic.height < 1000000) { + + var cameraPosition = scratchCameraPosition; + Cartesian3.clone(camera.position, cameraPosition); + var target = object._zoomWorldPosition; + + var targetNormal = scratchTargetNormal; + + targetNormal = Cartesian3.normalize(target, targetNormal); + + if (Cartesian3.dot(targetNormal, cameraPositionNormal) < 0.0) { + return; + } + + var center = scratchCenter; + var forward = scratchForwardNormal; + Cartesian3.clone(camera.direction, forward); + Cartesian3.add(cameraPosition, Cartesian3.multiplyByScalar(forward, 1000, scratchCartesian), center); + + + var positionToTarget = scratchPositionToTarget; + var positionToTargetNormal = scratchPositionToTargetNormal; + Cartesian3.subtract(target, cameraPosition, positionToTarget); + + Cartesian3.normalize(positionToTarget, positionToTargetNormal); + + var alpha = Math.acos( -Cartesian3.dot( cameraPositionNormal, positionToTargetNormal ) ); + var cameraDistance = Cartesian3.magnitude( cameraPosition ); + var targetDistance = Cartesian3.magnitude( target ); + var remainingDistance = cameraDistance - distance; + var positionToTargetDistance = Cartesian3.magnitude(positionToTarget); + + var gamma = Math.asin( CesiumMath.clamp( positionToTargetDistance / targetDistance * Math.sin(alpha), -1.0, 1.0 ) ); + var delta = Math.asin( CesiumMath.clamp( remainingDistance / targetDistance * Math.sin(alpha), -1.0, 1.0 ) ); + var beta = gamma - delta + alpha; + + var up = scratchCameraUpNormal; + Cartesian3.normalize(cameraPosition, up); + var right = scratchCameraRightNormal; + right = Cartesian3.cross(positionToTargetNormal, up, right); + right = Cartesian3.normalize(right, right ); + + Cartesian3.normalize( Cartesian3.cross(up, right, scratchCartesian), forward ); + + // Calculate new position to move to + Cartesian3.multiplyByScalar(Cartesian3.normalize(center, scratchCartesian), (Cartesian3.magnitude(center) - distance), center); + Cartesian3.normalize(cameraPosition, cameraPosition); + Cartesian3.multiplyByScalar(cameraPosition, remainingDistance, cameraPosition); + + // Pan + var pMid = scratchPan; + Cartesian3.multiplyByScalar(Cartesian3.add( + Cartesian3.multiplyByScalar(up, Math.cos(beta) - 1, scratchCartesianTwo), + Cartesian3.multiplyByScalar(forward, Math.sin(beta), scratchCartesianThree), + scratchCartesian + ), remainingDistance, pMid); + Cartesian3.add(cameraPosition, pMid, cameraPosition); + + Cartesian3.normalize(center, up); + Cartesian3.normalize( Cartesian3.cross(up, right, scratchCartesian), forward ); + + var cMid = scratchCenterMovement; + Cartesian3.multiplyByScalar(Cartesian3.add( + Cartesian3.multiplyByScalar(up, Math.cos(beta) - 1, scratchCartesianTwo), + Cartesian3.multiplyByScalar(forward, Math.sin(beta), scratchCartesianThree), + scratchCartesian + ), Cartesian3.magnitude(center), cMid); + Cartesian3.add(center, cMid, center); + + // Update camera + + // Set new position + Cartesian3.clone(cameraPosition, camera.position); + + // Set new direction + Cartesian3.normalize(Cartesian3.subtract(center, cameraPosition, scratchCartesian), camera.direction); + Cartesian3.clone(camera.direction, camera.direction); + + // Set new right & up vectors + Cartesian3.cross(camera.direction, camera.up, camera.right); + Cartesian3.cross(camera.right, camera.direction, camera.up); + + return; + } else if (defined(centerPosition)) { var positionNormal = Cartesian3.normalize(centerPosition, scratchPositionNormal); var pickedNormal = Cartesian3.normalize(object._zoomWorldPosition, scratchPickNormal); var dotProduct = Cartesian3.dot(pickedNormal, positionNormal);