123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880 |
- import ApproximateTerrainHeights from '../Core/ApproximateTerrainHeights.js';
- import BoundingRectangle from '../Core/BoundingRectangle.js';
- import Cartesian2 from '../Core/Cartesian2.js';
- import Cartesian3 from '../Core/Cartesian3.js';
- import Cartographic from '../Core/Cartographic.js';
- import Check from '../Core/Check.js';
- import Color from '../Core/Color.js';
- import defaultValue from '../Core/defaultValue.js';
- import defined from '../Core/defined.js';
- import DeveloperError from '../Core/DeveloperError.js';
- import Matrix4 from '../Core/Matrix4.js';
- import OrthographicFrustum from '../Core/OrthographicFrustum.js';
- import OrthographicOffCenterFrustum from '../Core/OrthographicOffCenterFrustum.js';
- import PerspectiveFrustum from '../Core/PerspectiveFrustum.js';
- import PerspectiveOffCenterFrustum from '../Core/PerspectiveOffCenterFrustum.js';
- import Ray from '../Core/Ray.js';
- import ShowGeometryInstanceAttribute from '../Core/ShowGeometryInstanceAttribute.js';
- import when from '../ThirdParty/when.js';
- import Camera from './Camera.js';
- import Cesium3DTileFeature from './Cesium3DTileFeature.js';
- import Cesium3DTilePass from './Cesium3DTilePass.js';
- import Cesium3DTilePassState from './Cesium3DTilePassState.js';
- import Cesium3DTileset from './Cesium3DTileset.js';
- import PickDepth from './PickDepth.js';
- import PrimitiveCollection from './PrimitiveCollection.js';
- import SceneMode from './SceneMode.js';
- import SceneTransforms from './SceneTransforms.js';
- import View from './View.js';
- var offscreenDefaultWidth = 0.1;
- var mostDetailedPreloadTilesetPassState = new Cesium3DTilePassState({
- pass : Cesium3DTilePass.MOST_DETAILED_PRELOAD
- });
- var mostDetailedPickTilesetPassState = new Cesium3DTilePassState({
- pass : Cesium3DTilePass.MOST_DETAILED_PICK
- });
- var pickTilesetPassState = new Cesium3DTilePassState({
- pass : Cesium3DTilePass.PICK
- });
- /**
- * @private
- */
- function Picking(scene) {
- this._mostDetailedRayPicks = [];
- this.pickRenderStateCache = {};
- this._pickPositionCache = {};
- this._pickPositionCacheDirty = false;
- var pickOffscreenViewport = new BoundingRectangle(0, 0, 1, 1);
- var pickOffscreenCamera = new Camera(scene);
- pickOffscreenCamera.frustum = new OrthographicFrustum({
- width: offscreenDefaultWidth,
- aspectRatio: 1.0,
- near: 0.1
- });
- this._pickOffscreenView = new View(scene, pickOffscreenCamera, pickOffscreenViewport);
- }
- Picking.prototype.update = function() {
- this._pickPositionCacheDirty = true;
- };
- Picking.prototype.getPickDepth = function(scene, index) {
- var pickDepths = scene.view.pickDepths;
- var pickDepth = pickDepths[index];
- if (!defined(pickDepth)) {
- pickDepth = new PickDepth();
- pickDepths[index] = pickDepth;
- }
- return pickDepth;
- };
- var scratchOrthoPickingFrustum = new OrthographicOffCenterFrustum();
- var scratchOrthoOrigin = new Cartesian3();
- var scratchOrthoDirection = new Cartesian3();
- var scratchOrthoPixelSize = new Cartesian2();
- var scratchOrthoPickVolumeMatrix4 = new Matrix4();
- function getPickOrthographicCullingVolume(scene, drawingBufferPosition, width, height, viewport) {
- var camera = scene.camera;
- var frustum = camera.frustum;
- if (defined(frustum._offCenterFrustum)) {
- frustum = frustum._offCenterFrustum;
- }
- var x = 2.0 * (drawingBufferPosition.x - viewport.x) / viewport.width - 1.0;
- x *= (frustum.right - frustum.left) * 0.5;
- var y = 2.0 * (viewport.height - drawingBufferPosition.y - viewport.y) / viewport.height - 1.0;
- y *= (frustum.top - frustum.bottom) * 0.5;
- var transform = Matrix4.clone(camera.transform, scratchOrthoPickVolumeMatrix4);
- camera._setTransform(Matrix4.IDENTITY);
- var origin = Cartesian3.clone(camera.position, scratchOrthoOrigin);
- Cartesian3.multiplyByScalar(camera.right, x, scratchOrthoDirection);
- Cartesian3.add(scratchOrthoDirection, origin, origin);
- Cartesian3.multiplyByScalar(camera.up, y, scratchOrthoDirection);
- Cartesian3.add(scratchOrthoDirection, origin, origin);
- camera._setTransform(transform);
- if (scene.mode === SceneMode.SCENE2D) {
- Cartesian3.fromElements(origin.z, origin.x, origin.y, origin);
- }
- var pixelSize = frustum.getPixelDimensions(viewport.width, viewport.height, 1.0, 1.0, scratchOrthoPixelSize);
- var ortho = scratchOrthoPickingFrustum;
- ortho.right = pixelSize.x * 0.5;
- ortho.left = -ortho.right;
- ortho.top = pixelSize.y * 0.5;
- ortho.bottom = -ortho.top;
- ortho.near = frustum.near;
- ortho.far = frustum.far;
- return ortho.computeCullingVolume(origin, camera.directionWC, camera.upWC);
- }
- var scratchPerspPickingFrustum = new PerspectiveOffCenterFrustum();
- var scratchPerspPixelSize = new Cartesian2();
- function getPickPerspectiveCullingVolume(scene, drawingBufferPosition, width, height, viewport) {
- var camera = scene.camera;
- var frustum = camera.frustum;
- var near = frustum.near;
- var tanPhi = Math.tan(frustum.fovy * 0.5);
- var tanTheta = frustum.aspectRatio * tanPhi;
- var x = 2.0 * (drawingBufferPosition.x - viewport.x) / viewport.width - 1.0;
- var y = 2.0 * (viewport.height - drawingBufferPosition.y - viewport.y) / viewport.height - 1.0;
- var xDir = x * near * tanTheta;
- var yDir = y * near * tanPhi;
- var pixelSize = frustum.getPixelDimensions(viewport.width, viewport.height, 1.0, 1.0, scratchPerspPixelSize);
- var pickWidth = pixelSize.x * width * 0.5;
- var pickHeight = pixelSize.y * height * 0.5;
- var offCenter = scratchPerspPickingFrustum;
- offCenter.top = yDir + pickHeight;
- offCenter.bottom = yDir - pickHeight;
- offCenter.right = xDir + pickWidth;
- offCenter.left = xDir - pickWidth;
- offCenter.near = near;
- offCenter.far = frustum.far;
- return offCenter.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
- }
- function getPickCullingVolume(scene, drawingBufferPosition, width, height, viewport) {
- var frustum = scene.camera.frustum;
- if (frustum instanceof OrthographicFrustum || frustum instanceof OrthographicOffCenterFrustum) {
- return getPickOrthographicCullingVolume(scene, drawingBufferPosition, width, height, viewport);
- }
- return getPickPerspectiveCullingVolume(scene, drawingBufferPosition, width, height, viewport);
- }
- // pick rectangle width and height, assumed odd
- var scratchRectangleWidth = 3.0;
- var scratchRectangleHeight = 3.0;
- var scratchRectangle = new BoundingRectangle(0.0, 0.0, scratchRectangleWidth, scratchRectangleHeight);
- var scratchPosition = new Cartesian2();
- var scratchColorZero = new Color(0.0, 0.0, 0.0, 0.0);
- Picking.prototype.pick = function(scene, windowPosition, width, height) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(windowPosition)) {
- throw new DeveloperError('windowPosition is undefined.');
- }
- //>>includeEnd('debug');
- scratchRectangleWidth = defaultValue(width, 3.0);
- scratchRectangleHeight = defaultValue(height, scratchRectangleWidth);
- var context = scene.context;
- var us = context.uniformState;
- var frameState = scene.frameState;
- var view = scene.defaultView;
- scene.view = view;
- var viewport = view.viewport;
- viewport.x = 0;
- viewport.y = 0;
- viewport.width = context.drawingBufferWidth;
- viewport.height = context.drawingBufferHeight;
- var passState = view.passState;
- passState.viewport = BoundingRectangle.clone(viewport, passState.viewport);
- var drawingBufferPosition = SceneTransforms.transformWindowToDrawingBuffer(scene, windowPosition, scratchPosition);
- scene.jobScheduler.disableThisFrame();
- scene.updateFrameState();
- frameState.cullingVolume = getPickCullingVolume(scene, drawingBufferPosition, scratchRectangleWidth, scratchRectangleHeight, viewport);
- frameState.invertClassification = false;
- frameState.passes.pick = true;
- frameState.tilesetPassState = pickTilesetPassState;
- us.update(frameState);
- scene.updateEnvironment();
- scratchRectangle.x = drawingBufferPosition.x - ((scratchRectangleWidth - 1.0) * 0.5);
- scratchRectangle.y = (scene.drawingBufferHeight - drawingBufferPosition.y) - ((scratchRectangleHeight - 1.0) * 0.5);
- scratchRectangle.width = scratchRectangleWidth;
- scratchRectangle.height = scratchRectangleHeight;
- passState = view.pickFramebuffer.begin(scratchRectangle, view.viewport);
- scene.updateAndExecuteCommands(passState, scratchColorZero);
- scene.resolveFramebuffers(passState);
- var object = view.pickFramebuffer.end(scratchRectangle);
- context.endFrame();
- return object;
- };
- function renderTranslucentDepthForPick(scene, drawingBufferPosition) {
- // PERFORMANCE_IDEA: render translucent only and merge with the previous frame
- var context = scene.context;
- var frameState = scene.frameState;
- var environmentState = scene.environmentState;
- var view = scene.defaultView;
- scene.view = view;
- var viewport = view.viewport;
- viewport.x = 0;
- viewport.y = 0;
- viewport.width = context.drawingBufferWidth;
- viewport.height = context.drawingBufferHeight;
- var passState = view.passState;
- passState.viewport = BoundingRectangle.clone(viewport, passState.viewport);
- scene.clearPasses(frameState.passes);
- frameState.passes.pick = true;
- frameState.passes.depth = true;
- frameState.cullingVolume = getPickCullingVolume(scene, drawingBufferPosition, 1, 1, viewport);
- frameState.tilesetPassState = pickTilesetPassState;
- scene.updateEnvironment();
- environmentState.renderTranslucentDepthForPick = true;
- passState = view.pickDepthFramebuffer.update(context, drawingBufferPosition, viewport);
- scene.updateAndExecuteCommands(passState, scratchColorZero);
- scene.resolveFramebuffers(passState);
- context.endFrame();
- }
- var scratchPerspectiveFrustum = new PerspectiveFrustum();
- var scratchPerspectiveOffCenterFrustum = new PerspectiveOffCenterFrustum();
- var scratchOrthographicFrustum = new OrthographicFrustum();
- var scratchOrthographicOffCenterFrustum = new OrthographicOffCenterFrustum();
- Picking.prototype.pickPositionWorldCoordinates = function(scene, windowPosition, result) {
- if (!scene.useDepthPicking) {
- return undefined;
- }
- //>>includeStart('debug', pragmas.debug);
- if (!defined(windowPosition)) {
- throw new DeveloperError('windowPosition is undefined.');
- }
- if (!scene.context.depthTexture) {
- throw new DeveloperError('Picking from the depth buffer is not supported. Check pickPositionSupported.');
- }
- //>>includeEnd('debug');
- var cacheKey = windowPosition.toString();
- if (this._pickPositionCacheDirty){
- this._pickPositionCache = {};
- this._pickPositionCacheDirty = false;
- } else if (this._pickPositionCache.hasOwnProperty(cacheKey)){
- return Cartesian3.clone(this._pickPositionCache[cacheKey], result);
- }
- var frameState = scene.frameState;
- var context = scene.context;
- var uniformState = context.uniformState;
- var view = scene.defaultView;
- scene.view = view;
- var drawingBufferPosition = SceneTransforms.transformWindowToDrawingBuffer(scene, windowPosition, scratchPosition);
- if (scene.pickTranslucentDepth) {
- renderTranslucentDepthForPick(scene, drawingBufferPosition);
- } else {
- scene.updateFrameState();
- uniformState.update(frameState);
- scene.updateEnvironment();
- }
- drawingBufferPosition.y = scene.drawingBufferHeight - drawingBufferPosition.y;
- var camera = scene.camera;
- // Create a working frustum from the original camera frustum.
- var frustum;
- if (defined(camera.frustum.fov)) {
- frustum = camera.frustum.clone(scratchPerspectiveFrustum);
- } else if (defined(camera.frustum.infiniteProjectionMatrix)){
- frustum = camera.frustum.clone(scratchPerspectiveOffCenterFrustum);
- } else if (defined(camera.frustum.width)) {
- frustum = camera.frustum.clone(scratchOrthographicFrustum);
- } else {
- frustum = camera.frustum.clone(scratchOrthographicOffCenterFrustum);
- }
- var frustumCommandsList = view.frustumCommandsList;
- var numFrustums = frustumCommandsList.length;
- for (var i = 0; i < numFrustums; ++i) {
- var pickDepth = this.getPickDepth(scene, i);
- var depth = pickDepth.getDepth(context, drawingBufferPosition.x, drawingBufferPosition.y);
- if (depth > 0.0 && depth < 1.0) {
- var renderedFrustum = frustumCommandsList[i];
- var height2D;
- if (scene.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(frameState);
- uniformState.updateFrustum(frustum);
- } else {
- frustum.near = renderedFrustum.near * (i !== 0 ? scene.opaqueFrustumNearOffset : 1.0);
- frustum.far = renderedFrustum.far;
- uniformState.updateFrustum(frustum);
- }
- result = SceneTransforms.drawingBufferToWgs84Coordinates(scene, drawingBufferPosition, depth, result);
- if (scene.mode === SceneMode.SCENE2D) {
- camera.position.z = height2D;
- uniformState.update(frameState);
- }
- this._pickPositionCache[cacheKey] = Cartesian3.clone(result);
- return result;
- }
- }
- this._pickPositionCache[cacheKey] = undefined;
- return undefined;
- };
- var scratchPickPositionCartographic = new Cartographic();
- Picking.prototype.pickPosition = function(scene, windowPosition, result) {
- result = this.pickPositionWorldCoordinates(scene, windowPosition, result);
- if (defined(result) && scene.mode !== SceneMode.SCENE3D) {
- Cartesian3.fromElements(result.y, result.z, result.x, result);
- var projection = scene.mapProjection;
- var ellipsoid = projection.ellipsoid;
- var cart = projection.unproject(result, scratchPickPositionCartographic);
- ellipsoid.cartographicToCartesian(cart, result);
- }
- return result;
- };
- function drillPick(limit, pickCallback) {
- // PERFORMANCE_IDEA: This function calls each primitive's update for each pass. Instead
- // we could update the primitive once, and then just execute their commands for each pass,
- // and cull commands for picked primitives. e.g., base on the command's owner.
- var i;
- var attributes;
- var result = [];
- var pickedPrimitives = [];
- var pickedAttributes = [];
- var pickedFeatures = [];
- if (!defined(limit)) {
- limit = Number.MAX_VALUE;
- }
- var pickedResult = pickCallback();
- while (defined(pickedResult)) {
- var object = pickedResult.object;
- var position = pickedResult.position;
- var exclude = pickedResult.exclude;
- if (defined(position) && !defined(object)) {
- result.push(pickedResult);
- break;
- }
- if (!defined(object) || !defined(object.primitive)) {
- break;
- }
- if (!exclude) {
- result.push(pickedResult);
- if (0 >= --limit) {
- break;
- }
- }
- var primitive = object.primitive;
- var hasShowAttribute = false;
- // If the picked object has a show attribute, use it.
- if (typeof primitive.getGeometryInstanceAttributes === 'function') {
- if (defined(object.id)) {
- attributes = primitive.getGeometryInstanceAttributes(object.id);
- if (defined(attributes) && defined(attributes.show)) {
- hasShowAttribute = true;
- attributes.show = ShowGeometryInstanceAttribute.toValue(false, attributes.show);
- pickedAttributes.push(attributes);
- }
- }
- }
- if (object instanceof Cesium3DTileFeature) {
- hasShowAttribute = true;
- object.show = false;
- pickedFeatures.push(object);
- }
- // Otherwise, hide the entire primitive
- if (!hasShowAttribute) {
- primitive.show = false;
- pickedPrimitives.push(primitive);
- }
- pickedResult = pickCallback();
- }
- // Unhide everything we hid while drill picking
- for (i = 0; i < pickedPrimitives.length; ++i) {
- pickedPrimitives[i].show = true;
- }
- for (i = 0; i < pickedAttributes.length; ++i) {
- attributes = pickedAttributes[i];
- attributes.show = ShowGeometryInstanceAttribute.toValue(true, attributes.show);
- }
- for (i = 0; i < pickedFeatures.length; ++i) {
- pickedFeatures[i].show = true;
- }
- return result;
- }
- Picking.prototype.drillPick = function(scene, windowPosition, limit, width, height) {
- var that = this;
- var pickCallback = function() {
- var object = that.pick(scene, windowPosition, width, height);
- if (defined(object)) {
- return {
- object : object,
- position : undefined,
- exclude : false
- };
- }
- };
- var objects = drillPick(limit, pickCallback);
- return objects.map(function(element) {
- return element.object;
- });
- };
- var scratchRight = new Cartesian3();
- var scratchUp = new Cartesian3();
- function MostDetailedRayPick(ray, width, tilesets) {
- this.ray = ray;
- this.width = width;
- this.tilesets = tilesets;
- this.ready = false;
- this.deferred = when.defer();
- this.promise = this.deferred.promise;
- }
- function updateOffscreenCameraFromRay(picking, ray, width, camera) {
- var direction = ray.direction;
- var orthogonalAxis = Cartesian3.mostOrthogonalAxis(direction, scratchRight);
- var right = Cartesian3.cross(direction, orthogonalAxis, scratchRight);
- var up = Cartesian3.cross(direction, right, scratchUp);
- camera.position = ray.origin;
- camera.direction = direction;
- camera.up = up;
- camera.right = right;
- camera.frustum.width = defaultValue(width, offscreenDefaultWidth);
- return camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
- }
- function updateMostDetailedRayPick(picking, scene, rayPick) {
- var frameState = scene.frameState;
- var ray = rayPick.ray;
- var width = rayPick.width;
- var tilesets = rayPick.tilesets;
- var camera = picking._pickOffscreenView.camera;
- var cullingVolume = updateOffscreenCameraFromRay(picking, ray, width, camera);
- var tilesetPassState = mostDetailedPreloadTilesetPassState;
- tilesetPassState.camera = camera;
- tilesetPassState.cullingVolume = cullingVolume;
- var ready = true;
- var tilesetsLength = tilesets.length;
- for (var i = 0; i < tilesetsLength; ++i) {
- var tileset = tilesets[i];
- if (tileset.show && scene.primitives.contains(tileset)) {
- // Only update tilesets that are still contained in the scene's primitive collection and are still visible
- // Update tilesets continually until all tilesets are ready. This way tiles are never removed from the cache.
- tileset.updateForPass(frameState, tilesetPassState);
- ready = (ready && tilesetPassState.ready);
- }
- }
- if (ready) {
- rayPick.deferred.resolve();
- }
- return ready;
- }
- Picking.prototype.updateMostDetailedRayPicks = function(scene) {
- // Modifies array during iteration
- var rayPicks = this._mostDetailedRayPicks;
- for (var i = 0; i < rayPicks.length; ++i) {
- if (updateMostDetailedRayPick(this, scene, rayPicks[i])) {
- rayPicks.splice(i--, 1);
- }
- }
- };
- function getTilesets(primitives, objectsToExclude, tilesets) {
- var length = primitives.length;
- for (var i = 0; i < length; ++i) {
- var primitive = primitives.get(i);
- if (primitive.show) {
- if ((primitive instanceof Cesium3DTileset)) {
- if (!defined(objectsToExclude) || objectsToExclude.indexOf(primitive) === -1) {
- tilesets.push(primitive);
- }
- } else if (primitive instanceof PrimitiveCollection) {
- getTilesets(primitive, objectsToExclude, tilesets);
- }
- }
- }
- }
- function launchMostDetailedRayPick(picking, scene, ray, objectsToExclude, width, callback) {
- var tilesets = [];
- getTilesets(scene.primitives, objectsToExclude, tilesets);
- if (tilesets.length === 0) {
- return when.resolve(callback());
- }
- var rayPick = new MostDetailedRayPick(ray, width, tilesets);
- picking._mostDetailedRayPicks.push(rayPick);
- return rayPick.promise.then(function() {
- return callback();
- });
- }
- function isExcluded(object, objectsToExclude) {
- if (!defined(object) || !defined(objectsToExclude) || objectsToExclude.length === 0) {
- return false;
- }
- return (objectsToExclude.indexOf(object) > -1) ||
- (objectsToExclude.indexOf(object.primitive) > -1) ||
- (objectsToExclude.indexOf(object.id) > -1);
- }
- function getRayIntersection(picking, scene, ray, objectsToExclude, width, requirePosition, mostDetailed) {
- var context = scene.context;
- var uniformState = context.uniformState;
- var frameState = scene.frameState;
- var view = picking._pickOffscreenView;
- scene.view = view;
- updateOffscreenCameraFromRay(picking, ray, width, view.camera);
- scratchRectangle = BoundingRectangle.clone(view.viewport, scratchRectangle);
- var passState = view.pickFramebuffer.begin(scratchRectangle, view.viewport);
- scene.jobScheduler.disableThisFrame();
- scene.updateFrameState();
- frameState.invertClassification = false;
- frameState.passes.pick = true;
- frameState.passes.offscreen = true;
- if (mostDetailed) {
- frameState.tilesetPassState = mostDetailedPickTilesetPassState;
- } else {
- frameState.tilesetPassState = pickTilesetPassState;
- }
- uniformState.update(frameState);
- scene.updateEnvironment();
- scene.updateAndExecuteCommands(passState, scratchColorZero);
- scene.resolveFramebuffers(passState);
- var position;
- var object = view.pickFramebuffer.end(context);
- if (scene.context.depthTexture) {
- var numFrustums = view.frustumCommandsList.length;
- for (var i = 0; i < numFrustums; ++i) {
- var pickDepth = picking.getPickDepth(scene, i);
- var depth = pickDepth.getDepth(context, 0, 0);
- if (depth > 0.0 && depth < 1.0) {
- var renderedFrustum = view.frustumCommandsList[i];
- var near = renderedFrustum.near * (i !== 0 ? scene.opaqueFrustumNearOffset : 1.0);
- var far = renderedFrustum.far;
- var distance = near + depth * (far - near);
- position = Ray.getPoint(ray, distance);
- break;
- }
- }
- }
- scene.view = scene.defaultView;
- context.endFrame();
- if (defined(object) || defined(position)) {
- return {
- object : object,
- position : position,
- exclude : (!defined(position) && requirePosition) || isExcluded(object, objectsToExclude)
- };
- }
- }
- function getRayIntersections(picking, scene, ray, limit, objectsToExclude, width, requirePosition, mostDetailed) {
- var pickCallback = function() {
- return getRayIntersection(picking, scene, ray, objectsToExclude, width, requirePosition, mostDetailed);
- };
- return drillPick(limit, pickCallback);
- }
- function pickFromRay(picking, scene, ray, objectsToExclude, width, requirePosition, mostDetailed) {
- var results = getRayIntersections(picking, scene, ray, 1, objectsToExclude, width, requirePosition, mostDetailed);
- if (results.length > 0) {
- return results[0];
- }
- }
- function drillPickFromRay(picking, scene, ray, limit, objectsToExclude, width, requirePosition, mostDetailed) {
- return getRayIntersections(picking, scene, ray, limit, objectsToExclude, width, requirePosition, mostDetailed);
- }
- function deferPromiseUntilPostRender(scene, promise) {
- // Resolve promise after scene's postRender in case entities are created when the promise resolves.
- // Entities can't be created between viewer._onTick and viewer._postRender.
- var deferred = when.defer();
- promise.then(function(result) {
- var removeCallback = scene.postRender.addEventListener(function() {
- deferred.resolve(result);
- removeCallback();
- });
- scene.requestRender();
- }).otherwise(function(error) {
- deferred.reject(error);
- });
- return deferred.promise;
- }
- Picking.prototype.pickFromRay = function(scene, ray, objectsToExclude, width) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('ray', ray);
- if (scene.mode !== SceneMode.SCENE3D) {
- throw new DeveloperError('Ray intersections are only supported in 3D mode.');
- }
- //>>includeEnd('debug');
- return pickFromRay(this, scene, ray, objectsToExclude, width, false, false);
- };
- Picking.prototype.drillPickFromRay = function(scene, ray, limit, objectsToExclude, width) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('ray', ray);
- if (scene.mode !== SceneMode.SCENE3D) {
- throw new DeveloperError('Ray intersections are only supported in 3D mode.');
- }
- //>>includeEnd('debug');
- return drillPickFromRay(this, scene, ray, limit, objectsToExclude, width,false, false);
- };
- Picking.prototype.pickFromRayMostDetailed = function(scene, ray, objectsToExclude, width) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('ray', ray);
- if (scene.mode !== SceneMode.SCENE3D) {
- throw new DeveloperError('Ray intersections are only supported in 3D mode.');
- }
- //>>includeEnd('debug');
- var that = this;
- ray = Ray.clone(ray);
- objectsToExclude = defined(objectsToExclude) ? objectsToExclude.slice() : objectsToExclude;
- return deferPromiseUntilPostRender(scene, launchMostDetailedRayPick(that, scene, ray, objectsToExclude, width, function() {
- return pickFromRay(that, scene, ray, objectsToExclude, width, false, true);
- }));
- };
- Picking.prototype.drillPickFromRayMostDetailed = function(scene, ray, limit, objectsToExclude, width) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('ray', ray);
- if (scene.mode !== SceneMode.SCENE3D) {
- throw new DeveloperError('Ray intersections are only supported in 3D mode.');
- }
- //>>includeEnd('debug');
- var that = this;
- ray = Ray.clone(ray);
- objectsToExclude = defined(objectsToExclude) ? objectsToExclude.slice() : objectsToExclude;
- return deferPromiseUntilPostRender(scene, launchMostDetailedRayPick(that, scene, ray, objectsToExclude, width, function() {
- return drillPickFromRay(that, scene, ray, limit, objectsToExclude, width, false, true);
- }));
- };
- var scratchSurfacePosition = new Cartesian3();
- var scratchSurfaceNormal = new Cartesian3();
- var scratchSurfaceRay = new Ray();
- var scratchCartographic = new Cartographic();
- function getRayForSampleHeight(scene, cartographic) {
- var globe = scene.globe;
- var ellipsoid = defined(globe) ? globe.ellipsoid : scene.mapProjection.ellipsoid;
- var height = ApproximateTerrainHeights._defaultMaxTerrainHeight;
- var surfaceNormal = ellipsoid.geodeticSurfaceNormalCartographic(cartographic, scratchSurfaceNormal);
- var surfacePosition = Cartographic.toCartesian(cartographic, ellipsoid, scratchSurfacePosition);
- var surfaceRay = scratchSurfaceRay;
- surfaceRay.origin = surfacePosition;
- surfaceRay.direction = surfaceNormal;
- var ray = new Ray();
- Ray.getPoint(surfaceRay, height, ray.origin);
- Cartesian3.negate(surfaceNormal, ray.direction);
- return ray;
- }
- function getRayForClampToHeight(scene, cartesian) {
- var globe = scene.globe;
- var ellipsoid = defined(globe) ? globe.ellipsoid : scene.mapProjection.ellipsoid;
- var cartographic = Cartographic.fromCartesian(cartesian, ellipsoid, scratchCartographic);
- return getRayForSampleHeight(scene, cartographic);
- }
- function getHeightFromCartesian(scene, cartesian) {
- var globe = scene.globe;
- var ellipsoid = defined(globe) ? globe.ellipsoid : scene.mapProjection.ellipsoid;
- var cartographic = Cartographic.fromCartesian(cartesian, ellipsoid, scratchCartographic);
- return cartographic.height;
- }
- function sampleHeightMostDetailed(picking, scene, cartographic, objectsToExclude, width) {
- var ray = getRayForSampleHeight(scene, cartographic);
- return launchMostDetailedRayPick(picking, scene, ray, objectsToExclude, width, function() {
- var pickResult = pickFromRay(picking, scene, ray, objectsToExclude, width, true, true);
- if (defined(pickResult)) {
- return getHeightFromCartesian(scene, pickResult.position);
- }
- });
- }
- function clampToHeightMostDetailed(picking, scene, cartesian, objectsToExclude, width, result) {
- var ray = getRayForClampToHeight(scene, cartesian);
- return launchMostDetailedRayPick(picking, scene, ray, objectsToExclude, width, function() {
- var pickResult = pickFromRay(picking, scene, ray, objectsToExclude, width, true, true);
- if (defined(pickResult)) {
- return Cartesian3.clone(pickResult.position, result);
- }
- });
- }
- Picking.prototype.sampleHeight = function(scene, position, objectsToExclude, width) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('position', position);
- if (scene.mode !== SceneMode.SCENE3D) {
- throw new DeveloperError('sampleHeight is only supported in 3D mode.');
- }
- if (!scene.sampleHeightSupported) {
- throw new DeveloperError('sampleHeight requires depth texture support. Check sampleHeightSupported.');
- }
- //>>includeEnd('debug');
- var ray = getRayForSampleHeight(scene, position);
- var pickResult = pickFromRay(this, scene, ray, objectsToExclude, width, true, false);
- if (defined(pickResult)) {
- return getHeightFromCartesian(scene, pickResult.position);
- }
- };
- Picking.prototype.clampToHeight = function(scene, cartesian, objectsToExclude, width, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('cartesian', cartesian);
- if (scene.mode !== SceneMode.SCENE3D) {
- throw new DeveloperError('clampToHeight is only supported in 3D mode.');
- }
- if (!scene.clampToHeightSupported) {
- throw new DeveloperError('clampToHeight requires depth texture support. Check clampToHeightSupported.');
- }
- //>>includeEnd('debug');
- var ray = getRayForClampToHeight(scene, cartesian);
- var pickResult = pickFromRay(this, scene, ray, objectsToExclude, width, true, false);
- if (defined(pickResult)) {
- return Cartesian3.clone(pickResult.position, result);
- }
- };
- Picking.prototype.sampleHeightMostDetailed = function(scene, positions, objectsToExclude, width) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('positions', positions);
- if (scene.mode !== SceneMode.SCENE3D) {
- throw new DeveloperError('sampleHeightMostDetailed is only supported in 3D mode.');
- }
- if (!scene.sampleHeightSupported) {
- throw new DeveloperError('sampleHeightMostDetailed requires depth texture support. Check sampleHeightSupported.');
- }
- //>>includeEnd('debug');
- objectsToExclude = defined(objectsToExclude) ? objectsToExclude.slice() : objectsToExclude;
- var length = positions.length;
- var promises = new Array(length);
- for (var i = 0; i < length; ++i) {
- promises[i] = sampleHeightMostDetailed(this, scene, positions[i], objectsToExclude, width);
- }
- return deferPromiseUntilPostRender(scene, when.all(promises).then(function(heights) {
- var length = heights.length;
- for (var i = 0; i < length; ++i) {
- positions[i].height = heights[i];
- }
- return positions;
- }));
- };
- Picking.prototype.clampToHeightMostDetailed = function(scene, cartesians, objectsToExclude, width) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('cartesians', cartesians);
- if (scene.mode !== SceneMode.SCENE3D) {
- throw new DeveloperError('clampToHeightMostDetailed is only supported in 3D mode.');
- }
- if (!scene.clampToHeightSupported) {
- throw new DeveloperError('clampToHeightMostDetailed requires depth texture support. Check clampToHeightSupported.');
- }
- //>>includeEnd('debug');
- objectsToExclude = defined(objectsToExclude) ? objectsToExclude.slice() : objectsToExclude;
- var length = cartesians.length;
- var promises = new Array(length);
- for (var i = 0; i < length; ++i) {
- promises[i] = clampToHeightMostDetailed(this, scene, cartesians[i], objectsToExclude, width, cartesians[i]);
- }
- return deferPromiseUntilPostRender(scene, when.all(promises).then(function(clampedCartesians) {
- var length = clampedCartesians.length;
- for (var i = 0; i < length; ++i) {
- cartesians[i] = clampedCartesians[i];
- }
- return cartesians;
- }));
- };
- Picking.prototype.destroy = function() {
- this._pickOffscreenView = this._pickOffscreenView && this._pickOffscreenView.destroy();
- };
- export default Picking;
|