Skip to content

Commit e0e76ba

Browse files
authoredOct 15, 2018
Merge pull request #7113 from AnalyticalGraphicsInc/fix-pick-position
Fix pickPosition called after sampleHeight
2 parents 93b4615 + a238fce commit e0e76ba

File tree

5 files changed

+188
-91
lines changed

5 files changed

+188
-91
lines changed
 

‎CHANGES.md

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ Change Log
77
* Added WMS-T (time) support in WebMapServiceImageryProvider [#2581](https://github.com/AnalyticalGraphicsInc/cesium/issues/2581)
88
* Added `cutoutRectangle` to `ImageryLayer`, which allows cutting out rectangular areas in imagery layers to reveal underlying imagery. [#7056](https://github.com/AnalyticalGraphicsInc/cesium/pull/7056)
99

10+
##### Fixes :wrench:
11+
* Fixed an issue where `pickPosition` would return incorrect results when called after `sampleHeight` or `clampToHeight`. [#7113](https://github.com/AnalyticalGraphicsInc/cesium/pull/7113)
12+
1013
### 1.50 - 2018-10-01
1114

1215
##### Breaking Changes :mega:

‎Source/Core/Transforms.js

+88-88
Original file line numberDiff line numberDiff line change
@@ -120,94 +120,94 @@ define([
120120
* @return {localFrameToFixedFrameGenerator~resultat} The function that will computes a
121121
* 4x4 transformation matrix from a reference frame, with first axis and second axis compliant with the parameters,
122122
*/
123-
Transforms.localFrameToFixedFrameGenerator = function( firstAxis, secondAxis) {
124-
if (!vectorProductLocalFrame.hasOwnProperty(firstAxis) || !vectorProductLocalFrame[firstAxis].hasOwnProperty(secondAxis)) {
125-
throw new DeveloperError('firstAxis and secondAxis must be east, north, up, west, south or down.');
126-
}
127-
var thirdAxis = vectorProductLocalFrame[firstAxis][secondAxis];
128-
129-
/**
130-
* Computes a 4x4 transformation matrix from a reference frame
131-
* centered at the provided origin to the provided ellipsoid's fixed reference frame.
132-
* @callback Transforms~LocalFrameToFixedFrame
133-
* @param {Cartesian3} origin The center point of the local reference frame.
134-
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
135-
* @param {Matrix4} [result] The object onto which to store the result.
136-
* @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
137-
*/
138-
var resultat;
139-
var hashAxis = firstAxis + secondAxis;
140-
if (defined(localFrameToFixedFrameCache[hashAxis])) {
141-
resultat = localFrameToFixedFrameCache[hashAxis];
142-
} else {
143-
resultat = function(origin, ellipsoid, result) {
144-
//>>includeStart('debug', pragmas.debug);
145-
if (!defined(origin)) {
146-
throw new DeveloperError('origin is required.');
147-
}
148-
//>>includeEnd('debug');
149-
if (!defined(result)) {
150-
result = new Matrix4();
151-
}
152-
// If x and y are zero, assume origin is at a pole, which is a special case.
153-
if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) && CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) {
154-
var sign = CesiumMath.sign(origin.z);
155-
156-
Cartesian3.unpack(degeneratePositionLocalFrame[firstAxis], 0, scratchFirstCartesian);
157-
if (firstAxis !== 'east' && firstAxis !== 'west') {
158-
Cartesian3.multiplyByScalar(scratchFirstCartesian, sign, scratchFirstCartesian);
159-
}
160-
161-
Cartesian3.unpack(degeneratePositionLocalFrame[secondAxis], 0, scratchSecondCartesian);
162-
if (secondAxis !== 'east' && secondAxis !== 'west') {
163-
Cartesian3.multiplyByScalar(scratchSecondCartesian, sign, scratchSecondCartesian);
164-
}
165-
166-
Cartesian3.unpack(degeneratePositionLocalFrame[thirdAxis], 0, scratchThirdCartesian);
167-
if (thirdAxis !== 'east' && thirdAxis !== 'west') {
168-
Cartesian3.multiplyByScalar(scratchThirdCartesian, sign, scratchThirdCartesian);
169-
}
170-
} else {
171-
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
172-
ellipsoid.geodeticSurfaceNormal(origin, scratchCalculateCartesian.up);
173-
174-
var up = scratchCalculateCartesian.up;
175-
var east = scratchCalculateCartesian.east;
176-
east.x = -origin.y;
177-
east.y = origin.x;
178-
east.z = 0.0;
179-
Cartesian3.normalize(east, scratchCalculateCartesian.east);
180-
Cartesian3.cross(up, east, scratchCalculateCartesian.north);
181-
182-
Cartesian3.multiplyByScalar(scratchCalculateCartesian.up, -1, scratchCalculateCartesian.down);
183-
Cartesian3.multiplyByScalar(scratchCalculateCartesian.east, -1, scratchCalculateCartesian.west);
184-
Cartesian3.multiplyByScalar(scratchCalculateCartesian.north, -1, scratchCalculateCartesian.south);
185-
186-
scratchFirstCartesian = scratchCalculateCartesian[firstAxis];
187-
scratchSecondCartesian = scratchCalculateCartesian[secondAxis];
188-
scratchThirdCartesian = scratchCalculateCartesian[thirdAxis];
189-
}
190-
result[0] = scratchFirstCartesian.x;
191-
result[1] = scratchFirstCartesian.y;
192-
result[2] = scratchFirstCartesian.z;
193-
result[3] = 0.0;
194-
result[4] = scratchSecondCartesian.x;
195-
result[5] = scratchSecondCartesian.y;
196-
result[6] = scratchSecondCartesian.z;
197-
result[7] = 0.0;
198-
result[8] = scratchThirdCartesian.x;
199-
result[9] = scratchThirdCartesian.y;
200-
result[10] = scratchThirdCartesian.z;
201-
result[11] = 0.0;
202-
result[12] = origin.x;
203-
result[13] = origin.y;
204-
result[14] = origin.z;
205-
result[15] = 1.0;
206-
return result;
207-
};
208-
localFrameToFixedFrameCache[hashAxis] = resultat;
209-
}
210-
return resultat;
123+
Transforms.localFrameToFixedFrameGenerator = function (firstAxis, secondAxis) {
124+
if (!vectorProductLocalFrame.hasOwnProperty(firstAxis) || !vectorProductLocalFrame[firstAxis].hasOwnProperty(secondAxis)) {
125+
throw new DeveloperError('firstAxis and secondAxis must be east, north, up, west, south or down.');
126+
}
127+
var thirdAxis = vectorProductLocalFrame[firstAxis][secondAxis];
128+
129+
/**
130+
* Computes a 4x4 transformation matrix from a reference frame
131+
* centered at the provided origin to the provided ellipsoid's fixed reference frame.
132+
* @callback Transforms~LocalFrameToFixedFrame
133+
* @param {Cartesian3} origin The center point of the local reference frame.
134+
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
135+
* @param {Matrix4} [result] The object onto which to store the result.
136+
* @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
137+
*/
138+
var resultat;
139+
var hashAxis = firstAxis + secondAxis;
140+
if (defined(localFrameToFixedFrameCache[hashAxis])) {
141+
resultat = localFrameToFixedFrameCache[hashAxis];
142+
} else {
143+
resultat = function (origin, ellipsoid, result) {
144+
//>>includeStart('debug', pragmas.debug);
145+
if (!defined(origin)) {
146+
throw new DeveloperError('origin is required.');
147+
}
148+
//>>includeEnd('debug');
149+
if (!defined(result)) {
150+
result = new Matrix4();
151+
}
152+
// If x and y are zero, assume origin is at a pole, which is a special case.
153+
if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) && CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) {
154+
var sign = CesiumMath.sign(origin.z);
155+
156+
Cartesian3.unpack(degeneratePositionLocalFrame[firstAxis], 0, scratchFirstCartesian);
157+
if (firstAxis !== 'east' && firstAxis !== 'west') {
158+
Cartesian3.multiplyByScalar(scratchFirstCartesian, sign, scratchFirstCartesian);
159+
}
160+
161+
Cartesian3.unpack(degeneratePositionLocalFrame[secondAxis], 0, scratchSecondCartesian);
162+
if (secondAxis !== 'east' && secondAxis !== 'west') {
163+
Cartesian3.multiplyByScalar(scratchSecondCartesian, sign, scratchSecondCartesian);
164+
}
165+
166+
Cartesian3.unpack(degeneratePositionLocalFrame[thirdAxis], 0, scratchThirdCartesian);
167+
if (thirdAxis !== 'east' && thirdAxis !== 'west') {
168+
Cartesian3.multiplyByScalar(scratchThirdCartesian, sign, scratchThirdCartesian);
169+
}
170+
} else {
171+
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
172+
ellipsoid.geodeticSurfaceNormal(origin, scratchCalculateCartesian.up);
173+
174+
var up = scratchCalculateCartesian.up;
175+
var east = scratchCalculateCartesian.east;
176+
east.x = -origin.y;
177+
east.y = origin.x;
178+
east.z = 0.0;
179+
Cartesian3.normalize(east, scratchCalculateCartesian.east);
180+
Cartesian3.cross(up, east, scratchCalculateCartesian.north);
181+
182+
Cartesian3.multiplyByScalar(scratchCalculateCartesian.up, -1, scratchCalculateCartesian.down);
183+
Cartesian3.multiplyByScalar(scratchCalculateCartesian.east, -1, scratchCalculateCartesian.west);
184+
Cartesian3.multiplyByScalar(scratchCalculateCartesian.north, -1, scratchCalculateCartesian.south);
185+
186+
scratchFirstCartesian = scratchCalculateCartesian[firstAxis];
187+
scratchSecondCartesian = scratchCalculateCartesian[secondAxis];
188+
scratchThirdCartesian = scratchCalculateCartesian[thirdAxis];
189+
}
190+
result[0] = scratchFirstCartesian.x;
191+
result[1] = scratchFirstCartesian.y;
192+
result[2] = scratchFirstCartesian.z;
193+
result[3] = 0.0;
194+
result[4] = scratchSecondCartesian.x;
195+
result[5] = scratchSecondCartesian.y;
196+
result[6] = scratchSecondCartesian.z;
197+
result[7] = 0.0;
198+
result[8] = scratchThirdCartesian.x;
199+
result[9] = scratchThirdCartesian.y;
200+
result[10] = scratchThirdCartesian.z;
201+
result[11] = 0.0;
202+
result[12] = origin.x;
203+
result[13] = origin.y;
204+
result[14] = origin.z;
205+
result[15] = 1.0;
206+
return result;
207+
};
208+
localFrameToFixedFrameCache[hashAxis] = resultat;
209+
}
210+
return resultat;
211211
};
212212

213213
/**

‎Source/Scene/Scene.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -3400,6 +3400,7 @@ define([
34003400
return Cartesian3.clone(this._pickPositionCache[cacheKey], result);
34013401
}
34023402

3403+
var frameState = this._frameState;
34033404
var context = this._context;
34043405
var uniformState = context.uniformState;
34053406

@@ -3410,6 +3411,8 @@ define([
34103411
if (this.pickTranslucentDepth) {
34113412
renderTranslucentDepthForPick(this, drawingBufferPosition);
34123413
} else {
3414+
updateFrameState(this, frameState.frameNumber, frameState.time);
3415+
uniformState.update(frameState);
34133416
updateEnvironment(this);
34143417
}
34153418
drawingBufferPosition.y = this.drawingBufferHeight - drawingBufferPosition.y;
@@ -3441,7 +3444,7 @@ define([
34413444
camera.position.z = height2D - renderedFrustum.near + 1.0;
34423445
frustum.far = Math.max(1.0, renderedFrustum.far - renderedFrustum.near);
34433446
frustum.near = 1.0;
3444-
uniformState.update(this.frameState);
3447+
uniformState.update(frameState);
34453448
uniformState.updateFrustum(frustum);
34463449
} else {
34473450
frustum.near = renderedFrustum.near * (i !== 0 ? this.opaqueFrustumNearOffset : 1.0);
@@ -3453,7 +3456,7 @@ define([
34533456

34543457
if (this.mode === SceneMode.SCENE2D) {
34553458
camera.position.z = height2D;
3456-
uniformState.update(this.frameState);
3459+
uniformState.update(frameState);
34573460
}
34583461

34593462
this._pickPositionCache[cacheKey] = Cartesian3.clone(result);

‎Specs/Scene/PickSpec.js

+68-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
defineSuite([
22
'Core/Cartesian3',
33
'Core/Cartographic',
4+
'Core/Color',
45
'Core/Ellipsoid',
56
'Core/FeatureDetection',
67
'Core/GeometryInstance',
@@ -27,6 +28,7 @@ defineSuite([
2728
], 'Scene/Pick', function(
2829
Cartesian3,
2930
Cartographic,
31+
Color,
3032
Ellipsoid,
3133
FeatureDetection,
3234
GeometryInstance,
@@ -57,7 +59,7 @@ defineSuite([
5759
var camera;
5860
var largeRectangle = Rectangle.fromDegrees(-1.0, -1.0, 1.0, 1.0);
5961
var smallRectangle = Rectangle.fromDegrees(-0.0001, -0.0001, 0.0001, 0.0001);
60-
var offscreenRectangle = Rectangle.fromDegrees(-45.0, -1.0, -43.0, 1.0);
62+
var offscreenRectangle = Rectangle.fromDegrees(-45.0002, -1.0002, -45.0001, -1.0001);
6163
var primitiveRay;
6264
var offscreenRay;
6365

@@ -1081,4 +1083,69 @@ defineSuite([
10811083
scene.context._depthTexture = depthTexture;
10821084
});
10831085
});
1086+
1087+
it('calls multiple picking functions within the same frame', function() {
1088+
if (!scene.clampToHeightSupported || !scene.pickPositionSupported) {
1089+
return;
1090+
}
1091+
1092+
createSmallRectangle(0.0);
1093+
var offscreenRectanglePrimitive = createRectangle(0.0, offscreenRectangle);
1094+
offscreenRectanglePrimitive.appearance.material.uniforms.color = new Color(1.0, 0.0, 0.0, 1.0);
1095+
1096+
scene.camera.setView({ destination : offscreenRectangle });
1097+
1098+
// Call render. Lays down depth for the pickPosition call
1099+
scene.renderForSpecs();
1100+
1101+
// Call clampToHeight
1102+
var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100000.0);
1103+
expect(scene).toClampToHeightAndCall(function(cartesian) {
1104+
var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0);
1105+
expect(cartesian).toEqualEpsilon(expectedCartesian, CesiumMath.EPSILON5);
1106+
}, cartesian);
1107+
1108+
// Call pickPosition
1109+
expect(scene).toPickPositionAndCall(function(cartesian) {
1110+
var expectedCartesian = Cartographic.toCartesian(Rectangle.center(offscreenRectangle));
1111+
expect(cartesian).toEqualEpsilon(expectedCartesian, CesiumMath.EPSILON5);
1112+
});
1113+
1114+
// Call clampToHeight again
1115+
expect(scene).toClampToHeightAndCall(function(cartesian) {
1116+
var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0);
1117+
expect(cartesian).toEqualEpsilon(expectedCartesian, CesiumMath.EPSILON5);
1118+
}, cartesian);
1119+
1120+
// Call pick
1121+
expect(scene).toPickPrimitive(offscreenRectanglePrimitive);
1122+
1123+
// Call clampToHeight again
1124+
expect(scene).toClampToHeightAndCall(function(cartesian) {
1125+
var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0);
1126+
expect(cartesian).toEqualEpsilon(expectedCartesian, CesiumMath.EPSILON5);
1127+
}, cartesian);
1128+
1129+
// Call pickPosition on translucent primitive and returns undefined
1130+
offscreenRectanglePrimitive.appearance.material.uniforms.color = new Color(1.0, 0.0, 0.0, 0.5);
1131+
scene.renderForSpecs();
1132+
expect(scene).toPickPositionAndCall(function(cartesian) {
1133+
expect(cartesian).toBeUndefined();
1134+
});
1135+
1136+
// Call clampToHeight again
1137+
expect(scene).toClampToHeightAndCall(function(cartesian) {
1138+
var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0);
1139+
expect(cartesian).toEqualEpsilon(expectedCartesian, CesiumMath.EPSILON5);
1140+
}, cartesian);
1141+
1142+
// Call pickPosition on translucent primitive with pickTranslucentDepth
1143+
scene.pickTranslucentDepth = true;
1144+
scene.renderForSpecs();
1145+
expect(scene).toPickPositionAndCall(function(cartesian) {
1146+
var expectedCartesian = Cartographic.toCartesian(Rectangle.center(offscreenRectangle));
1147+
expect(cartesian).toEqualEpsilon(expectedCartesian, CesiumMath.EPSILON5);
1148+
});
1149+
});
1150+
10841151
}, 'WebGL');

‎Specs/addDefaultMatchers.js

+24
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,30 @@ define([
439439
};
440440
},
441441

442+
toPickPositionAndCall : function(util, customEqualityTesters) {
443+
return {
444+
compare : function(actual, expected, x, y) {
445+
var scene = actual;
446+
var canvas = scene.canvas;
447+
x = defaultValue(x, canvas.clientWidth / 2);
448+
y = defaultValue(y, canvas.clientHeight / 2);
449+
var result = scene.pickPosition(new Cartesian2(x, y));
450+
451+
var webglStub = !!window.webglStub;
452+
if (!webglStub) {
453+
// The callback may have expectations that fail, which still makes the
454+
// spec fail, as we desired, even though this matcher sets pass to true.
455+
var callback = expected;
456+
callback(result);
457+
}
458+
459+
return {
460+
pass : true
461+
};
462+
}
463+
};
464+
},
465+
442466
toReadPixels : function(util, customEqualityTesters) {
443467
return {
444468
compare : function(actual, expected) {

0 commit comments

Comments
 (0)