Skip to content

Commit

Permalink
Merge pull request #4990 from AnalyticalGraphicsInc/pick-position
Browse files Browse the repository at this point in the history
Scene.pickPosition in 2D/CV
  • Loading branch information
pjcozzi authored Feb 15, 2017
2 parents 668d678 + 4d29924 commit 5a7491b
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 28 deletions.
15 changes: 5 additions & 10 deletions Apps/Sandcastle/gallery/Picking.html
Original file line number Diff line number Diff line change
Expand Up @@ -174,17 +174,16 @@
}
});

var sceneModeWarningPosted = false;

// Mouse over the globe to see the cartographic position
handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function(movement) {

var foundPosition = false;

var scene = viewer.scene;
var pickedObject = scene.pick(movement.endPosition);
if (scene.pickPositionSupported && Cesium.defined(pickedObject) && pickedObject.id === modelEntity) {
if (scene.mode === Cesium.SceneMode.SCENE3D) {
if (scene.mode !== Cesium.SceneMode.MORPHING) {
var pickedObject = scene.pick(movement.endPosition);
if (scene.pickPositionSupported && Cesium.defined(pickedObject) && pickedObject.id === modelEntity) {
var cartesian = viewer.scene.pickPosition(movement.endPosition);

if (Cesium.defined(cartesian)) {
Expand All @@ -200,14 +199,10 @@
'\nLat: ' + (' ' + latitudeString).slice(-7) + '\u00B0' +
'\nAlt: ' + (' ' + heightString).slice(-7) + 'm';

var camera = scene.camera;
labelEntity.label.eyeOffset = new Cesium.Cartesian3(0.0, 0.0, camera.frustum.near * 1.5 - Cesium.Cartesian3.distance(cartesian, camera.position));
labelEntity.label.eyeOffset = new Cesium.Cartesian3(0.0, 0.0, -cartographic.height * (scene.mode === Cesium.SceneMode.SCENE2D ? 1.5 : 1.0));

foundPosition = true;
}
} else if (!sceneModeWarningPosted) {
sceneModeWarningPosted = true;
console.log("pickPosition is currently only supported in 3D mode.");
}
}

Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Change Log
* Fixed an issue where the camera would zoom past an object and flip to the other side of the globe. [#4967](https://github.com/AnalyticalGraphicsInc/cesium/pull/4967) and [#4982](https://github.com/AnalyticalGraphicsInc/cesium/pull/4982)
* Fixed exception in 2D in certain cases with polylines when rotating the map. [#4619](https://github.com/AnalyticalGraphicsInc/cesium/issues/4619)
* Fixed an issue with constant `VertexArray` attributes not being set correctly. [#4995](https://github.com/AnalyticalGraphicsInc/cesium/pull/4995)
* Add support for `Scene.pickPosition` in Columbus view and 2D. [#4990](https://github.com/AnalyticalGraphicsInc/cesium/pull/4990)

### 1.30 - 2017-02-01

Expand Down
68 changes: 58 additions & 10 deletions Source/Scene/Scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -2701,15 +2701,18 @@ define([

/**
* Returns the cartesian position reconstructed from the depth buffer and window position.
* The returned position is in world coordinates. Used internally by camera functions to
* prevent conversion to projected 2D coordinates and then back.
*
* @private
*
* @param {Cartesian2} windowPosition Window coordinates to perform picking on.
* @param {Cartesian3} [result] The object on which to restore the result.
* @returns {Cartesian3} The cartesian position.
* @returns {Cartesian3} The cartesian position in world coordinates.
*
* @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
* @exception {DeveloperError} 2D is not supported. An orthographic projection matrix is not invertible.
*/
Scene.prototype.pickPosition = function(windowPosition, result) {
Scene.prototype.pickPositionWorldCoordinates = function(windowPosition, result) {
if (!this.useDepthPicking) {
return undefined;
}
Expand Down Expand Up @@ -2738,9 +2741,7 @@ define([
} else if (defined(camera.frustum.infiniteProjectionMatrix)){
frustum = camera.frustum.clone(scratchPerspectiveOffCenterFrustum);
} else {
//>>includeStart('debug', pragmas.debug);
throw new DeveloperError('2D is not supported. An orthographic projection matrix is not invertible.');
//>>includeEnd('debug');
frustum = camera.frustum.clone(scratchOrthographicFrustum);
}

var numFrustums = this.numberOfFrustums;
Expand All @@ -2760,17 +2761,64 @@ define([

if (depth > 0.0 && depth < 1.0) {
var renderedFrustum = this._frustumCommandsList[i];
frustum.near = renderedFrustum.near * (i !== 0 ? OPAQUE_FRUSTUM_NEAR_OFFSET : 1.0);
frustum.far = renderedFrustum.far;
uniformState.updateFrustum(frustum);
var height2D;
if (this.mode === SceneMode.SCENE2D) {
height2D = camera.position.z;
camera.position.z = height2D - renderedFrustum.near + 1.0;
frustum.far = Math.max(1.0, renderedFrustum.far - renderedFrustum.near);
frustum.near = 1.0;
uniformState.update(this.frameState);
uniformState.updateFrustum(frustum);
} else {
frustum.near = renderedFrustum.near * (i !== 0 ? OPAQUE_FRUSTUM_NEAR_OFFSET : 1.0);
frustum.far = renderedFrustum.far;
uniformState.updateFrustum(frustum);
}

result = SceneTransforms.drawingBufferToWgs84Coordinates(this, drawingBufferPosition, depth, result);

return SceneTransforms.drawingBufferToWgs84Coordinates(this, drawingBufferPosition, depth, result);
if (this.mode === SceneMode.SCENE2D) {
camera.position.z = height2D;
uniformState.update(this.frameState);
}

return result;
}
}

return undefined;
};

var scratchPickPositionCartographic = new Cartographic();

/**
* Returns the cartesian position reconstructed from the depth buffer and window position.
* <p>
* The position reconstructed from the depth buffer in 2D may be slightly different from those
* reconstructed in 3D and Columbus view. This is caused by the difference in the distribution
* of depth values of perspective and orthographic projection.
* </p>
*
* @param {Cartesian2} windowPosition Window coordinates to perform picking on.
* @param {Cartesian3} [result] The object on which to restore the result.
* @returns {Cartesian3} The cartesian position.
*
* @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
*/
Scene.prototype.pickPosition = function(windowPosition, result) {
result = this.pickPositionWorldCoordinates(windowPosition, result);
if (defined(result) && this.mode !== SceneMode.SCENE3D) {
Cartesian3.fromElements(result.y, result.z, result.x, result);

var projection = this.mapProjection;
var ellipsoid = projection.ellipsoid;

var cart = projection.unproject(result, scratchPickPositionCartographic);
ellipsoid.cartographicToCartesian(cart, result);
}
return result;
};

/**
* Returns a list of objects, each containing a `primitive` property, for all primitives at
* a particular window coordinate position. Other properties may also be set depending on the
Expand Down
23 changes: 18 additions & 5 deletions Source/Scene/SceneTransforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,11 +320,24 @@ define([
ndc.z = (depth * 2.0) - 1.0;
ndc.w = 1.0;

var worldCoords = Matrix4.multiplyByVector(uniformState.inverseViewProjection, ndc, scratchWorldCoords);

// Reverse perspective divide
var w = 1.0 / worldCoords.w;
Cartesian3.multiplyByScalar(worldCoords, w, worldCoords);
var worldCoords;
var frustum = scene.camera.frustum;
if (!defined(frustum.fovy)) {
var currentFrustum = uniformState.currentFrustum;
worldCoords = scratchWorldCoords;
worldCoords.x = (ndc.x * (frustum.right - frustum.left) + frustum.left + frustum.right) * 0.5;
worldCoords.y = (ndc.y * (frustum.top - frustum.bottom) + frustum.bottom + frustum.top) * 0.5;
worldCoords.z = (ndc.z * (currentFrustum.x - currentFrustum.y) - currentFrustum.x - currentFrustum.y) * 0.5;
worldCoords.w = 1.0;

worldCoords = Matrix4.multiplyByVector(uniformState.inverseView, worldCoords, worldCoords);
} else {
worldCoords = Matrix4.multiplyByVector(uniformState.inverseViewProjection, ndc, scratchWorldCoords);

// Reverse perspective divide
var w = 1.0 / worldCoords.w;
Cartesian3.multiplyByScalar(worldCoords, w, worldCoords);
}

return Cartesian3.fromCartesian4(worldCoords, result);
};
Expand Down
2 changes: 1 addition & 1 deletion Source/Scene/ScreenSpaceCameraController.js
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,7 @@ define([

var depthIntersection;
if (scene.pickPositionSupported) {
depthIntersection = scene.pickPosition(mousePosition, scratchDepthIntersection);
depthIntersection = scene.pickPositionWorldCoordinates(mousePosition, scratchDepthIntersection);
}

var ray = camera.getPickRay(mousePosition, pickGlobeScratchRay);
Expand Down
69 changes: 67 additions & 2 deletions Specs/Scene/SceneSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defineSuite([
'Core/Ellipsoid',
'Core/GeographicProjection',
'Core/GeometryInstance',
'Core/Math',
'Core/PixelFormat',
'Core/Rectangle',
'Core/RectangleGeometry',
Expand Down Expand Up @@ -43,6 +44,7 @@ defineSuite([
Ellipsoid,
GeographicProjection,
GeometryInstance,
CesiumMath,
PixelFormat,
Rectangle,
RectangleGeometry,
Expand Down Expand Up @@ -82,7 +84,7 @@ defineSuite([
scene.debugCommandFilter = undefined;
scene.fxaa = false;
scene.primitives.removeAll();
scene.morphTo3D();
scene.morphTo3D(0.0);
});

afterAll(function() {
Expand Down Expand Up @@ -628,6 +630,9 @@ defineSuite([
scene.destroyForSpecs();
});

var pickedPosition3D = new Cartesian3(-455845.46867895435, -5210337.548977215, 3637549.8562320103);
var pickedPosition2D = new Cartesian3(-455861.7055871038, -5210523.137686572, 3637866.6638769475);

it('pickPosition', function() {
if (!scene.pickPositionSupported) {
return;
Expand All @@ -652,7 +657,67 @@ defineSuite([

expect(scene).toRenderAndCall(function() {
var position = scene.pickPosition(windowPosition);
expect(position).toBeDefined();
expect(position).toEqualEpsilon(pickedPosition3D, CesiumMath.EPSILON6);
});
});

it('pickPosition in CV', function() {
if (!scene.pickPositionSupported) {
return;
}

scene.morphToColumbusView(0.0);

var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
scene.camera.setView({ destination : rectangle });

var canvas = scene.canvas;
var windowPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);

expect(scene).toRenderAndCall(function() {
var position = scene.pickPosition(windowPosition);
expect(position).not.toBeDefined();

var rectanglePrimitive = createRectangle(rectangle);
rectanglePrimitive.appearance.material.uniforms.color = new Color(1.0, 0.0, 0.0, 1.0);

var primitives = scene.primitives;
primitives.add(rectanglePrimitive);
});

expect(scene).toRenderAndCall(function() {
var position = scene.pickPosition(windowPosition);
expect(position).toEqualEpsilon(pickedPosition2D, CesiumMath.EPSILON6);
});
});

it('pickPosition in 2D', function() {
if (!scene.pickPositionSupported) {
return;
}

scene.morphTo2D(0.0);

var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
scene.camera.setView({ destination : rectangle });

var canvas = scene.canvas;
var windowPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);

expect(scene).toRenderAndCall(function() {
var position = scene.pickPosition(windowPosition);
expect(position).not.toBeDefined();

var rectanglePrimitive = createRectangle(rectangle);
rectanglePrimitive.appearance.material.uniforms.color = new Color(1.0, 0.0, 0.0, 1.0);

var primitives = scene.primitives;
primitives.add(rectanglePrimitive);
});

expect(scene).toRenderAndCall(function() {
var position = scene.pickPosition(windowPosition);
expect(position).toEqualEpsilon(pickedPosition2D, CesiumMath.EPSILON6);
});
});

Expand Down

0 comments on commit 5a7491b

Please sign in to comment.