itowns
Version:
A JS/WebGL framework for 3D geospatial data visualization
131 lines (126 loc) • 6.07 kB
JavaScript
import binaryPropertyAccessor from "./utils/BinaryPropertyAccessor.js";
import { C3DTilesTypes } from "./C3DTilesEnums.js";
const utf8Decoder = new TextDecoder();
/**
* A 3D Tiles
* [batch
* table](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/BatchTable).
* @property {C3DTilesTypes} type - Used by 3D Tiles extensions
* (e.g. {@link C3DTBatchTableHierarchyExtension}) to know in which context
* (i.e. for which 3D Tiles class) the parsing of the extension should be done.
* @property {number} batchLength - the length of the batch.
* @property {object} content - the content of the batch table in the form:
* {property1: values[], property2: values[], ...}.
* @property {object} extensions - 3D Tiles extensions of the batch table
* stored in the following format:
* {extensioName1: extensionObject1, extensioName2: extensionObject2, ...}
*/
class C3DTBatchTable {
/**
* @param {ArrayBuffer} [buffer=new ArrayBuffer()] - batch table buffer to parse
* @param {number} [jsonLength=0] - batch table json part length
* @param {number} [binaryLength=0] - batch table binary part length
* @param {number} [batchLength=0] - the length of the batch.
* @param {Object} [registeredExtensions] - extensions registered to the layer
*/
constructor() {
let buffer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new ArrayBuffer();
let jsonLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
let binaryLength = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
let batchLength = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
let registeredExtensions = arguments.length > 4 ? arguments[4] : undefined;
if (arguments.length === 4 && typeof batchLength === 'object' && !Array.isArray(batchLength) && batchLength !== null) {
console.warn('You most likely used a deprecated constructor of C3DTBatchTable.');
}
if (jsonLength + binaryLength !== buffer.byteLength) {
console.error('3DTiles batch table json length and binary length are not consistent with total buffer' + ' length. The batch table may be wrong.');
}
this.type = C3DTilesTypes.batchtable;
this.batchLength = batchLength;
const jsonBuffer = buffer.slice(0, jsonLength);
const decodedJsonBuffer = utf8Decoder.decode(new Uint8Array(jsonBuffer));
const jsonContent = decodedJsonBuffer === '' ? null : JSON.parse(decodedJsonBuffer);
if (binaryLength > 0) {
const binaryBuffer = buffer.slice(jsonLength, jsonLength + binaryLength);
for (const propKey in jsonContent) {
if (!Object.prototype.hasOwnProperty.call(jsonContent, propKey)) {
continue;
}
const propVal = jsonContent[propKey];
// Batch table entries that have already been parsed from the JSON buffer have an array of values.
if (Array.isArray(propVal)) {
continue;
}
if (typeof propVal?.byteOffset !== 'undefined' && typeof propVal?.componentType !== 'undefined' && typeof propVal?.type !== 'undefined') {
jsonContent[propKey] = binaryPropertyAccessor(binaryBuffer, this.batchLength, propVal.byteOffset, propVal.componentType, propVal.type);
} else {
console.error('Invalid 3D Tiles batch table property that is neither a JSON array nor a valid ' + 'accessor to a binary body');
}
}
}
// Separate the content and the possible extensions
// When an extension is found, we call its parser and append the
// returned object to batchTable.extensions
// Extensions must be registered in the layer (see an example of this in
// 3dtiles_hierarchy.html)
if (jsonContent && jsonContent.extensions) {
this.extensions = registeredExtensions.parseExtensions(jsonContent.extensions, this.type);
delete jsonContent.extensions;
}
// Store batch table json content
this.content = jsonContent;
}
/**
* Creates and returns a javascript object holding the displayable
* information from the batch table and from extensions of the batch table,
* for a given feature (identified with its batchID).
* @param {integer} batchID - id of the feature
* @returns {Object} - displayable information relative to the batch
* table and its extensions. Object is formatted as follow:
* {batchTable:
* {property1: value1
* property2: value2
* ...}
* extensions:
* {extension1:
* {property1: value1
* ...}
* extension2: {...}
* ...}
* }
*/
getInfoById(batchID) {
// Verify that the batch ID is valid
if (batchID < 0 && batchID < this.batchLength) {
throw new Error(`Batch Id (${batchID}) must be between 0 and
${this.batchLength} to access feature properties from the batch
table.`);
}
const featureDisplayableInfo = {};
featureDisplayableInfo.batchTable = {};
// Get properties from batch table content
for (const property in this.content) {
// check that the property is not inherited from prototype chain
if (Object.prototype.hasOwnProperty.call(this.content, property)) {
const val = this.content[property][batchID];
// Property value may be a threejs vector (see 3D Tiles spec and BinaryPropertyAccessor.js)
if (val && (val.isVector2 || val.isVector3 || val.isVector4)) {
featureDisplayableInfo.batchTable[property] = val.toArray();
} else {
featureDisplayableInfo.batchTable[property] = val;
}
}
}
// Extensions
if (this.extensions) {
featureDisplayableInfo.extensions = {};
for (const extName in this.extensions) {
if (Object.prototype.hasOwnProperty.call(this.extensions, extName)) {
featureDisplayableInfo.extensions[extName] = this.extensions[extName].getInfoById(batchID);
}
}
}
return featureDisplayableInfo;
}
}
export default C3DTBatchTable;