UNPKG

@cesium/engine

Version:

CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.

275 lines (257 loc) 7.76 kB
import Cartesian3 from "../Core/Cartesian3.js"; import Check from "../Core/Check.js"; import defined from "../Core/defined.js"; import MetadataType from "./MetadataType.js"; import OrientedBoundingBox from "../Core/OrientedBoundingBox.js"; /** * A cell from a {@link VoxelPrimitive}. * <p> * Provides access to properties associated with one cell of a voxel primitive. * </p> * <p> * Do not construct this directly. Access it through picking using {@link Scene#pickVoxel}. * </p> * * @alias VoxelCell * @constructor * * @param {VoxelPrimitive} primitive The voxel primitive containing the cell * @param {number} tileIndex The index of the tile * @param {number} sampleIndex The index of the sample within the tile, containing metadata for this cell * * @example * // On left click, display all the properties for a voxel cell in the console log. * handler.setInputAction(function(movement) { * const voxelCell = scene.pickVoxel(movement.position); * if (voxelCell instanceof Cesium.VoxelCell) { * const propertyIds = voxelCell.getPropertyIds(); * const length = propertyIds.length; * for (let i = 0; i < length; ++i) { * const propertyId = propertyIds[i]; * console.log(`{propertyId}: ${voxelCell.getProperty(propertyId)}`); * } * } * }, Cesium.ScreenSpaceEventType.LEFT_CLICK); * * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy. */ function VoxelCell(primitive, tileIndex, sampleIndex) { this._primitive = primitive; this._tileIndex = tileIndex; this._sampleIndex = sampleIndex; this._metadata = {}; this._orientedBoundingBox = new OrientedBoundingBox(); } /** * Construct a VoxelCell, and update the metadata and bounding box using the properties * of a supplied keyframe node. * * @private * @param {VoxelPrimitive} primitive The voxel primitive containing the cell. * @param {number} tileIndex The index of the tile. * @param {number} sampleIndex The index of the sample within the tile, containing metadata for this cell. * @param {KeyframeNode} keyframeNode The keyframe node containing information about the tile. * @returns {VoxelCell} * * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy. */ VoxelCell.fromKeyframeNode = function ( primitive, tileIndex, sampleIndex, keyframeNode, ) { //>>includeStart('debug', pragmas.debug); Check.typeOf.object("primitive", primitive); Check.typeOf.number("tileIndex", tileIndex); Check.typeOf.number("sampleIndex", sampleIndex); Check.typeOf.object("keyframeNode", keyframeNode); //>>includeEnd('debug'); const voxelCell = new VoxelCell(primitive, tileIndex, sampleIndex); const { spatialNode, content } = keyframeNode; voxelCell._metadata = getMetadataForSample(primitive, content, sampleIndex); voxelCell._orientedBoundingBox = getOrientedBoundingBox( primitive, spatialNode, sampleIndex, voxelCell._orientedBoundingBox, ); return voxelCell; }; /** * @private * @param {VoxelPrimitive} primitive * @param {VoxelContent} content * @param {number} sampleIndex * @returns {object} */ function getMetadataForSample(primitive, content, sampleIndex) { if (!defined(content) || !defined(content.metadata)) { return undefined; } const { names, types } = primitive.provider; const { metadata } = content; const metadataMap = {}; for (let i = 0; i < names.length; i++) { const name = names[i]; const componentCount = MetadataType.getComponentCount(types[i]); const samples = metadata[i].slice( sampleIndex * componentCount, (sampleIndex + 1) * componentCount, ); metadataMap[name] = samples; } return metadataMap; } const tileCoordinateScratch = new Cartesian3(); const tileUvScratch = new Cartesian3(); /** * @private * @param {VoxelPrimitive} primitive * @param {SpatialNode} spatialNode * @param {OrientedBoundingBox} result * @returns {OrientedBoundingBox} */ function getOrientedBoundingBox(primitive, spatialNode, sampleIndex, result) { // Convert the sample index into a 3D tile coordinate // Note: dimensions from the spatialNode include padding const paddedDimensions = spatialNode.dimensions; const sliceSize = paddedDimensions.x * paddedDimensions.y; const zIndex = Math.floor(sampleIndex / sliceSize); const indexInSlice = sampleIndex - zIndex * sliceSize; const yIndex = Math.floor(indexInSlice / paddedDimensions.x); const xIndex = indexInSlice - yIndex * paddedDimensions.x; const tileCoordinate = Cartesian3.fromElements( xIndex, yIndex, zIndex, tileCoordinateScratch, ); // Remove padding, and convert to a fraction in [0, 1], where the limits are // the unpadded bounds of the tile const tileUv = Cartesian3.divideComponents( Cartesian3.subtract( tileCoordinate, primitive._paddingBefore, tileCoordinateScratch, ), primitive.dimensions, tileUvScratch, ); const shape = primitive._shape; return shape.computeOrientedBoundingBoxForSample( spatialNode, primitive.dimensions, tileUv, result, ); } Object.defineProperties(VoxelCell.prototype, { /** * Gets an object of the metadata values for this cell. The object's keys are the metadata names. * * @memberof VoxelCell.prototype * * @type {object} * * @readonly * @private */ metadata: { get: function () { return this._metadata; }, }, /** * All objects returned by {@link Scene#pick} have a <code>primitive</code> property. This returns * the VoxelPrimitive containing the cell. * * @memberof VoxelCell.prototype * * @type {VoxelPrimitive} * * @readonly */ primitive: { get: function () { return this._primitive; }, }, /** * Get the sample index of the cell. * * @memberof VoxelCell.prototype * * @type {number} * * @readonly */ sampleIndex: { get: function () { return this._sampleIndex; }, }, /** * Get the index of the tile containing the cell. * * @memberof VoxelCell.prototype * * @type {number} * * @readonly */ tileIndex: { get: function () { return this._tileIndex; }, }, /** * Get a copy of the oriented bounding box containing the cell. * * @memberof VoxelCell.prototype * * @type {OrientedBoundingBox} * * @readonly */ orientedBoundingBox: { get: function () { return this._orientedBoundingBox.clone(); }, }, }); /** * Returns <code>true</code> if the feature contains this property. * * @param {string} name The case-sensitive name of the property. * @returns {boolean} Whether the feature contains this property. */ VoxelCell.prototype.hasProperty = function (name) { return defined(this._metadata[name]); }; /** * Returns an array of metadata property names for the feature. * * @returns {string[]} The IDs of the feature's properties. */ VoxelCell.prototype.getNames = function () { return Object.keys(this._metadata); }; /** * Returns a copy of the value of the metadata in the cell with the given name. * * @param {string} name The case-sensitive name of the property. * @returns {*} The value of the property or <code>undefined</code> if the feature does not have this property. * * @example * // Display all the properties for a voxel cell in the console log. * const names = voxelCell.getNames(); * for (let i = 0; i < names.length; ++i) { * const name = names[i]; * console.log(`{name}: ${voxelCell.getProperty(name)}`); * } */ VoxelCell.prototype.getProperty = function (name) { return this._metadata[name]; }; export default VoxelCell;