| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683 |
- 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 defined from "../Core/defined.js";
- import DeveloperError from "../Core/DeveloperError.js";
- import Matrix4 from "../Core/Matrix4.js";
- import oneTimeWarning from "../Core/oneTimeWarning.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 Camera from "./Camera.js";
- import Cesium3DTileFeature from "./Cesium3DTileFeature.js";
- import Cesium3DTilePass from "./Cesium3DTilePass.js";
- import Cesium3DTilePassState from "./Cesium3DTilePassState.js";
- import MetadataPicking from "./MetadataPicking.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";
-
- const offscreenDefaultWidth = 0.1;
-
- const mostDetailedPreloadTilesetPassState = new Cesium3DTilePassState({
- pass: Cesium3DTilePass.MOST_DETAILED_PRELOAD,
- });
-
- const mostDetailedPickTilesetPassState = new Cesium3DTilePassState({
- pass: Cesium3DTilePass.MOST_DETAILED_PICK,
- });
-
- const pickTilesetPassState = new Cesium3DTilePassState({
- pass: Cesium3DTilePass.PICK,
- });
-
- /**
- * @private
- */
- function Picking(scene) {
- this._mostDetailedRayPicks = [];
- this.pickRenderStateCache = {};
- this._pickPositionCache = {};
- this._pickPositionCacheDirty = false;
-
- const pickOffscreenViewport = new BoundingRectangle(0, 0, 1, 1);
- const 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) {
- const pickDepths = scene.view.pickDepths;
- let pickDepth = pickDepths[index];
- if (!defined(pickDepth)) {
- pickDepth = new PickDepth();
- pickDepths[index] = pickDepth;
- }
- return pickDepth;
- };
-
- const scratchOrthoPickingFrustum = new OrthographicOffCenterFrustum();
- const scratchOrthoOrigin = new Cartesian3();
- const scratchOrthoDirection = new Cartesian3();
- const scratchOrthoPixelSize = new Cartesian2();
- const scratchOrthoPickVolumeMatrix4 = new Matrix4();
-
- function getPickOrthographicCullingVolume(
- scene,
- drawingBufferPosition,
- width,
- height,
- viewport,
- ) {
- const camera = scene.camera;
- let frustum = camera.frustum;
- const offCenterFrustum = frustum.offCenterFrustum;
- if (defined(offCenterFrustum)) {
- frustum = offCenterFrustum;
- }
-
- let x = (2.0 * (drawingBufferPosition.x - viewport.x)) / viewport.width - 1.0;
- x *= (frustum.right - frustum.left) * 0.5;
- let y =
- (2.0 * (viewport.height - drawingBufferPosition.y - viewport.y)) /
- viewport.height -
- 1.0;
- y *= (frustum.top - frustum.bottom) * 0.5;
-
- const transform = Matrix4.clone(
- camera.transform,
- scratchOrthoPickVolumeMatrix4,
- );
- camera._setTransform(Matrix4.IDENTITY);
-
- const 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);
- }
-
- const pixelSize = frustum.getPixelDimensions(
- viewport.width,
- viewport.height,
- 1.0,
- 1.0,
- scratchOrthoPixelSize,
- );
-
- const 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);
- }
-
- const scratchPerspPickingFrustum = new PerspectiveOffCenterFrustum();
- const scratchPerspPixelSize = new Cartesian2();
-
- function getPickPerspectiveCullingVolume(
- scene,
- drawingBufferPosition,
- width,
- height,
- viewport,
- ) {
- const camera = scene.camera;
- const frustum = camera.frustum;
- const near = frustum.near;
-
- const tanPhi = Math.tan(frustum.fovy * 0.5);
- const tanTheta = frustum.aspectRatio * tanPhi;
-
- const x =
- (2.0 * (drawingBufferPosition.x - viewport.x)) / viewport.width - 1.0;
- const y =
- (2.0 * (viewport.height - drawingBufferPosition.y - viewport.y)) /
- viewport.height -
- 1.0;
-
- const xDir = x * near * tanTheta;
- const yDir = y * near * tanPhi;
-
- const pixelSize = frustum.getPixelDimensions(
- viewport.width,
- viewport.height,
- 1.0,
- 1.0,
- scratchPerspPixelSize,
- );
- const pickWidth = pixelSize.x * width * 0.5;
- const pickHeight = pixelSize.y * height * 0.5;
-
- const 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,
- ) {
- const 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 position and rectangle, used in all picking functions,
- // filled in computePickingDrawingBufferRectangle and passed
- // the the FrameBuffer begin/end methods
- const scratchRectangle = new BoundingRectangle(0.0, 0.0, 3.0, 3.0);
- const scratchPosition = new Cartesian2();
-
- // Dummy color that is passed to updateAndExecuteCommands in
- // all picking functions, used as the "background color"
- const scratchColorZero = new Color(0.0, 0.0, 0.0, 0.0);
-
- /**
- * Compute the rectangle that describes the part of the drawing buffer
- * that is relevant for picking.
- *
- * @param {number} drawingBufferHeight The height of the drawing buffer
- * @param {Cartesian2} position The position inside the drawing buffer
- * @param {number|undefined} width The width of the rectangle, assumed to
- * be an odd integer number, default : 3.0
- * @param {number|undefined} height The height of the rectangle. If unspecified,
- * height will default to the value of <code>width</code>
- * @param {BoundingRectangle} result The result rectangle
- * @returns {BoundingRectangle} The result rectangle
- */
- function computePickingDrawingBufferRectangle(
- drawingBufferHeight,
- position,
- width,
- height,
- result,
- ) {
- result.width = width ?? 3.0;
- result.height = height ?? result.width;
- result.x = position.x - (result.width - 1.0) * 0.5;
- result.y = drawingBufferHeight - position.y - (result.height - 1.0) * 0.5;
- return result;
- }
-
- /**
- * Setup needed before picking.
- *
- * @param {Scene} scene
- * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
- * @param {BoundingRectangle} drawingBufferRectangle The output drawing buffer recangle.
- * @param {number} [width=3] Width of the pick rectangle.
- * @param {number} [height=3] Height of the pick rectangle.
- */
- function pickBegin(
- scene,
- windowPosition,
- drawingBufferRectangle,
- width,
- height,
- ) {
- const { context, frameState, defaultView } = scene;
- const { viewport, pickFramebuffer } = defaultView;
-
- scene.view = defaultView;
-
- viewport.x = 0;
- viewport.y = 0;
- viewport.width = context.drawingBufferWidth;
- viewport.height = context.drawingBufferHeight;
-
- let passState = defaultView.passState;
- passState.viewport = BoundingRectangle.clone(viewport, passState.viewport);
-
- const drawingBufferPosition = SceneTransforms.transformWindowToDrawingBuffer(
- scene,
- windowPosition,
- scratchPosition,
- );
- computePickingDrawingBufferRectangle(
- context.drawingBufferHeight,
- drawingBufferPosition,
- width,
- height,
- drawingBufferRectangle,
- );
-
- scene.jobScheduler.disableThisFrame();
-
- scene.updateFrameState();
- frameState.cullingVolume = getPickCullingVolume(
- scene,
- drawingBufferPosition,
- drawingBufferRectangle.width,
- drawingBufferRectangle.height,
- viewport,
- );
- frameState.invertClassification = false;
- frameState.passes.pick = true;
- frameState.tilesetPassState = pickTilesetPassState;
-
- context.uniformState.update(frameState);
-
- scene.updateEnvironment();
-
- passState = pickFramebuffer.begin(drawingBufferRectangle, viewport);
-
- scene.updateAndExecuteCommands(passState, scratchColorZero);
- scene.resolveFramebuffers(passState);
- }
-
- /**
- * Teardown needed after picking.
- *
- * @param {Scene} scene
- */
- function pickEnd(scene) {
- const { context } = scene;
- context.endFrame();
- }
-
- /**
- * Same operation as {@link Picking#pick}, but returns a Promise that resolves asynchronously without blocking the main render thread.
- * Requires WebGL2 else using synchronous fallback.
- *
- * @see Picking#pick
- *
- * @param {Scene} scene
- * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
- * @param {number} [width=3] Width of the pick rectangle.
- * @param {number} [height=3] Height of the pick rectangle.
- * @param {number} [limit=1] If supplied, stop iterating after collecting this many objects.
- * @returns {Promise<object[]>} List of objects containing the picked primitives.
- *
- * @exception {RuntimeError} Async Picking Request Timeout.
- */
- Picking.prototype.pickAsync = async function (
- scene,
- windowPosition,
- width,
- height,
- limit = 1,
- ) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined("windowPosition", windowPosition);
- //>>includeEnd('debug');
-
- const { context, frameState, defaultView } = scene;
- const { pickFramebuffer } = defaultView;
- const drawingBufferRectangle = scratchRectangle;
- pickBegin(scene, windowPosition, drawingBufferRectangle, width, height);
- let pickedObjects;
- if (context.webgl2) {
- pickedObjects = pickFramebuffer.endAsync(
- drawingBufferRectangle,
- frameState,
- limit,
- ); // Promise<Object[]>
- } else {
- pickedObjects = pickFramebuffer.end(drawingBufferRectangle, limit); // Object[]
- pickedObjects = Promise.resolve(pickedObjects); // Promise<Object[]> Wrap as Promise
- oneTimeWarning(
- "picking-async-fallback",
- "Fallback to synchronous picking because async operation requires WebGL2 context.",
- );
- }
- pickEnd(scene);
- return pickedObjects;
- };
-
- /**
- * Returns a list of objects with a <code>primitive</code> property that contains the first (top) primitives
- * in the scene at a particular window coordinate. Other properties may potentially be set depending on the
- * type of primitive and may be used to further identify the picked object.
- * <p>
- * When a feature of a 3D Tiles tileset is picked, <code>pick</code> returns a {@link Cesium3DTileFeature} object.
- * </p>
- * @param {Scene} scene
- * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
- * @param {number} [width=3] Width of the pick rectangle.
- * @param {number} [height=3] Height of the pick rectangle.
- * @param {number} [limit=1] If supplied, stop iterating after collecting this many objects.
- * @returns {object[]} List of objects containing the picked primitives.
- *
- */
- Picking.prototype.pick = function (
- scene,
- windowPosition,
- width,
- height,
- limit = 1,
- ) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined("windowPosition", windowPosition);
- //>>includeEnd('debug');
-
- const { defaultView } = scene;
- const { pickFramebuffer } = defaultView;
- const drawingBufferRectangle = scratchRectangle;
- pickBegin(scene, windowPosition, drawingBufferRectangle, width, height);
- const pickedObjects = pickFramebuffer.end(drawingBufferRectangle, limit); // Object[]
- pickEnd(scene);
- return pickedObjects;
- };
-
- /**
- * Returns an object with information about the voxel sample rendered at
- * a particular window coordinate. Returns <code>undefined</code> if there is no
- * voxel at that position.
- *
- * @param {Scene} scene
- * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
- * @param {number} [width=3] Width of the pick rectangle.
- * @param {number} [height=3] Height of the pick rectangle.
- * @returns {object|undefined} Object containing the picked primitive.
- */
- Picking.prototype.pickVoxelCoordinate = function (
- scene,
- windowPosition,
- width,
- height,
- ) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined("windowPosition", windowPosition);
- //>>includeEnd('debug');
-
- const { context, frameState, defaultView } = scene;
- const { viewport, pickFramebuffer } = defaultView;
-
- scene.view = defaultView;
-
- viewport.x = 0;
- viewport.y = 0;
- viewport.width = context.drawingBufferWidth;
- viewport.height = context.drawingBufferHeight;
-
- let passState = defaultView.passState;
- passState.viewport = BoundingRectangle.clone(viewport, passState.viewport);
-
- const drawingBufferPosition = SceneTransforms.transformWindowToDrawingBuffer(
- scene,
- windowPosition,
- scratchPosition,
- );
- const drawingBufferRectangle = computePickingDrawingBufferRectangle(
- context.drawingBufferHeight,
- drawingBufferPosition,
- width,
- height,
- scratchRectangle,
- );
-
- scene.jobScheduler.disableThisFrame();
-
- scene.updateFrameState();
- frameState.cullingVolume = getPickCullingVolume(
- scene,
- drawingBufferPosition,
- drawingBufferRectangle.width,
- drawingBufferRectangle.height,
- viewport,
- );
- frameState.invertClassification = false;
- frameState.passes.pickVoxel = true;
- frameState.tilesetPassState = pickTilesetPassState;
-
- context.uniformState.update(frameState);
-
- scene.updateEnvironment();
-
- passState = pickFramebuffer.begin(drawingBufferRectangle, viewport);
-
- scene.updateAndExecuteCommands(passState, scratchColorZero);
- scene.resolveFramebuffers(passState);
-
- const voxelInfo = pickFramebuffer.readCenterPixel(drawingBufferRectangle);
- context.endFrame();
- return voxelInfo;
- };
-
- /**
- * Pick a metadata value at the given window position.
- *
- * The given `pickedMetadataInfo` defines the metadata value that is
- * supposed to be picked.
- *
- * The return type will depend on the type of the metadata property
- * that is picked. Given the current limitations of the types that
- * are supported for metadata picking, the return type will be one
- * of the following:
- *
- * - For `SCALAR`, the return type will be a `number`
- * - For `SCALAR` arrays, the return type will be a `number[]`
- * - For `VEC2`, the return type will be a `Cartesian2`
- * - For `VEC3`, the return type will be a `Cartesian3`
- * - For `VEC4`, the return type will be a `Cartesian4`
- *
- * Future implementations may additionally return `string`- or
- * `boolean` types, and `MATn` values as `MatrixN` objects,
- * and arrays of the respective types.
- *
- * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
- * @param {PickedMetadataInfo} pickedMetadataInfo Information about the picked metadata.
- * @returns {MetadataValue|undefined} The metadata value, or `undefined`
- * when no matching metadata value could be picked at the given position
- *
- * @private
- */
- Picking.prototype.pickMetadata = function (
- scene,
- windowPosition,
- pickedMetadataInfo,
- ) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("windowPosition", windowPosition);
- Check.typeOf.object("pickedMetadataInfo", pickedMetadataInfo);
- //>>includeEnd('debug');
-
- const { context, frameState, defaultView } = scene;
- const { viewport, pickFramebuffer } = defaultView;
-
- scene.view = defaultView;
-
- viewport.x = 0;
- viewport.y = 0;
- viewport.width = context.drawingBufferWidth;
- viewport.height = context.drawingBufferHeight;
-
- let passState = defaultView.passState;
- passState.viewport = BoundingRectangle.clone(viewport, passState.viewport);
-
- const drawingBufferPosition = SceneTransforms.transformWindowToDrawingBuffer(
- scene,
- windowPosition,
- scratchPosition,
- );
- const drawingBufferRectangle = computePickingDrawingBufferRectangle(
- context.drawingBufferHeight,
- drawingBufferPosition,
- 1.0,
- 1.0,
- scratchRectangle,
- );
-
- scene.jobScheduler.disableThisFrame();
-
- scene.updateFrameState();
- frameState.cullingVolume = getPickCullingVolume(
- scene,
- drawingBufferPosition,
- drawingBufferRectangle.width,
- drawingBufferRectangle.height,
- viewport,
- );
- frameState.invertClassification = false;
-
- frameState.passes.pick = true;
- frameState.tilesetPassState = pickTilesetPassState;
-
- // Insert the information about the picked metadata property
- // into the frame state, so that the `Scene.updateDerivedCommands`
- // call can detect any changes in the picked metadata description,
- // and update the derived commands for the new picked metadata
- // property
- frameState.pickingMetadata = true;
- frameState.pickedMetadataInfo = pickedMetadataInfo;
- context.uniformState.update(frameState);
-
- scene.updateEnvironment();
-
- passState = pickFramebuffer.begin(drawingBufferRectangle, viewport);
-
- scene.updateAndExecuteCommands(passState, scratchColorZero);
-
- // When OIT is enabled, then the resolveFrameBuffers function
- // will juggle around several frame buffers, and eventually use
- // the "environmentState.originalFramebuffer" instead of the
- // picking frame buffer. Skipping a million questions, just
- // switch OIT off here:
- const oldOIT = scene._environmentState.useOIT;
- scene._environmentState.useOIT = false;
- scene.resolveFramebuffers(passState);
- scene._environmentState.useOIT = oldOIT;
-
- const rawMetadataPixel = pickFramebuffer.readCenterPixel(
- drawingBufferRectangle,
- );
- context.endFrame();
-
- frameState.pickingMetadata = false;
-
- const metadataValue = MetadataPicking.decodeMetadataValues(
- pickedMetadataInfo.classProperty,
- pickedMetadataInfo.metadataProperty,
- rawMetadataPixel,
- );
-
- return metadataValue;
- };
-
- /**
- * @typedef {object} PickedMetadataInfo
- *
- * Information about metadata that is supposed to be picked
- *
- * @property {string|undefined} schemaId The optional ID of the metadata schema
- * @property {string} className The name of the metadata class
- * @property {string} propertyName The name of the metadata property
- * @property {MetadataClassProperty} classProperty The metadata class property
- */
-
- function renderTranslucentDepthForPick(scene, drawingBufferPosition) {
- // PERFORMANCE_IDEA: render translucent only and merge with the previous frame
- const { defaultView, context, frameState, environmentState } = scene;
- const { viewport, pickDepthFramebuffer } = defaultView;
-
- scene.view = defaultView;
-
- viewport.x = 0;
- viewport.y = 0;
- viewport.width = context.drawingBufferWidth;
- viewport.height = context.drawingBufferHeight;
-
- let passState = defaultView.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 = pickDepthFramebuffer.update(
- context,
- drawingBufferPosition,
- viewport,
- );
-
- scene.updateAndExecuteCommands(passState, scratchColorZero);
- scene.resolveFramebuffers(passState);
-
- context.endFrame();
- }
-
- const scratchPerspectiveFrustum = new PerspectiveFrustum();
- const scratchPerspectiveOffCenterFrustum = new PerspectiveOffCenterFrustum();
- const scratchOrthographicFrustum = new OrthographicFrustum();
- const scratchOrthographicOffCenterFrustum = new OrthographicOffCenterFrustum();
-
- Picking.prototype.pickPositionWorldCoordinates = function (
- scene,
- windowPosition,
- result,
- ) {
- if (!scene.useDepthPicking) {
- return undefined;
- }
-
- //>>includeStart('debug', pragmas.debug);
- Check.defined("windowPosition", windowPosition);
- if (!scene.context.depthTexture) {
- throw new DeveloperError(
- "Picking from the depth buffer is not supported. Check pickPositionSupported.",
- );
- }
- //>>includeEnd('debug');
-
- const cacheKey = windowPosition.toString();
-
- if (this._pickPositionCacheDirty) {
- this._pickPositionCache = {};
- this._pickPositionCacheDirty = false;
- } else if (this._pickPositionCache.hasOwnProperty(cacheKey)) {
- return Cartesian3.clone(this._pickPositionCache[cacheKey], result);
- }
-
- const { context, frameState, camera, defaultView } = scene;
- const { uniformState } = context;
-
- scene.view = defaultView;
-
- const 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;
-
- // Create a working frustum from the original camera frustum.
- let 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);
- }
-
- const { frustumCommandsList } = defaultView;
- const numFrustums = frustumCommandsList.length;
- for (let i = 0; i < numFrustums; ++i) {
- const pickDepth = this.getPickDepth(scene, i);
- const depth = pickDepth.getDepth(
- context,
- drawingBufferPosition.x,
- drawingBufferPosition.y,
- );
- if (!defined(depth)) {
- continue;
- }
- if (depth > 0.0 && depth < 1.0) {
- const renderedFrustum = frustumCommandsList[i];
- let 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.drawingBufferToWorldCoordinates(
- 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;
- };
-
- const 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);
-
- const projection = scene.mapProjection;
- const ellipsoid = projection.ellipsoid;
-
- const cart = projection.unproject(result, scratchPickPositionCartographic);
- ellipsoid.cartographicToCartesian(cart, result);
- }
-
- return result;
- };
-
- /**
- * @param {object[]} pickedResults the results from the pickCallback
- * @param {number} limit If supplied, stop drilling after collecting this many picks.
- * @param {object[]} results
- * @param {object[]} pickedPrimitives
- * @param {object[]} pickedAttributes
- * @param {object[]} pickedFeatures
- * @returns {boolean} whether picking should end
- */
- function addDrillPickedResults(
- pickedResults,
- limit,
- results,
- pickedPrimitives,
- pickedAttributes,
- pickedFeatures,
- ) {
- for (const pickedResult of pickedResults) {
- const object = pickedResult.object;
- const position = pickedResult.position;
- const exclude = pickedResult.exclude;
-
- if (defined(position) && !defined(object)) {
- results.push(pickedResult);
- return true;
- }
-
- if (!defined(object) || !defined(object.primitive)) {
- return true;
- }
-
- if (!exclude) {
- results.push(pickedResult);
- if (results.length >= limit) {
- return true;
- }
- }
-
- const primitive = object.primitive;
- let hasShowAttribute = false;
-
- // If the picked object has a show attribute, use it.
- if (typeof primitive.getGeometryInstanceAttributes === "function") {
- if (defined(object.id)) {
- const 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);
- }
- }
- }
-
- /**
- * Drill pick by repeatedly calling a given `pickCallback`, each time stripping away the previously picked objects.
- * @param {function(number): object[]} pickCallback Pick callback to execute each iteration
- * @param {number} [limit=Number.MAX_VALUE] If supplied, stop drilling after collecting this many picks
- * @returns {object[]} List of picked results
- */
- function drillPick(pickCallback, limit) {
- // 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.
- const results = [];
- const pickedPrimitives = [];
- const pickedAttributes = [];
- const pickedFeatures = [];
- if (!defined(limit)) {
- limit = Number.MAX_VALUE;
- }
-
- let pickedResults = pickCallback(limit);
- while (defined(pickedResults) && pickedResults.length > 0) {
- const complete = addDrillPickedResults(
- pickedResults,
- limit,
- results,
- pickedPrimitives,
- pickedAttributes,
- pickedFeatures,
- );
- if (complete) {
- break;
- }
- pickedResults = pickCallback(limit - results.length);
- }
-
- // Unhide everything we hid while drill picking
- for (let i = 0; i < pickedPrimitives.length; ++i) {
- pickedPrimitives[i].show = true;
- }
-
- for (let i = 0; i < pickedAttributes.length; ++i) {
- const attributes = pickedAttributes[i];
- attributes.show = ShowGeometryInstanceAttribute.toValue(
- true,
- attributes.show,
- );
- }
-
- for (let i = 0; i < pickedFeatures.length; ++i) {
- pickedFeatures[i].show = true;
- }
-
- return results;
- }
-
- Picking.prototype.drillPick = function (
- scene,
- windowPosition,
- limit,
- width,
- height,
- ) {
- const pickCallback = (limit) => {
- const pickedObjects = this.pick(
- scene,
- windowPosition,
- width,
- height,
- limit,
- );
- return pickedObjects.map((object) => ({
- object: object,
- position: undefined,
- exclude: false,
- }));
- };
- const objects = drillPick(pickCallback, limit);
- return objects.map((element) => element.object);
- };
-
- const scratchRight = new Cartesian3();
- const scratchUp = new Cartesian3();
-
- function MostDetailedRayPick(ray, width, tilesets) {
- this.ray = ray;
- this.width = width;
- this.tilesets = tilesets;
- this.ready = false;
- const pick = this;
- this.promise = new Promise((resolve) => {
- pick._completePick = () => {
- resolve();
- };
- });
- }
-
- function updateOffscreenCameraFromRay(picking, ray, width, camera) {
- const direction = ray.direction;
- const orthogonalAxis = Cartesian3.mostOrthogonalAxis(direction, scratchRight);
- const right = Cartesian3.cross(direction, orthogonalAxis, scratchRight);
- const up = Cartesian3.cross(direction, right, scratchUp);
-
- camera.position = ray.origin;
- camera.direction = direction;
- camera.up = up;
- camera.right = right;
-
- camera.frustum.width = width ?? offscreenDefaultWidth;
- return camera.frustum.computeCullingVolume(
- camera.positionWC,
- camera.directionWC,
- camera.upWC,
- );
- }
-
- function updateMostDetailedRayPick(picking, scene, rayPick) {
- const frameState = scene.frameState;
-
- const { ray, width, tilesets } = rayPick;
-
- const camera = picking._pickOffscreenView.camera;
- const cullingVolume = updateOffscreenCameraFromRay(
- picking,
- ray,
- width,
- camera,
- );
-
- const tilesetPassState = mostDetailedPreloadTilesetPassState;
- tilesetPassState.camera = camera;
- tilesetPassState.cullingVolume = cullingVolume;
-
- let ready = true;
- const tilesetsLength = tilesets.length;
- for (let i = 0; i < tilesetsLength; ++i) {
- const 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._completePick();
- }
-
- return ready;
- }
-
- Picking.prototype.updateMostDetailedRayPicks = function (scene) {
- // Modifies array during iteration
- const rayPicks = this._mostDetailedRayPicks;
- for (let i = 0; i < rayPicks.length; ++i) {
- if (updateMostDetailedRayPick(this, scene, rayPicks[i])) {
- rayPicks.splice(i--, 1);
- }
- }
- };
-
- function getTilesets(primitives, objectsToExclude, tilesets) {
- for (let i = 0; i < primitives.length; ++i) {
- const primitive = primitives.get(i);
- if (primitive.show) {
- if (defined(primitive.isCesium3DTileset)) {
- if (
- !defined(objectsToExclude) ||
- objectsToExclude.indexOf(primitive) === -1
- ) {
- tilesets.push(primitive);
- }
- } else if (primitive instanceof PrimitiveCollection) {
- getTilesets(primitive, objectsToExclude, tilesets);
- }
- }
- }
- }
-
- /**
- * @private
- * @param {Picking} picking
- * @param {Scene} scene
- * @param {Ray} ray
- * @param {object[] | undefined} objectsToExclude
- * @param {number | undefined} width
- * @param {Function} callback
- * @returns {Promise<Cartesian3 | undefined>}
- */
- function launchMostDetailedRayPick(
- picking,
- scene,
- ray,
- objectsToExclude,
- width,
- callback,
- ) {
- const tilesets = [];
- getTilesets(scene.primitives, objectsToExclude, tilesets);
- if (tilesets.length === 0) {
- return Promise.resolve(callback());
- }
-
- const 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,
- ) {
- const { context, frameState } = scene;
- const uniformState = context.uniformState;
-
- const view = picking._pickOffscreenView;
- scene.view = view;
-
- updateOffscreenCameraFromRay(picking, ray, width, view.camera);
-
- const drawingBufferRectangle = BoundingRectangle.clone(
- view.viewport,
- scratchRectangle,
- );
-
- const passState = view.pickFramebuffer.begin(
- drawingBufferRectangle,
- 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);
-
- let position;
- // Picking one object, result is either [object] or []
- const object = view.pickFramebuffer.end(drawingBufferRectangle, 1)[0];
-
- if (scene.context.depthTexture) {
- const { frustumCommandsList } = view;
- const numFrustums = frustumCommandsList.length;
- for (let i = 0; i < numFrustums; ++i) {
- const pickDepth = picking.getPickDepth(scene, i);
- const depth = pickDepth.getDepth(context, 0, 0);
- if (!defined(depth)) {
- continue;
- }
- if (depth > 0.0 && depth < 1.0) {
- const renderedFrustum = frustumCommandsList[i];
- const near =
- renderedFrustum.near *
- (i !== 0 ? scene.opaqueFrustumNearOffset : 1.0);
- const far = renderedFrustum.far;
- const 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 drillPickFromRay(
- picking,
- scene,
- ray,
- limit,
- objectsToExclude,
- width,
- requirePosition,
- mostDetailed,
- ) {
- const pickCallback = function () {
- const pickResult = getRayIntersection(
- picking,
- scene,
- ray,
- objectsToExclude,
- width,
- requirePosition,
- mostDetailed,
- );
- return pickResult ? [pickResult] : undefined;
- };
- return drillPick(pickCallback, limit);
- }
-
- function pickFromRay(
- picking,
- scene,
- ray,
- objectsToExclude,
- width,
- requirePosition,
- mostDetailed,
- ) {
- // Use drillPickFromRay rather than getRayIntersection directly to select the first non-excluded object
- const results = drillPickFromRay(
- picking,
- scene,
- ray,
- 1,
- objectsToExclude,
- width,
- requirePosition,
- mostDetailed,
- );
- if (results.length > 0) {
- return results[0];
- }
- }
-
- 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.
- return new Promise((resolve, reject) => {
- promise
- .then(function (result) {
- const removeCallback = scene.postRender.addEventListener(function () {
- removeCallback();
- resolve(result);
- });
- scene.requestRender();
- })
- .catch(function (error) {
- reject(error);
- });
- });
- }
-
- 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');
-
- const 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');
-
- const 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,
- );
- },
- ),
- );
- };
-
- const scratchSurfacePosition = new Cartesian3();
- const scratchSurfaceNormal = new Cartesian3();
- const scratchSurfaceRay = new Ray();
- const scratchCartographic = new Cartographic();
-
- /**
- * @private
- * @param {Scene} scene
- * @param {Cartographic} cartographic
- * @returns {Ray}
- */
- function getRayForSampleHeight(scene, cartographic) {
- const ellipsoid = scene.ellipsoid;
- const height = ApproximateTerrainHeights._defaultMaxTerrainHeight;
- const surfaceNormal = ellipsoid.geodeticSurfaceNormalCartographic(
- cartographic,
- scratchSurfaceNormal,
- );
- const surfacePosition = Cartographic.toCartesian(
- cartographic,
- ellipsoid,
- scratchSurfacePosition,
- );
- const surfaceRay = scratchSurfaceRay;
- surfaceRay.origin = surfacePosition;
- surfaceRay.direction = surfaceNormal;
- const ray = new Ray();
- Ray.getPoint(surfaceRay, height, ray.origin);
- Cartesian3.negate(surfaceNormal, ray.direction);
- return ray;
- }
-
- /**
- * @private
- * @param {Scene} scene
- * @param {Cartesian3} cartesian
- * @returns {Ray}
- */
- function getRayForClampToHeight(scene, cartesian) {
- const ellipsoid = scene.ellipsoid;
- const cartographic = Cartographic.fromCartesian(
- cartesian,
- ellipsoid,
- scratchCartographic,
- );
- return getRayForSampleHeight(scene, cartographic);
- }
-
- function getHeightFromCartesian(scene, cartesian) {
- const ellipsoid = scene.ellipsoid;
- const cartographic = Cartographic.fromCartesian(
- cartesian,
- ellipsoid,
- scratchCartographic,
- );
- return cartographic.height;
- }
-
- function sampleHeightMostDetailed(
- picking,
- scene,
- cartographic,
- objectsToExclude,
- width,
- ) {
- const ray = getRayForSampleHeight(scene, cartographic);
- return launchMostDetailedRayPick(
- picking,
- scene,
- ray,
- objectsToExclude,
- width,
- function () {
- const pickResult = pickFromRay(
- picking,
- scene,
- ray,
- objectsToExclude,
- width,
- true,
- true,
- );
- if (defined(pickResult)) {
- return getHeightFromCartesian(scene, pickResult.position);
- }
- },
- );
- }
-
- /**
- * @private
- * @param {Picking} picking
- * @param {Scene} scene
- * @param {Cartesian3} cartesian
- * @param {object[]} [objectsToExclude]
- * @param {number} [width]
- * @param {Cartesian3} [result]
- * @returns {Promise<Cartesian3 | undefined>}
- */
- function clampToHeightMostDetailed(
- picking,
- scene,
- cartesian,
- objectsToExclude,
- width,
- result,
- ) {
- const ray = getRayForClampToHeight(scene, cartesian);
- return launchMostDetailedRayPick(
- picking,
- scene,
- ray,
- objectsToExclude,
- width,
- function () {
- const 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');
-
- const ray = getRayForSampleHeight(scene, position);
- const 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');
-
- const ray = getRayForClampToHeight(scene, cartesian);
- const 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;
- const length = positions.length;
- const promises = new Array(length);
- for (let i = 0; i < length; ++i) {
- promises[i] = sampleHeightMostDetailed(
- this,
- scene,
- positions[i],
- objectsToExclude,
- width,
- );
- }
- return deferPromiseUntilPostRender(
- scene,
- Promise.all(promises).then(function (heights) {
- const length = heights.length;
- for (let i = 0; i < length; ++i) {
- positions[i].height = heights[i];
- }
- return positions;
- }),
- );
- };
-
- /**
- * @private
- * @param {Scene} scene
- * @param {Cartesian3[]} cartesians
- * @param {object[]} [objectsToExclude]
- * @param {number} [width]
- * @returns {Promise<Array<Cartesian3 | undefined>>}
- */
- 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;
- const length = cartesians.length;
- const promises = new Array(length);
- for (let i = 0; i < length; ++i) {
- promises[i] = clampToHeightMostDetailed(
- this,
- scene,
- cartesians[i],
- objectsToExclude,
- width,
- cartesians[i],
- );
- }
- return deferPromiseUntilPostRender(
- scene,
- Promise.all(promises).then(function (clampedCartesians) {
- const length = clampedCartesians.length;
- for (let 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;
|