Skip to content

Commit 5a7491b

Browse files
authored
Merge pull request #4990 from AnalyticalGraphicsInc/pick-position
Scene.pickPosition in 2D/CV
2 parents 668d678 + 4d29924 commit 5a7491b

File tree

6 files changed

+150
-28
lines changed

6 files changed

+150
-28
lines changed

Apps/Sandcastle/gallery/Picking.html

+5-10
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,16 @@
174174
}
175175
});
176176

177-
var sceneModeWarningPosted = false;
178-
179177
// Mouse over the globe to see the cartographic position
180178
handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
181179
handler.setInputAction(function(movement) {
180+
182181
var foundPosition = false;
183182

184183
var scene = viewer.scene;
185-
var pickedObject = scene.pick(movement.endPosition);
186-
if (scene.pickPositionSupported && Cesium.defined(pickedObject) && pickedObject.id === modelEntity) {
187-
if (scene.mode === Cesium.SceneMode.SCENE3D) {
184+
if (scene.mode !== Cesium.SceneMode.MORPHING) {
185+
var pickedObject = scene.pick(movement.endPosition);
186+
if (scene.pickPositionSupported && Cesium.defined(pickedObject) && pickedObject.id === modelEntity) {
188187
var cartesian = viewer.scene.pickPosition(movement.endPosition);
189188

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

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

206204
foundPosition = true;
207205
}
208-
} else if (!sceneModeWarningPosted) {
209-
sceneModeWarningPosted = true;
210-
console.log("pickPosition is currently only supported in 3D mode.");
211206
}
212207
}
213208

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Change Log
2323
* 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)
2424
* Fixed exception in 2D in certain cases with polylines when rotating the map. [#4619](https://github.com/AnalyticalGraphicsInc/cesium/issues/4619)
2525
* Fixed an issue with constant `VertexArray` attributes not being set correctly. [#4995](https://github.com/AnalyticalGraphicsInc/cesium/pull/4995)
26+
* Add support for `Scene.pickPosition` in Columbus view and 2D. [#4990](https://github.com/AnalyticalGraphicsInc/cesium/pull/4990)
2627

2728
### 1.30 - 2017-02-01
2829

Source/Scene/Scene.js

+58-10
Original file line numberDiff line numberDiff line change
@@ -2701,15 +2701,18 @@ define([
27012701

27022702
/**
27032703
* Returns the cartesian position reconstructed from the depth buffer and window position.
2704+
* The returned position is in world coordinates. Used internally by camera functions to
2705+
* prevent conversion to projected 2D coordinates and then back.
2706+
*
2707+
* @private
27042708
*
27052709
* @param {Cartesian2} windowPosition Window coordinates to perform picking on.
27062710
* @param {Cartesian3} [result] The object on which to restore the result.
2707-
* @returns {Cartesian3} The cartesian position.
2711+
* @returns {Cartesian3} The cartesian position in world coordinates.
27082712
*
27092713
* @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
2710-
* @exception {DeveloperError} 2D is not supported. An orthographic projection matrix is not invertible.
27112714
*/
2712-
Scene.prototype.pickPosition = function(windowPosition, result) {
2715+
Scene.prototype.pickPositionWorldCoordinates = function(windowPosition, result) {
27132716
if (!this.useDepthPicking) {
27142717
return undefined;
27152718
}
@@ -2738,9 +2741,7 @@ define([
27382741
} else if (defined(camera.frustum.infiniteProjectionMatrix)){
27392742
frustum = camera.frustum.clone(scratchPerspectiveOffCenterFrustum);
27402743
} else {
2741-
//>>includeStart('debug', pragmas.debug);
2742-
throw new DeveloperError('2D is not supported. An orthographic projection matrix is not invertible.');
2743-
//>>includeEnd('debug');
2744+
frustum = camera.frustum.clone(scratchOrthographicFrustum);
27442745
}
27452746

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

27612762
if (depth > 0.0 && depth < 1.0) {
27622763
var renderedFrustum = this._frustumCommandsList[i];
2763-
frustum.near = renderedFrustum.near * (i !== 0 ? OPAQUE_FRUSTUM_NEAR_OFFSET : 1.0);
2764-
frustum.far = renderedFrustum.far;
2765-
uniformState.updateFrustum(frustum);
2764+
var height2D;
2765+
if (this.mode === SceneMode.SCENE2D) {
2766+
height2D = camera.position.z;
2767+
camera.position.z = height2D - renderedFrustum.near + 1.0;
2768+
frustum.far = Math.max(1.0, renderedFrustum.far - renderedFrustum.near);
2769+
frustum.near = 1.0;
2770+
uniformState.update(this.frameState);
2771+
uniformState.updateFrustum(frustum);
2772+
} else {
2773+
frustum.near = renderedFrustum.near * (i !== 0 ? OPAQUE_FRUSTUM_NEAR_OFFSET : 1.0);
2774+
frustum.far = renderedFrustum.far;
2775+
uniformState.updateFrustum(frustum);
2776+
}
2777+
2778+
result = SceneTransforms.drawingBufferToWgs84Coordinates(this, drawingBufferPosition, depth, result);
27662779

2767-
return SceneTransforms.drawingBufferToWgs84Coordinates(this, drawingBufferPosition, depth, result);
2780+
if (this.mode === SceneMode.SCENE2D) {
2781+
camera.position.z = height2D;
2782+
uniformState.update(this.frameState);
2783+
}
2784+
2785+
return result;
27682786
}
27692787
}
27702788

27712789
return undefined;
27722790
};
27732791

2792+
var scratchPickPositionCartographic = new Cartographic();
2793+
2794+
/**
2795+
* Returns the cartesian position reconstructed from the depth buffer and window position.
2796+
* <p>
2797+
* The position reconstructed from the depth buffer in 2D may be slightly different from those
2798+
* reconstructed in 3D and Columbus view. This is caused by the difference in the distribution
2799+
* of depth values of perspective and orthographic projection.
2800+
* </p>
2801+
*
2802+
* @param {Cartesian2} windowPosition Window coordinates to perform picking on.
2803+
* @param {Cartesian3} [result] The object on which to restore the result.
2804+
* @returns {Cartesian3} The cartesian position.
2805+
*
2806+
* @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
2807+
*/
2808+
Scene.prototype.pickPosition = function(windowPosition, result) {
2809+
result = this.pickPositionWorldCoordinates(windowPosition, result);
2810+
if (defined(result) && this.mode !== SceneMode.SCENE3D) {
2811+
Cartesian3.fromElements(result.y, result.z, result.x, result);
2812+
2813+
var projection = this.mapProjection;
2814+
var ellipsoid = projection.ellipsoid;
2815+
2816+
var cart = projection.unproject(result, scratchPickPositionCartographic);
2817+
ellipsoid.cartographicToCartesian(cart, result);
2818+
}
2819+
return result;
2820+
};
2821+
27742822
/**
27752823
* Returns a list of objects, each containing a `primitive` property, for all primitives at
27762824
* a particular window coordinate position. Other properties may also be set depending on the

Source/Scene/SceneTransforms.js

+18-5
Original file line numberDiff line numberDiff line change
@@ -320,11 +320,24 @@ define([
320320
ndc.z = (depth * 2.0) - 1.0;
321321
ndc.w = 1.0;
322322

323-
var worldCoords = Matrix4.multiplyByVector(uniformState.inverseViewProjection, ndc, scratchWorldCoords);
324-
325-
// Reverse perspective divide
326-
var w = 1.0 / worldCoords.w;
327-
Cartesian3.multiplyByScalar(worldCoords, w, worldCoords);
323+
var worldCoords;
324+
var frustum = scene.camera.frustum;
325+
if (!defined(frustum.fovy)) {
326+
var currentFrustum = uniformState.currentFrustum;
327+
worldCoords = scratchWorldCoords;
328+
worldCoords.x = (ndc.x * (frustum.right - frustum.left) + frustum.left + frustum.right) * 0.5;
329+
worldCoords.y = (ndc.y * (frustum.top - frustum.bottom) + frustum.bottom + frustum.top) * 0.5;
330+
worldCoords.z = (ndc.z * (currentFrustum.x - currentFrustum.y) - currentFrustum.x - currentFrustum.y) * 0.5;
331+
worldCoords.w = 1.0;
332+
333+
worldCoords = Matrix4.multiplyByVector(uniformState.inverseView, worldCoords, worldCoords);
334+
} else {
335+
worldCoords = Matrix4.multiplyByVector(uniformState.inverseViewProjection, ndc, scratchWorldCoords);
336+
337+
// Reverse perspective divide
338+
var w = 1.0 / worldCoords.w;
339+
Cartesian3.multiplyByScalar(worldCoords, w, worldCoords);
340+
}
328341

329342
return Cartesian3.fromCartesian4(worldCoords, result);
330343
};

Source/Scene/ScreenSpaceCameraController.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ define([
806806

807807
var depthIntersection;
808808
if (scene.pickPositionSupported) {
809-
depthIntersection = scene.pickPosition(mousePosition, scratchDepthIntersection);
809+
depthIntersection = scene.pickPositionWorldCoordinates(mousePosition, scratchDepthIntersection);
810810
}
811811

812812
var ray = camera.getPickRay(mousePosition, pickGlobeScratchRay);

Specs/Scene/SceneSpec.js

+67-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ defineSuite([
88
'Core/Ellipsoid',
99
'Core/GeographicProjection',
1010
'Core/GeometryInstance',
11+
'Core/Math',
1112
'Core/PixelFormat',
1213
'Core/Rectangle',
1314
'Core/RectangleGeometry',
@@ -43,6 +44,7 @@ defineSuite([
4344
Ellipsoid,
4445
GeographicProjection,
4546
GeometryInstance,
47+
CesiumMath,
4648
PixelFormat,
4749
Rectangle,
4850
RectangleGeometry,
@@ -82,7 +84,7 @@ defineSuite([
8284
scene.debugCommandFilter = undefined;
8385
scene.fxaa = false;
8486
scene.primitives.removeAll();
85-
scene.morphTo3D();
87+
scene.morphTo3D(0.0);
8688
});
8789

8890
afterAll(function() {
@@ -628,6 +630,9 @@ defineSuite([
628630
scene.destroyForSpecs();
629631
});
630632

633+
var pickedPosition3D = new Cartesian3(-455845.46867895435, -5210337.548977215, 3637549.8562320103);
634+
var pickedPosition2D = new Cartesian3(-455861.7055871038, -5210523.137686572, 3637866.6638769475);
635+
631636
it('pickPosition', function() {
632637
if (!scene.pickPositionSupported) {
633638
return;
@@ -652,7 +657,67 @@ defineSuite([
652657

653658
expect(scene).toRenderAndCall(function() {
654659
var position = scene.pickPosition(windowPosition);
655-
expect(position).toBeDefined();
660+
expect(position).toEqualEpsilon(pickedPosition3D, CesiumMath.EPSILON6);
661+
});
662+
});
663+
664+
it('pickPosition in CV', function() {
665+
if (!scene.pickPositionSupported) {
666+
return;
667+
}
668+
669+
scene.morphToColumbusView(0.0);
670+
671+
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
672+
scene.camera.setView({ destination : rectangle });
673+
674+
var canvas = scene.canvas;
675+
var windowPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
676+
677+
expect(scene).toRenderAndCall(function() {
678+
var position = scene.pickPosition(windowPosition);
679+
expect(position).not.toBeDefined();
680+
681+
var rectanglePrimitive = createRectangle(rectangle);
682+
rectanglePrimitive.appearance.material.uniforms.color = new Color(1.0, 0.0, 0.0, 1.0);
683+
684+
var primitives = scene.primitives;
685+
primitives.add(rectanglePrimitive);
686+
});
687+
688+
expect(scene).toRenderAndCall(function() {
689+
var position = scene.pickPosition(windowPosition);
690+
expect(position).toEqualEpsilon(pickedPosition2D, CesiumMath.EPSILON6);
691+
});
692+
});
693+
694+
it('pickPosition in 2D', function() {
695+
if (!scene.pickPositionSupported) {
696+
return;
697+
}
698+
699+
scene.morphTo2D(0.0);
700+
701+
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
702+
scene.camera.setView({ destination : rectangle });
703+
704+
var canvas = scene.canvas;
705+
var windowPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
706+
707+
expect(scene).toRenderAndCall(function() {
708+
var position = scene.pickPosition(windowPosition);
709+
expect(position).not.toBeDefined();
710+
711+
var rectanglePrimitive = createRectangle(rectangle);
712+
rectanglePrimitive.appearance.material.uniforms.color = new Color(1.0, 0.0, 0.0, 1.0);
713+
714+
var primitives = scene.primitives;
715+
primitives.add(rectanglePrimitive);
716+
});
717+
718+
expect(scene).toRenderAndCall(function() {
719+
var position = scene.pickPosition(windowPosition);
720+
expect(position).toEqualEpsilon(pickedPosition2D, CesiumMath.EPSILON6);
656721
});
657722
});
658723

0 commit comments

Comments
 (0)