UNPKG

@itwin/core-frontend

Version:
173 lines • 10 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Tiles */ Object.defineProperty(exports, "__esModule", { value: true }); exports.B3dmReader = void 0; const core_bentley_1 = require("@itwin/core-bentley"); const core_geometry_1 = require("@itwin/core-geometry"); const core_common_1 = require("@itwin/core-common"); const GltfSchema_1 = require("../../common/gltf/GltfSchema"); const internal_1 = require("../../tile/internal"); /** * Deserializes a tile in [b3dm](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/Batched3DModel) format. */ class B3dmReader extends internal_1.GltfReader { _range; _isLeaf; _batchTableLength; _transformToRoot; _batchTableJson; _pseudoRtcBias; _batchIdRemap = new Map(); _colors; _modelId; static create(stream, iModel, modelId, is3d, range, system, yAxisUp, isLeaf, tileCenter, transformToRoot, isCanceled, idMap, deduplicateVertices = false, tileData) { const header = new core_common_1.B3dmHeader(stream); if (!header.isValid) return undefined; let returnToCenterTransform, pseudoRtcBias; if (header.featureTableJson && Array.isArray(header.featureTableJson.RTC_CENTER)) { returnToCenterTransform = core_geometry_1.Transform.createTranslationXYZ(header.featureTableJson.RTC_CENTER[0], header.featureTableJson.RTC_CENTER[1], header.featureTableJson.RTC_CENTER[2]); } else { /** * This is a workaround for tiles generated by * context capture which have a large offset from the tileset origin that exceeds the * capacity of 32 bit integers. It is essentially an ad hoc RTC applied at read time only if the tile is far from the * origin and there is no RTC supplied either with the B3DM of the GLTF. * as the vertices are supplied in a quantized format, applying the RTC bias to * quantization origin will make these tiles work correctly. */ pseudoRtcBias = core_geometry_1.Vector3d.create(tileCenter.x, tileCenter.y, tileCenter.z); } if (undefined !== returnToCenterTransform) transformToRoot = transformToRoot ? transformToRoot.multiplyTransformTransform(returnToCenterTransform) : returnToCenterTransform; const props = internal_1.GltfReaderProps.create(stream.nextBytes(header.length - stream.curPos), yAxisUp); const batchTableLength = header.featureTableJson ? core_bentley_1.JsonUtils.asInt(header.featureTableJson.BATCH_LENGTH, 0) : 0; return undefined !== props ? new B3dmReader(props, iModel, modelId, is3d, system, range, isLeaf, batchTableLength, transformToRoot, header.batchTableJson, isCanceled, idMap, pseudoRtcBias, deduplicateVertices, tileData) : undefined; } constructor(props, iModel, modelId, is3d, system, _range, _isLeaf, _batchTableLength, _transformToRoot, _batchTableJson, shouldAbort, _idMap, _pseudoRtcBias, deduplicateVertices = false, tileData) { super({ props, iModel, system, shouldAbort, deduplicateVertices, is2d: !is3d, idMap: _idMap, tileData }); this._range = _range; this._isLeaf = _isLeaf; this._batchTableLength = _batchTableLength; this._transformToRoot = _transformToRoot; this._batchTableJson = _batchTableJson; this._pseudoRtcBias = _pseudoRtcBias; this._modelId = modelId; } async read() { // NB: For reality models with no batch table, we want the model ID in the feature table const featureTable = new core_common_1.FeatureTable(this._batchTableLength ? this._batchTableLength : 1, this._modelId, this._type); if (this._batchTableLength > 0 && this._idMap !== undefined && this._batchTableJson !== undefined) { if (this._batchTableJson.extensions && this._batchTableJson.extensions["3DTILES_batch_table_hierarchy"]) { const hierarchy = this._batchTableJson.extensions["3DTILES_batch_table_hierarchy"]; const { classIds, classes, parentIds, parentCounts, instancesLength } = hierarchy; if (classes !== undefined && classIds !== undefined && instancesLength !== 0) { const classCounts = new Array(classes.length); classCounts.fill(0); const classIndexes = new Uint16Array(instancesLength); for (let i = 0; i < instancesLength; ++i) { const classId = classIds[i]; classIndexes[i] = classCounts[classId]++; } let parentMap; if (parentIds) { parentMap = new Array(); for (let i = 0, parentIndex = 0; i < instancesLength; i++) { const parentCount = parentCounts === undefined ? 1 : parentCounts[i]; parentMap[i] = parentIds.slice(parentIndex, parentIndex += parentCount); } } const getProperties = (instance, instanceIndex) => { const classId = classIds[instanceIndex]; const instanceClass = classes[classId]; const instances = instanceClass.instances; const indexInClass = classIndexes[instanceIndex]; for (const key in instances) { // eslint-disable-line guard-for-in const value = instances[key][indexInClass]; if (value !== undefined && value !== null) instance[key] = value; } if (parentIds !== undefined) { const thisParents = parentMap[instanceIndex]; for (const parentId of thisParents) { if (parentId !== instanceIndex) getProperties(instance, parentId); } } }; for (let batchId = 0; batchId < instancesLength; batchId++) { const instance = {}; getProperties(instance, batchId); this._batchIdRemap.set(batchId, featureTable.insert(new core_common_1.Feature(this._idMap.getBatchId(instance)))); const cesiumColor = instance["cesium#color"]; if (undefined !== cesiumColor) { if (!this._colors) { this._colors = new Array(instancesLength); this._colors.fill(core_common_1.ColorDef.white.tbgr); } this._colors[batchId] = core_common_1.ColorDef.create(cesiumColor).tbgr; } } } } else { for (let i = 0; i < this._batchTableLength; i++) { const feature = {}; for (const key in this._batchTableJson) // eslint-disable-line guard-for-in feature[key] = this._batchTableJson[key][i]; this._batchIdRemap.set(i, featureTable.insert(new core_common_1.Feature(this._idMap.getBatchId(feature)))); } } } if (featureTable.isEmpty) { this._batchIdRemap.set(0, 0); const feature = new core_common_1.Feature(this._modelId); featureTable.insert(feature); } await this.resolveResources(); if (this._isCanceled) return { readStatus: core_common_1.TileReadStatus.Canceled, isLeaf: this._isLeaf }; return this.readGltfAndCreateGraphics(this._isLeaf, featureTable, this._range, this._transformToRoot, this._pseudoRtcBias, undefined); } readBatchTable(mesh, json) { if (mesh.features !== undefined) { if (this._batchTableLength > 0 && undefined !== this._batchTableJson && undefined !== json.attributes) { const view = this.getBufferView(json.attributes, "_BATCHID"); let batchIds; if (undefined !== view && (undefined !== (batchIds = view.toBufferData(GltfSchema_1.GltfDataType.UInt32)) || undefined !== (batchIds = view.toBufferData(GltfSchema_1.GltfDataType.Float)))) { const indices = []; const { colors, colorMap } = mesh; let colorRemap; if (this._colors && this._colors.length === this._batchTableLength) { colorRemap = new Uint32Array(this._batchTableLength); for (let i = 0; i < this._batchTableLength; i++) colorRemap[i] = colorMap.insert(this._colors[i]); } for (let i = 0; i < batchIds.count; i++) { const batchId = batchIds.buffer[i * view.stride]; const remapId = this._batchIdRemap.get(batchId); indices.push(remapId === undefined ? 0 : remapId); if (colorRemap) colors.push(colorRemap[batchId]); } mesh.features.setIndices(indices); } } else { mesh.features.add(new core_common_1.Feature(this._modelId), 1); } } } } exports.B3dmReader = B3dmReader; //# sourceMappingURL=B3dmReader.js.map