UNPKG

@cesium/engine

Version:

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

453 lines (392 loc) 13.4 kB
// @ts-check import BufferPoint from "./BufferPoint.js"; import BufferPointCollection from "./BufferPointCollection.js"; import BufferPointMaterial from "./BufferPointMaterial.js"; import BufferPolygon from "./BufferPolygon.js"; import BufferPolygonCollection from "./BufferPolygonCollection.js"; import BufferPolygonMaterial from "./BufferPolygonMaterial.js"; import BufferPolyline from "./BufferPolyline.js"; import BufferPolylineCollection from "./BufferPolylineCollection.js"; import BufferPolylineMaterial from "./BufferPolylineMaterial.js"; import Cesium3DTileStyle from "./Cesium3DTileStyle.js"; import Matrix4 from "../Core/Matrix4.js"; import Model from "./Model/Model.js"; import ModelUtility from "./Model/ModelUtility.js"; import Pass from "../Renderer/Pass.js"; import createVectorTileBuffersFromModelComponents from "./Model/createVectorTileBuffersFromModelComponents.js"; import defined from "../Core/defined.js"; import destroyObject from "../Core/destroyObject.js"; import DeveloperError from "../Core/DeveloperError.js"; /** @import BufferPrimitive from "./BufferPrimitive.js"; */ /** @import BufferPrimitiveCollection from "./BufferPrimitiveCollection.js"; */ /** @import Cartesian3 from "../Core/Cartesian3.js"; */ /** @import Cesium3DContentGroup from "./Cesium3DContentGroup.js"; */ /** @import Cesium3DTile from "./Cesium3DTile.js"; */ /** @import Cesium3DTileBatchTable from "./Cesium3DTileBatchTable.js"; */ /** @import Cesium3DTileVectorFeature from "./Cesium3DTileVectorFeature.js";*/ /** @import Cesium3DTileset from "./Cesium3DTileset.js"; */ /** @import Color from "../Core/Color.js"; */ /** @import FrameState from "./FrameState.js"; */ /** @import ImplicitMetadataView from "./ImplicitMetadataView.js"; */ /** @import Ray from "../Core/Ray.js"; */ /** @import Resource from "../Core/Resource.js"; */ /** @ignore */ const point = new BufferPoint(); /** @ignore */ const polyline = new BufferPolyline(); /** @ignore */ const polygon = new BufferPolygon(); /** @ignore */ const pointMaterial = new BufferPointMaterial(); /** @ignore */ const polylineMaterial = new BufferPolylineMaterial(); /** @ignore */ const polygonMaterial = new BufferPolygonMaterial(); /** @ignore */ const scratchTileModelMatrix = new Matrix4(); /** * Vector glTF tile content. This path decodes glTF primitives into vector * buffers, then renders with dedicated vector primitives. * * @ignore */ class VectorGltf3DTileContent { /** * @param {Cesium3DTileset} tileset * @param {Cesium3DTile} tile * @param {Resource} resource */ constructor(tileset, tile, resource) { /** @type {Cesium3DTileset} */ this._tileset = tileset; /** @type {Cesium3DTile} */ this._tile = tile; /** @type {Resource} */ this._resource = resource; /** @type {Model} */ this._model = undefined; /** * List of all vector primitive collections. * @type {Array<BufferPrimitiveCollection<BufferPrimitive>>} */ this._collections = []; /** * List of transform matrices for each collection; order matches 'collections'. * @type {Array<Matrix4>} */ this._collectionLocalMatrices = []; /** * Maps vector primitive collection -> propertyTableId. * @type {Map<BufferPrimitiveCollection<BufferPrimitive>, number>} */ this._collectionFeatureTableIds = new Map(); /** * Maps propertyTableId -> featureId -> feature. Note that Feature IDs are * unique within their assigned property table, but not globally unique. * @type {Map<number, Map<number, Cesium3DTileVectorFeature>>} */ this._featuresByTableId = new Map(); /** @type {ImplicitMetadataView} */ this._metadata = undefined; /** @type {Cesium3DContentGroup} */ this._group = undefined; /** @type {boolean} */ this.featurePropertiesDirty = false; /** @type {boolean} */ this._ready = false; /** @type {Matrix4} */ this._modelMatrix = Matrix4.clone(Matrix4.IDENTITY); } get featuresLength() { return this.batchTables.reduce( (acc, batchTable) => acc + batchTable.featuresLength, 0, ); } get pointsLength() { return this._collections .filter((collection) => collection instanceof BufferPointCollection) .reduce((acc, collection) => acc + collection.primitiveCount, 0); } get trianglesLength() { return this._collections.reduce((acc, collection) => { if (collection instanceof BufferPolygonCollection) { return acc + collection.triangleCount; } else if (collection instanceof BufferPolylineCollection) { return acc + (collection.vertexCount - collection.primitiveCount) * 2; } return acc; }, 0); } get geometryByteLength() { return this._collections.reduce((totalByteLength, collection) => { return totalByteLength + collection.byteLength; }, 0); } get texturesByteLength() { return 0; } get batchTableByteLength() { return this.batchTables.reduce( // @ts-expect-error Missing types. (acc, batchTable) => acc + batchTable.batchTableByteLength, 0, ); } /** @returns {undefined} */ get innerContents() { return undefined; } get ready() { return this._ready; } get tileset() { return this._tileset; } get tile() { return this._tile; } get url() { return this._resource.getUrlComponent(true); } /** @type {Cesium3DTileBatchTable[]} */ get batchTables() { return this._model._featureTables; } /** * @type {Cesium3DTileBatchTable} * @deprecated See {@link batchTables}. */ get batchTable() { throw new DeveloperError("Deprecated: Use `content.batchTables`."); } /** @type {ImplicitMetadataView} */ get metadata() { return this._metadata; } set metadata(value) { this._metadata = value; } /** @type {Cesium3DContentGroup} */ get group() { return this._group; } set group(value) { this._group = value; } /** * @param {number} featureId * @param {number} [featureTableId] * @returns {Cesium3DTileVectorFeature} */ getFeature(featureId, featureTableId) { return this._featuresByTableId.get(featureTableId)?.get(featureId); } /** * @param {number} featureId * @param {string} name * @param {number} [featureTableId] * @returns {boolean} */ hasProperty(featureId, name, featureTableId) { const feature = this.getFeature(featureId, featureTableId); return feature ? feature.hasProperty(name) : false; } /** * @param {boolean} enabled * @param {Color} color */ applyDebugSettings(enabled, color) { const colorString = enabled ? `color("${color.toCssHexString()}", 1.0)` : 'color("white", 1.0)'; this.applyStyle(new Cesium3DTileStyle({ color: colorString })); } /** * @param {*} style */ applyStyle(style) { const isPointCollection = /** @param {unknown} c */ (c) => c instanceof BufferPointCollection; const isPolylineCollection = /** @param {unknown} c */ (c) => c instanceof BufferPolylineCollection; const isPolygonCollection = /** @param {unknown} c */ (c) => c instanceof BufferPolygonCollection; for (const collection of this._collections.filter(isPointCollection)) { const featureTableId = this._collectionFeatureTableIds.get(collection); for (let i = 0, il = collection.primitiveCount; i < il; i++) { collection.get(i, point); const feature = this.getFeature(point.featureId, featureTableId); if (defined(style.show)) { point.show = style.show.evaluate(feature); } if (defined(style.color)) { style.color.evaluate(feature, pointMaterial.color); } if (defined(style.pointSize)) { pointMaterial.size = style.pointSize.evaluate(feature); } if (defined(style.pointOutlineWidth)) { pointMaterial.outlineWidth = style.pointOutlineWidth.evaluate(feature); } if (defined(style.pointOutlineColor)) { style.pointOutlineColor.evaluate(feature, pointMaterial.outlineColor); } point.setMaterial(pointMaterial); } } for (const collection of this._collections.filter(isPolylineCollection)) { const featureTableId = this._collectionFeatureTableIds.get(collection); for (let i = 0, il = collection.primitiveCount; i < il; i++) { collection.get(i, polyline); const feature = this.getFeature(polyline.featureId, featureTableId); if (defined(style.show)) { polyline.show = style.show.evaluate(feature); } if (defined(style.color)) { style.color.evaluate(feature, polylineMaterial.color); } if (defined(style.lineWidth)) { polylineMaterial.width = style.lineWidth.evaluate(feature); } polyline.setMaterial(polylineMaterial); } } for (const collection of this._collections.filter(isPolygonCollection)) { const featureTableId = this._collectionFeatureTableIds.get(collection); for (let i = 0, il = collection.primitiveCount; i < il; i++) { collection.get(i, polygon); const feature = this.getFeature(polygon.featureId, featureTableId); if (defined(style.show)) { polygon.show = style.show.evaluate(feature); } if (defined(style.color)) { style.color.evaluate(feature, polygonMaterial.color); } polygon.setMaterial(polygonMaterial); } } } /** * @param {Cesium3DTileset} _tileset * @param {FrameState} frameState */ update(_tileset, frameState) { if (defined(this._model) && !this._ready) { const model = this._model; model.modelMatrix = this._tile.computedTransform; model.update(frameState); // @ts-expect-error Requires Model conversion to ES6 class. if (model.ready) { initializeVectorPrimitives(this); this._ready = true; } } Matrix4.multiplyTransformation( this._tile.computedTransform, this._modelMatrix, scratchTileModelMatrix, ); for (let i = 0; i < this._collections.length; i++) { Matrix4.multiplyTransformation( scratchTileModelMatrix, this._collectionLocalMatrices[i], this._collections[i].modelMatrix, ); this._collections[i].update(frameState); } } /** * @param {Ray} _ray * @param {FrameState} _frameState * @param {Cartesian3|undefined} _result * @returns {Cartesian3|undefined} */ pick(_ray, _frameState, _result) { return undefined; } isDestroyed() { return false; } destroy() { this._model?.destroy(); this._model = undefined; this._collections.forEach((collection) => collection.destroy()); this._collections.length = 0; return destroyObject(this); } /** * @param {Cesium3DTileset} tileset * @param {Cesium3DTile} tile * @param {Resource} resource * @param {Uint8Array} glb GLB binary produced by buildVectorGltfFromMVT * @returns {Promise<VectorGltf3DTileContent>} */ static async fromGltf(tileset, tile, resource, glb) { const content = new VectorGltf3DTileContent(tileset, tile, resource); const modelOptions = makeModelOptions(tileset, tile, content, glb); const model = await Model.fromGltfAsync(modelOptions); // @ts-expect-error Requires Model conversion to ES6 class. model.show = false; content._model = model; return content; } } /** * @param {Cesium3DTileset} tileset * @param {Cesium3DTile} tile * @param {VectorGltf3DTileContent} content * @param {Uint8Array} glb * @returns {*} * @ignore */ function makeModelOptions(tileset, tile, content, glb) { return { gltf: glb, basePath: content._resource, cull: false, releaseGltfJson: true, opaquePass: Pass.CESIUM_3D_TILE, modelMatrix: tile.computedTransform, upAxis: tileset._modelUpAxis, forwardAxis: tileset._modelForwardAxis, incrementallyLoadTextures: false, content: content, // @ts-expect-error Requires Cesium3DTileset conversion to ES6 class. featureIdLabel: tileset.featureIdLabel, // @ts-expect-error Requires Cesium3DTileset conversion to ES6 class. instanceFeatureIdLabel: tileset.instanceFeatureIdLabel, projectTo2D: tileset._projectTo2D, enablePick: tileset._enablePick, enableDebugWireframe: tileset._enableDebugWireframe, enableShowOutline: false, }; } /** * @param {VectorGltf3DTileContent} content * @ignore */ function initializeVectorPrimitives(content) { // @ts-expect-error Requires Model conversion to ES6 class. const components = content._model.sceneGraph.components; const axisCorrection = ModelUtility.getAxisCorrectionMatrix( components.upAxis, components.forwardAxis, new Matrix4(), ); Matrix4.multiplyTransformation( components.transform, axisCorrection, content._modelMatrix, ); const result = createVectorTileBuffersFromModelComponents( content, components, ); content._collections = result.collections; content._collectionLocalMatrices = result.collectionLocalMatrices; content._collectionFeatureTableIds = result.collectionFeatureTableIds; content._featuresByTableId = result.featuresByTableId; } export default VectorGltf3DTileContent;