@loaders.gl/tile-converter 4.2.0-beta.2 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/converter.min.cjs +2 -2
- package/dist/deps-installer/deps-installer.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/pgm-loader.js +1 -1
- package/package.json +16 -16
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["index.js", "i3s-converter/types.js", "i3s-converter/helpers/attribute-metadata-info.js", "i3s-converter/i3s-converter.js", "i3s-converter/helpers/node-pages.js", "i3s-converter/json-templates/metadata.js", "lib/utils/file-utils.js", "lib/utils/compress-util.js", "lib/utils/statistic-utills.js", "i3s-converter/helpers/geometry-converter.js", "i3s-converter/helpers/geometry-attributes.js", "i3s-converter/helpers/coordinate-converter.js", "i3s-converter/helpers/gltf-attributes.js", "i3s-converter/helpers/batch-ids-extensions.js", "i3s-converter/helpers/feature-attributes.js", "lib/utils/geometry-utils.js", "i3s-converter/helpers/create-scene-server-path.js", "i3s-converter/json-templates/scene-server.js", "lib/utils/lod-conversion-utils.js", "pgm-loader.js", "i3s-converter/json-templates/layers.js", "i3s-converter/json-templates/store.js", "i3s-converter/json-templates/geometry-definitions.js", "i3s-converter/json-templates/shared-resources.js", "i3s-converter/helpers/node-debug.js", "lib/utils/queue.js", "lib/utils/write-queue.js", "constants.js", "i3s-converter/helpers/node-index-document.js", "i3s-converter/json-templates/node.js", "i3s-converter/helpers/load-3d-tiles.js", "i3s-converter/helpers/tileset-traversal.js", "i3s-converter/helpers/preprocess-3d-tiles.js", "i3s-converter/helpers/progress.js", "lib/utils/conversion-dump.js", "lib/json-schemas/conversion-dump-json-schema.js", "3d-tiles-converter/3d-tiles-converter.js", "3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js", "3d-tiles-converter/json-templates/tileset.js", "3d-tiles-converter/helpers/b3dm-converter.js", "3d-tiles-converter/helpers/texture-atlas.js", "3d-tiles-converter/helpers/load-i3s.js"],
|
|
4
|
-
"sourcesContent": ["export { default as I3SConverter } from \"./i3s-converter/i3s-converter.js\";\nexport { default as Tiles3DConverter } from \"./3d-tiles-converter/3d-tiles-converter.js\";\n", "/**\n * glTF primitive modes (mesh topology types)\n * @see https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode\n */\nexport var GLTFPrimitiveModeString;\n(function (GLTFPrimitiveModeString) {\n GLTFPrimitiveModeString[\"POINTS\"] = \"POINTS\";\n GLTFPrimitiveModeString[\"LINES\"] = \"LINES\";\n GLTFPrimitiveModeString[\"LINE_LOOP\"] = \"LINE_LOOP\";\n GLTFPrimitiveModeString[\"LINE_STRIP\"] = \"LINE_STRIP\";\n GLTFPrimitiveModeString[\"TRIANGLES\"] = \"TRIANGLES\";\n GLTFPrimitiveModeString[\"TRIANGLE_STRIP\"] = \"TRIANGLE_STRIP\";\n GLTFPrimitiveModeString[\"TRIANGLE_FAN\"] = \"TRIANGLE_FAN\";\n})(GLTFPrimitiveModeString || (GLTFPrimitiveModeString = {}));\n/**\n * I3S' types difine the following:\n * type Attribute = 'OBJECTID' | 'string' | 'double' | 'Int32' | string;\n * The AttributeType contains the string values of the Attribute type.\n */\nexport const AttributeType = {\n /** Type of attribute that is linked with feature ids */\n OBJECT_ID_TYPE: 'OBJECTID',\n /** String data type name for feature attributes */\n STRING_TYPE: 'string',\n /** Double data type name for feature attributes */\n DOUBLE_TYPE: 'double',\n /** Integer data type name for feature attributes */\n SHORT_INT_TYPE: 'Int32'\n};\nexport var ResourceType;\n(function (ResourceType) {\n ResourceType[\"ATTRIBUTES\"] = \"ATTRIBUTES\";\n ResourceType[\"DRACO_GEOMETRY\"] = \"DRACO_GEOMETRY\";\n ResourceType[\"GEOMETRY\"] = \"GEOMETRY\";\n ResourceType[\"SHARED\"] = \"SHARED\";\n ResourceType[\"TEXTURE\"] = \"TEXTURE\";\n})(ResourceType || (ResourceType = {}));\n", "import { AttributeType } from \"../types.js\";\nexport class AttributeMetadataInfo {\n _attributeStorageInfo;\n _fields;\n _popupInfo;\n constructor() {\n this._attributeStorageInfo = [];\n this._fields = [];\n }\n get attributeStorageInfo() {\n return this._attributeStorageInfo;\n }\n get fields() {\n return this._fields;\n }\n get popupInfo() {\n return this._popupInfo;\n }\n /**\n * Creates and stores Attribute Storage Info, Fields and PopupInfo objects based on attribute's types.\n * Appends objects that have not been stored yet.\n * @param attributeTypesMap - set of attribute's types\n * @example AttributeStorageInfo, Fields and PopupInfo already contain objects for the following attributes:\n * {\n * color: 'string',\n * name: 'string',\n * opt_uint8: 'Int32'\n * }\n * Then, we call the addMetadataInfo method with the following attributeTypesMap:\n * {\n * // The same attributes\n * color: 'string',\n * name: 'string',\n * opt_uint8: 'Int32',\n * // New attributes\n * opt_uint64: 'string',\n * opt_float32: 'double',\n * }\n * The method creates and stores objects for opt_uint64, opt_float32 attributes.\n */\n addMetadataInfo(attributeTypesMap) {\n if (!Object.keys(attributeTypesMap).length) {\n return;\n }\n const attributeTypes = {\n OBJECTID: AttributeType.OBJECT_ID_TYPE,\n ...attributeTypesMap\n };\n let isUpdated = false;\n let attributeIndex = this._attributeStorageInfo.length;\n for (const key in attributeTypes) {\n /*\n We will append a new attribute only in case it has not been added to the attribute storage info yet.\n */\n const elementFound = this._attributeStorageInfo.find((element) => element.name === key);\n if (!elementFound) {\n const attributeType = attributeTypes[key];\n const storageAttribute = this.createStorageAttribute(attributeIndex, key, attributeType);\n const fieldAttributeType = this.getFieldAttributeType(attributeType);\n const fieldAttribute = this.createFieldAttribute(key, fieldAttributeType);\n this._attributeStorageInfo.push(storageAttribute);\n this._fields.push(fieldAttribute);\n attributeIndex += 1;\n isUpdated = true;\n }\n }\n if (isUpdated) {\n /*\n The attributeStorageInfo is updated. So, popupInfo should be recreated.\n Use attributeStorageInfo as a source of attribute names to create the popupInfo.\n */\n const attributeNames = [];\n for (const info of this._attributeStorageInfo) {\n attributeNames.push(info.name);\n }\n this._popupInfo = this.createPopupInfo(attributeNames);\n }\n }\n /**\n * Set AttributeMetadataInfo from object\n * @param object - object with AttributeMetadataInfo props\n */\n fromObject(object) {\n this._attributeStorageInfo = object.attributeStorageInfo;\n this._fields = object.fields;\n this._popupInfo = object.popupInfo;\n }\n /**\n * Generates storage attribute for map segmentation.\n * @param attributeIndex - order index of attribute (f_0, f_1 ...).\n * @param key - attribute key from propertyTable.\n * @param attributeType - attribute type.\n * @return Updated storageAttribute.\n */\n createStorageAttribute(attributeIndex, key, attributeType) {\n const storageAttribute = {\n key: `f_${attributeIndex}`,\n name: key,\n ordering: ['attributeValues'],\n header: [{ property: 'count', valueType: 'UInt32' }],\n attributeValues: { valueType: 'Int32', valuesPerElement: 1 }\n };\n switch (attributeType) {\n case AttributeType.OBJECT_ID_TYPE:\n this.setupIdAttribute(storageAttribute);\n break;\n case AttributeType.STRING_TYPE:\n this.setupStringAttribute(storageAttribute);\n break;\n case AttributeType.DOUBLE_TYPE:\n this.setupDoubleAttribute(storageAttribute);\n break;\n case AttributeType.SHORT_INT_TYPE:\n break;\n default:\n this.setupStringAttribute(storageAttribute);\n }\n return storageAttribute;\n }\n /**\n * Finds and returns attribute type based on key form propertyTable.\n * @param attributeType\n */\n getFieldAttributeType(attributeType) {\n switch (attributeType) {\n case AttributeType.OBJECT_ID_TYPE:\n return 'esriFieldTypeOID';\n case AttributeType.STRING_TYPE:\n return 'esriFieldTypeString';\n case AttributeType.SHORT_INT_TYPE:\n return 'esriFieldTypeInteger';\n case AttributeType.DOUBLE_TYPE:\n return 'esriFieldTypeDouble';\n default:\n return 'esriFieldTypeString';\n }\n }\n /**\n * Sets up Id attribute for map segmentation.\n * @param storageAttribute - attribute for map segmentation .\n */\n setupIdAttribute(storageAttribute) {\n storageAttribute.attributeValues = {\n valueType: 'Oid32',\n valuesPerElement: 1\n };\n }\n /**\n * Sets up storage attribute as string.\n * @param storageAttribute - attribute for map segmentation.\n */\n setupStringAttribute(storageAttribute) {\n // @ts-expect-error\n storageAttribute.ordering.unshift('attributeByteCounts');\n storageAttribute.header.push({ property: 'attributeValuesByteCount', valueType: 'UInt32' });\n storageAttribute.attributeValues = {\n valueType: 'String',\n encoding: 'UTF-8',\n valuesPerElement: 1\n };\n storageAttribute.attributeByteCounts = {\n valueType: 'UInt32',\n valuesPerElement: 1\n };\n }\n /**\n * Sets up double attribute for map segmentation.\n * @param storageAttribute - attribute for map segmentation .\n */\n setupDoubleAttribute(storageAttribute) {\n storageAttribute.attributeValues = {\n valueType: 'Float64',\n valuesPerElement: 1\n };\n }\n /**\n * Sets up field attribute for map segmentation.\n * @param key - attribute for map segmentation.\n * @param fieldAttributeType - esri attribute type ('esriFieldTypeString' or 'esriFieldTypeOID').\n */\n createFieldAttribute(key, fieldAttributeType) {\n return {\n name: key,\n type: fieldAttributeType,\n alias: key\n };\n }\n /**\n * Generates popup info to show metadata on the map.\n * @param propertyNames - array of property names including OBJECTID.\n * @return data for correct rendering of popup.\n */\n createPopupInfo(propertyNames) {\n const title = '{OBJECTID}';\n const mediaInfos = [];\n const fieldInfos = [];\n const popupElements = [];\n const expressionInfos = [];\n for (const propertyName of propertyNames) {\n fieldInfos.push({\n fieldName: propertyName,\n visible: true,\n isEditable: false,\n label: propertyName\n });\n }\n popupElements.push({\n fieldInfos,\n type: 'fields'\n });\n return {\n title,\n mediaInfos,\n popupElements,\n fieldInfos,\n expressionInfos\n };\n }\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { AttributeMetadataInfo } from \"./helpers/attribute-metadata-info.js\";\nimport { load, encode, isBrowser } from '@loaders.gl/core';\nimport { CesiumIonLoader, Tiles3DLoader } from '@loaders.gl/3d-tiles';\nimport { join } from 'path';\nimport { v4 as uuidv4 } from 'uuid';\nimport process from 'process';\nimport transform from 'json-map-transform';\nimport md5 from 'md5';\nimport NodePages from \"./helpers/node-pages.js\";\nimport { writeFile, removeDir, writeFileForSlpk, removeFile } from \"../lib/utils/file-utils.js\";\nimport { compressFileWithGzip } from \"../lib/utils/compress-util.js\";\nimport { calculateFilesSize, timeConverter } from \"../lib/utils/statistic-utills.js\";\nimport convertB3dmToI3sGeometry, { getPropertyTable } from \"./helpers/geometry-converter.js\";\nimport { createBoundingVolumes, convertBoundingVolumeToI3SFullExtent } from \"./helpers/coordinate-converter.js\";\nimport { createSceneServerPath } from \"./helpers/create-scene-server-path.js\";\nimport { convertGeometricErrorToScreenThreshold } from \"../lib/utils/lod-conversion-utils.js\";\nimport { PGMLoader } from \"../pgm-loader.js\";\nimport { LAYERS as layersTemplate } from \"./json-templates/layers.js\";\nimport { GEOMETRY_DEFINITION as geometryDefinitionTemlate } from \"./json-templates/geometry-definitions.js\";\nimport { SHARED_RESOURCES as sharedResourcesTemplate } from \"./json-templates/shared-resources.js\";\nimport { validateNodeBoundingVolumes } from \"./helpers/node-debug.js\";\nimport { KTX2BasisWriterWorker } from '@loaders.gl/textures';\nimport { ImageWriter } from '@loaders.gl/images';\nimport { GLTFPrimitiveModeString, ResourceType } from \"./types.js\";\nimport { WorkerFarm } from '@loaders.gl/worker-utils';\nimport WriteQueue from \"../lib/utils/write-queue.js\";\nimport { BROWSER_ERROR_MESSAGE } from \"../constants.js\";\nimport { getAttributeTypesMapFromPropertyTable, getAttributeTypesMapFromSchema } from \"./helpers/feature-attributes.js\";\nimport { NodeIndexDocument } from \"./helpers/node-index-document.js\";\nimport { isNestedTileset, loadNestedTileset, loadTile3DContent, loadFromArchive } from \"./helpers/load-3d-tiles.js\";\nimport { Matrix4 } from '@math.gl/core';\nimport { TILE_REFINEMENT, createBoundingVolume } from '@loaders.gl/tiles';\nimport { traverseDatasetWith } from \"./helpers/tileset-traversal.js\";\nimport { analyzeTileContent, mergePreprocessData } from \"./helpers/preprocess-3d-tiles.js\";\nimport { Progress } from \"./helpers/progress.js\";\nimport { composeHashFile, createZip } from '@loaders.gl/zip';\nimport { ConversionDump } from \"../lib/utils/conversion-dump.js\";\nconst ION_DEFAULT_TOKEN = process.env?.IonToken;\nconst HARDCODED_NODES_PER_PAGE = 64;\nconst _3D_TILES = '3DTILES';\nconst _3D_OBJECT_LAYER_TYPE = '3DObject';\nconst REFRESH_TOKEN_TIMEOUT = 1800; // 30 minutes in seconds\nconst CESIUM_DATASET_PREFIX = 'https://';\n// const FS_FILE_TOO_LARGE = 'ERR_FS_FILE_TOO_LARGE';\nconst PROGRESS_PHASE1_COUNT = 'phase1-count';\n/**\n * Converter from 3d-tiles tileset to i3s layer\n */\nexport default class I3SConverter {\n attributeMetadataInfo;\n nodePages;\n options;\n layers0Path;\n materialMap;\n materialDefinitions;\n geometryMap;\n geometryConfigs;\n vertexCounter;\n layers0;\n featuresHashArray;\n refinementCounter;\n validate;\n boundingVolumeWarnings = [];\n conversionStartTime = [0, 0];\n refreshTokenTime = [0, 0];\n sourceTileset = null;\n loadOptions = {\n _nodeWorkers: true,\n reuseWorkers: true,\n useLocalLibraries: true,\n basis: {\n format: 'rgba32',\n // We need to load local fs workers because nodejs can't load workers from the Internet\n workerUrl: './modules/textures/dist/basis-worker-node.js'\n },\n // We need to load local fs workers because nodejs can't load workers from the Internet\n draco: { workerUrl: './modules/draco/dist/draco-worker-node.js' },\n fetch: {},\n modules: {}\n };\n geoidHeightModel = null;\n Loader = Tiles3DLoader;\n generateTextures;\n generateBoundingVolumes;\n layersHasTexture;\n workerSource = {};\n writeQueue = new WriteQueue(new ConversionDump());\n compressList = null;\n preprocessData = {\n meshTopologyTypes: new Set(),\n metadataClasses: new Set()\n };\n progresses = {};\n conversionDump;\n constructor() {\n this.attributeMetadataInfo = new AttributeMetadataInfo();\n this.nodePages = new NodePages(writeFile, HARDCODED_NODES_PER_PAGE, this);\n this.options = {};\n this.layers0Path = '';\n this.materialMap = new Map();\n this.materialDefinitions = [];\n this.geometryMap = new Map();\n this.geometryConfigs = [];\n this.vertexCounter = 0;\n this.layers0 = null;\n this.featuresHashArray = [];\n this.refinementCounter = {\n tilesCount: 0,\n tilesWithAddRefineCount: 0\n };\n this.validate = false;\n this.generateTextures = false;\n this.generateBoundingVolumes = false;\n this.layersHasTexture = false;\n this.compressList = null;\n this.conversionDump = new ConversionDump();\n }\n /**\n * Convert a 3d tileset\n * @param options\n * @param options.inputUrl the url to read the tileset from\n * @param options.outputPath the output filename\n * @param options.tilesetName the output name of the tileset\n * @param options.maxDepth The max tree depth of conversion\n * @param options.slpk Generate slpk (Scene Layer Packages) output file\n * @param options.sevenZipExe Location of 7z.exe archiver to create slpk on Windows\n * @param options.egmFilePath location of *.pgm file to convert heights from ellipsoidal to gravity-related format\n * @param options.token Token for Cesium ION tilesets authentication\n * @param options.draco Generate I3S 1.7 draco compressed geometries\n * @param options.validate -enable validation\n * @param options.generateTextures - generate alternative type of textures (to have non-compressed jpeg/png and compressed ktx2)\n * @param options.generateBoundingVolumes - generate bounding volumes from vertices coordinates instead of source tiles bounding volumes\n * @param options.instantNodeWriting - Keep created 3DNodeIndexDocument files on disk instead of memory. This option reduce memory usage but decelerates conversion speed\n */\n // eslint-disable-next-line max-statements, complexity\n async convert(options) {\n if (isBrowser) {\n console.log(BROWSER_ERROR_MESSAGE); // eslint-disable-line no-console\n return BROWSER_ERROR_MESSAGE;\n }\n this.conversionStartTime = process.hrtime();\n const { tilesetName, slpk, egmFilePath, inputUrl, validate, outputPath, draco = true, sevenZipExe, maxDepth, token, generateTextures, generateBoundingVolumes, instantNodeWriting = false, mergeMaterials = true, inquirer, metadataClass, analyze = false } = options;\n this.options = {\n outputPath,\n tilesetName,\n maxDepth,\n slpk,\n sevenZipExe,\n egmFilePath,\n draco,\n token,\n inputUrl,\n instantNodeWriting,\n mergeMaterials,\n inquirer,\n metadataClass\n };\n this.progresses[PROGRESS_PHASE1_COUNT] = new Progress();\n this.compressList = (this.options.instantNodeWriting && []) || null;\n this.validate = Boolean(validate);\n this.Loader = inputUrl.indexOf(CESIUM_DATASET_PREFIX) !== -1 ? CesiumIonLoader : Tiles3DLoader;\n this.generateTextures = Boolean(generateTextures);\n this.generateBoundingVolumes = Boolean(generateBoundingVolumes);\n this.writeQueue = new WriteQueue(this.conversionDump);\n this.writeQueue.startListening();\n console.log('Loading egm file...'); // eslint-disable-line\n this.geoidHeightModel = await load(egmFilePath, PGMLoader);\n console.log('Loading egm file completed!'); // eslint-disable-line\n if (slpk) {\n this.nodePages.useWriteFunction(writeFileForSlpk);\n }\n try {\n const preloadOptions = await this._fetchPreloadOptions();\n let tilesetUrl = inputUrl;\n if (preloadOptions.url) {\n tilesetUrl = preloadOptions.url;\n }\n if (preloadOptions.headers) {\n this.loadOptions.fetch = { headers: preloadOptions.headers };\n }\n this.sourceTileset = await loadFromArchive(tilesetUrl, this.Loader, this.loadOptions);\n const preprocessResult = this.Loader === Tiles3DLoader || analyze ? await this.preprocessConversion() : true;\n if (preprocessResult && !analyze) {\n const selectMetadataClassResult = await this.selectMetadataClass();\n if (selectMetadataClassResult) {\n await this._createAndSaveTileset(outputPath, tilesetName);\n await this._finishConversion({ slpk: Boolean(slpk), outputPath, tilesetName });\n }\n }\n }\n catch (error) {\n throw error;\n }\n finally {\n await this.writeQueue.finalize();\n // Clean up worker pools\n const workerFarm = WorkerFarm.getWorkerFarm({});\n workerFarm.destroy();\n }\n return 'success';\n }\n /**\n * Preprocess stage of the tile converter. Traverse all the tiles tree and\n * check a tile content to be sure that the data is supported\n * @returns true - the conversion is possible, false - the tileset's content is not supported\n */\n async preprocessConversion() {\n // eslint-disable-next-line no-console\n console.log('Analyze source tileset');\n const sourceRootTile = this.sourceTileset.root;\n await traverseDatasetWith({\n tile: sourceRootTile,\n traversalProps: null,\n processTile: this.analyzeTile.bind(this),\n postprocessTile: undefined,\n maxDepth: this.options.maxDepth\n });\n const { meshTopologyTypes, metadataClasses } = this.preprocessData;\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n // eslint-disable-next-line no-console\n console.log('Preprocess results:');\n // eslint-disable-next-line no-console\n console.log(`Tile count: ${this.progresses[PROGRESS_PHASE1_COUNT].stepsTotal}`);\n // eslint-disable-next-line no-console\n console.log(`glTF mesh topology types: ${Array.from(meshTopologyTypes).join(', ')}`);\n if (metadataClasses.size) {\n // eslint-disable-next-line no-console\n console.log(`Feature metadata classes have been found: ${Array.from(metadataClasses).join(', ')}`);\n }\n else {\n // eslint-disable-next-line no-console\n console.log('Feature metadata classes have not been found');\n }\n if (!meshTopologyTypes.has(GLTFPrimitiveModeString.TRIANGLES) &&\n !meshTopologyTypes.has(GLTFPrimitiveModeString.TRIANGLE_STRIP)) {\n // eslint-disable-next-line no-console\n console.log('The tileset is of unsupported mesh topology types. The conversion will be interrupted.');\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n return false;\n }\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n return true;\n }\n /**\n * Analyze a tile content. The callback for preprocess stage.\n * @param sourceTile - 3DTiles tile JSON metadata\n * @param traversalProps - mandatory argument but it is not used for the preprocess stage\n * @returns - nothing\n */\n async analyzeTile(sourceTile, traversalProps) {\n const isTileset = isNestedTileset(sourceTile);\n if (isTileset) {\n await loadNestedTileset(this.sourceTileset, sourceTile, this.loadOptions);\n return null;\n }\n if (sourceTile.id) {\n this.progresses[PROGRESS_PHASE1_COUNT].stepsTotal += 1;\n console.log(`[analyze]: ${sourceTile.id}`); // eslint-disable-line\n }\n let tileContent = null;\n try {\n tileContent = await loadTile3DContent(this.sourceTileset, sourceTile, {\n ...this.loadOptions,\n '3d-tiles': { ...this.loadOptions['3d-tiles'], loadGLTF: false }\n });\n }\n catch (error) {\n // eslint-disable-next-line no-console\n console.log(`[warning]: Failed to load ${sourceTile.contentUrl}. An I3S tile with empty content will be added to the output tileset`);\n }\n const tilePreprocessData = await analyzeTileContent(tileContent);\n mergePreprocessData(this.preprocessData, tilePreprocessData);\n return null;\n }\n /**\n * Select metadata class associated with the set of feature attributes\n * @returns true if the metadata class has been successfully selected\n */\n async selectMetadataClass() {\n const { metadataClasses } = this.preprocessData;\n if (metadataClasses.size > 1) {\n if (this.options.metadataClass?.length) {\n // eslint-disable-next-line no-console\n console.log(`${this.options.metadataClass} has been selected`);\n }\n else if (this.options.inquirer) {\n const result = await this.options.inquirer.prompt([\n {\n name: 'metadataClass',\n type: 'list',\n message: 'Select feature metadata data class to convert...',\n choices: Array.from(metadataClasses)\n }\n ]);\n this.options.metadataClass = result.metadataClass;\n // eslint-disable-next-line no-console\n console.log(`${result.metadataClass} has been selected`);\n }\n else {\n // eslint-disable-next-line no-console\n console.log(`A feature metadata class has not been selected. Start the converter with option \"--metadata-class\". For example, \"npx tile-converter ... --metadata-class ${Array.from(metadataClasses)[0]}\"`);\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n return false;\n }\n }\n return true;\n }\n /**\n * Convert and save the layer and embedded tiles\n * @param outputPath - path to save output data\n * @param tilesetName - new tileset path\n */\n // eslint-disable-next-line max-statements, complexity\n async _createAndSaveTileset(outputPath, tilesetName) {\n const tilesetPath = join(`${outputPath}`, `${tilesetName}`);\n await this.conversionDump.createDump(this.options);\n if (this.conversionDump.restored && this.options.inquirer) {\n const result = await this.options.inquirer.prompt([\n {\n name: 'resumeConversion',\n type: 'confirm',\n message: 'Dump file of the previous conversion exists, do you want to resume that conversion?'\n }\n ]);\n if (!result.resumeConversion) {\n this.conversionDump.reset();\n }\n }\n this.layers0Path = join(tilesetPath, 'SceneServer', 'layers', '0');\n // Removing the tilesetPath needed to exclude erroneous files after conversion\n const removePath = this.conversionDump.restored\n ? join(this.layers0Path, 'nodepages')\n : tilesetPath;\n try {\n await removeDir(removePath);\n }\n catch (e) {\n // do nothing\n }\n if (this.conversionDump.restored && this.conversionDump.attributeMetadataInfo) {\n this.attributeMetadataInfo.fromObject(this.conversionDump.attributeMetadataInfo);\n }\n this.materialDefinitions = [];\n this.materialMap = new Map();\n if (this.conversionDump.restored && this.conversionDump.materialDefinitions) {\n for (let i = 0; i < this.conversionDump.materialDefinitions.length; i++) {\n const hash = md5(JSON.stringify(this.conversionDump.materialDefinitions[i]));\n this.materialMap.set(hash, i);\n }\n this.materialDefinitions = this.conversionDump.materialDefinitions;\n }\n const sourceRootTile = this.sourceTileset.root;\n const sourceBoundingVolume = createBoundingVolume(sourceRootTile.boundingVolume, new Matrix4(sourceRootTile.transform), null);\n this._formLayers0(tilesetName, sourceBoundingVolume, this.sourceTileset?.root?.boundingVolume?.region);\n const boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);\n await this.nodePages.push({\n index: 0,\n lodThreshold: 0,\n obb: boundingVolumes.obb,\n children: []\n });\n this.progresses[PROGRESS_PHASE1_COUNT].startMonitoring();\n const rootNode = await NodeIndexDocument.createRootNode(boundingVolumes, this);\n await traverseDatasetWith({\n tile: sourceRootTile,\n traversalProps: {\n transform: new Matrix4(sourceRootTile.transform),\n parentNodes: [rootNode]\n },\n processTile: this.convertTile.bind(this),\n postprocessTile: this.finalizeTile.bind(this),\n maxDepth: this.options.maxDepth\n });\n this.progresses[PROGRESS_PHASE1_COUNT].stopMonitoring();\n console.log(`[finalizing conversion]`); // eslint-disable-line\n this.layers0.attributeStorageInfo = this.attributeMetadataInfo.attributeStorageInfo;\n this.layers0.fields = this.attributeMetadataInfo.fields;\n this.layers0.popupInfo = this.attributeMetadataInfo.popupInfo;\n if (this.attributeMetadataInfo.attributeStorageInfo.length) {\n this.layers0.layerType = _3D_OBJECT_LAYER_TYPE;\n }\n if (this.conversionDump.restored && this.conversionDump.textureSetDefinitions) {\n this.layers0.textureSetDefinitions = this.conversionDump.textureSetDefinitions;\n }\n this.layers0.materialDefinitions = this.materialDefinitions;\n // @ts-ignore\n this.layers0.geometryDefinitions = transform(this.geometryConfigs.map((config) => ({\n geometryConfig: { ...config, draco: this.options.draco }\n })), geometryDefinitionTemlate());\n if (this.layersHasTexture === false) {\n this.layers0.store.defaultGeometrySchema.ordering =\n this.layers0.store.defaultGeometrySchema.ordering.filter((attribute) => attribute !== 'uv0');\n }\n await this._writeLayers0();\n createSceneServerPath(tilesetName, this.layers0, tilesetPath);\n for (const filePath of this.compressList || []) {\n await compressFileWithGzip(filePath);\n await removeFile(filePath);\n }\n await this.nodePages.save();\n await this.writeQueue.finalize();\n await this._createSlpk(tilesetPath);\n }\n /**\n * Form object of 3DSceneLayer https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DSceneLayer.cmn.md\n * @param tilesetName - Name of layer\n * @param sourceBoundingVolume - initialized bounding volume of the source root tile\n * @param boundingVolumeRegion - region bounding volume of the source root tile\n */\n _formLayers0(tilesetName, sourceBoundingVolume, boundingVolumeRegion) {\n if (!this.sourceTileset?.root) {\n return;\n }\n const fullExtent = convertBoundingVolumeToI3SFullExtent(sourceBoundingVolume);\n if (boundingVolumeRegion) {\n fullExtent.zmin = boundingVolumeRegion[4];\n fullExtent.zmax = boundingVolumeRegion[5];\n }\n const extent = [fullExtent.xmin, fullExtent.ymin, fullExtent.xmax, fullExtent.ymax];\n const layers0data = {\n version: `{${uuidv4().toUpperCase()}}`,\n id: 0,\n name: tilesetName,\n href: './layers/0',\n store: {\n id: `{${uuidv4().toUpperCase()}}`,\n extent\n },\n nodePages: {\n nodesPerPage: HARDCODED_NODES_PER_PAGE\n },\n compressGeometry: this.options.draco,\n fullExtent\n };\n this.layers0 = transform(layers0data, layersTemplate());\n }\n /**\n * Write 3DSceneLayer https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DSceneLayer.cmn.md in file\n */\n async _writeLayers0() {\n if (this.options.slpk) {\n await this.writeQueue.enqueue({\n archiveKey: '3dSceneLayer.json.gz',\n writePromise: () => writeFileForSlpk(this.layers0Path, JSON.stringify(this.layers0), '3dSceneLayer.json')\n });\n }\n else {\n await this.writeQueue.enqueue({\n writePromise: () => writeFile(this.layers0Path, JSON.stringify(this.layers0))\n });\n }\n }\n /**\n * Pack files into *.slpk archive\n * @param tilesetPath - Path to save file\n */\n async _createSlpk(tilesetPath) {\n await this.conversionDump.deleteDumpFile();\n if (this.options.slpk) {\n const slpkTilesetPath = join(tilesetPath, 'SceneServer', 'layers', '0');\n const slpkFileName = `${tilesetPath}.slpk`;\n await createZip(slpkTilesetPath, slpkFileName, async (fileList) => ({\n path: '@specialIndexFileHASH128@',\n file: await composeHashFile(fileList)\n }));\n try {\n await removeDir(tilesetPath);\n }\n catch (e) {\n // do nothing\n }\n }\n }\n /**\n * Convert the specific 3DTiles tile to I3S nodes.\n * This is callback function for the traversal generic function\n * @param sourceTile - current 3DTiles tile JSON metadata\n * @param traversalProps - traversal properties calculated recursively\n * @returns - traversal properties for the child tiles\n */\n // eslint-disable-next-line max-statements\n async convertTile(sourceTile, traversalProps) {\n const isTileset = isNestedTileset(sourceTile);\n if (isTileset || sourceTile.type === 'empty') {\n if (isTileset) {\n if (sourceTile.id) {\n console.log(`[load]: ${sourceTile.id}`); // eslint-disable-line\n }\n await loadNestedTileset(this.sourceTileset, sourceTile, this.loadOptions);\n }\n return traversalProps;\n }\n if (sourceTile.id) {\n console.log(`[convert]: ${sourceTile.id}`); // eslint-disable-line\n }\n const { parentNodes, transform } = traversalProps;\n let transformationMatrix = transform.clone();\n if (sourceTile.transform) {\n transformationMatrix = transformationMatrix.multiplyRight(sourceTile.transform);\n }\n const parentNode = parentNodes[0];\n const restoreResult = await this._restoreNode(parentNode, sourceTile, transformationMatrix);\n let childNodes;\n if (restoreResult === null) {\n childNodes = await this._createNode(parentNode, sourceTile, transformationMatrix);\n }\n else {\n childNodes = restoreResult;\n }\n await parentNode.addChildren(childNodes);\n const newTraversalProps = {\n transform: transformationMatrix,\n parentNodes: childNodes\n };\n if (sourceTile.id) {\n this.progresses[PROGRESS_PHASE1_COUNT].stepsDone += 1;\n let timeRemainingString = 'Calculating time left...';\n const timeRemainingStringBasedOnCount = this.progresses[PROGRESS_PHASE1_COUNT].getTimeRemainingString();\n if (timeRemainingStringBasedOnCount) {\n timeRemainingString = `${timeRemainingStringBasedOnCount} left`;\n }\n const percentString = this.progresses[PROGRESS_PHASE1_COUNT].getPercentString();\n const progressString = percentString ? ` ${percentString}%, ${timeRemainingString}` : '';\n console.log(`[converted${progressString}]: ${sourceTile.id}`); // eslint-disable-line\n }\n return newTraversalProps;\n }\n /**\n * Do final action with nodes after the current node and all child nodes been converted.\n * @param conversionResults - array of conversion results of the current node\n * @param currentTraversalProps - traversal properties of the current node\n */\n async finalizeTile(conversionResults, currentTraversalProps) {\n for (const result of conversionResults) {\n for (const node of result.parentNodes) {\n await node.addNeighbors();\n }\n }\n for (const node of currentTraversalProps.parentNodes) {\n await node.save();\n }\n }\n /**\n * Generate NodeIndexDocument\n * @param boundingVolumes - Bounding volumes\n * @param resources - converted or dumped node resources data\n * @param parentNode - 3DNodeIndexDocument of parent node\n * @param sourceTile - source 3DTile data\n * @param isDumped - indicator if the node is dumped\n * @return NodeIndexDocument, nodeInPage and node data\n */\n async _generateNodeIndexDocument(boundingVolumes, resources, parentNode, sourceTile, isDumped) {\n this.layersHasTexture =\n this.layersHasTexture ||\n Boolean(('texture' in resources && resources.texture) ||\n ('texelCountHint' in resources && resources.texelCountHint));\n if (this.generateBoundingVolumes && resources.boundingVolumes) {\n boundingVolumes = resources.boundingVolumes;\n }\n const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);\n const maxScreenThresholdSQ = lodSelection.find((val) => val.metricType === 'maxScreenThresholdSQ') || { maxError: 0 };\n if (isDumped) {\n const draftObb = {\n center: [],\n halfSize: [],\n quaternion: []\n };\n await this.nodePages.push({ index: 0, obb: draftObb }, parentNode.inPageId);\n }\n const nodeInPage = await this._updateNodeInNodePages(maxScreenThresholdSQ, boundingVolumes, sourceTile, parentNode.inPageId, resources);\n const nodeData = await NodeIndexDocument.createNodeIndexDocument(parentNode, boundingVolumes, lodSelection, nodeInPage, resources);\n const node = await new NodeIndexDocument(nodeInPage.index, this).addData(nodeData);\n return { node, nodeInPage, nodeData };\n }\n /**\n * Restore 3DNodeIndexDocument from a comversion dump file\n * @param parentNode - 3DNodeIndexDocument of parent node\n * @param sourceTile - source 3DTile data\n * @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n */\n async _restoreNode(parentNode, sourceTile, transformationMatrix) {\n this._checkAddRefinementTypeForTile(sourceTile);\n await this._updateTilesetOptions();\n if (this.conversionDump.restored &&\n sourceTile.id &&\n this.conversionDump.isFileConversionComplete(sourceTile.id)) {\n const sourceBoundingVolume = createBoundingVolume(sourceTile.boundingVolume, transformationMatrix, null);\n const boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);\n const nodes = [];\n for (const convertedNode of this.conversionDump.tilesConverted[sourceTile.id].nodes) {\n const { node } = await this._generateNodeIndexDocument(boundingVolumes, {\n ...convertedNode.dumpMetadata,\n nodeId: convertedNode.nodeId\n }, parentNode, sourceTile, true);\n nodes.push(node);\n }\n return nodes;\n }\n else if (this.conversionDump.restored && sourceTile.id) {\n // clear existing record in a dump\n this.conversionDump.clearDumpRecord(sourceTile.id);\n }\n return null;\n }\n /**\n * Convert tile to one or more I3S nodes\n * @param parentNode - 3DNodeIndexDocument of parent node\n * @param sourceTile - source 3DTile data\n * @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n * @param level - tree level\n */\n // eslint-disable-next-line max-statements\n async _createNode(parentNode, sourceTile, transformationMatrix) {\n this._checkAddRefinementTypeForTile(sourceTile);\n await this._updateTilesetOptions();\n let tileContent = null;\n try {\n tileContent = await loadTile3DContent(this.sourceTileset, sourceTile, this.loadOptions);\n }\n catch (error) {\n // eslint-disable-next-line no-console\n console.log(`[warning]: Failed to load ${sourceTile.contentUrl}`);\n }\n const sourceBoundingVolume = createBoundingVolume(sourceTile.boundingVolume, transformationMatrix, null);\n const boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);\n const propertyTable = getPropertyTable(tileContent, this.options.metadataClass);\n this.createAttributeStorageInfo(tileContent, propertyTable);\n this.conversionDump.attributeMetadataInfo = {\n attributeStorageInfo: this.attributeMetadataInfo.attributeStorageInfo,\n fields: this.attributeMetadataInfo.fields,\n popupInfo: this.attributeMetadataInfo.popupInfo\n };\n const resourcesData = await this._convertResources({\n sourceTile,\n transformationMatrix,\n boundingVolume: sourceBoundingVolume,\n tileContent,\n parentId: parentNode.inPageId,\n propertyTable\n });\n const nodes = [];\n const nodeIds = [];\n const nodesInPage = [];\n const emptyResources = {\n geometry: null,\n compressedGeometry: null,\n texture: null,\n hasUvRegions: false,\n sharedResources: null,\n meshMaterial: null,\n vertexCount: null,\n attributes: null,\n featureCount: null,\n boundingVolumes: null\n };\n for (const resources of resourcesData || [emptyResources]) {\n const { node, nodeInPage, nodeData } = await this._generateNodeIndexDocument(boundingVolumes, resources, parentNode, sourceTile, false);\n nodes.push(node);\n if (nodeInPage.mesh) {\n // update a record in a dump file\n if (sourceTile.id) {\n const dumpMetadata = {\n boundingVolumes: resources.boundingVolumes,\n attributesCount: resources.attributes?.length,\n featureCount: resources.featureCount,\n geometry: Boolean(resources.geometry),\n hasUvRegions: resources.hasUvRegions,\n materialId: nodeInPage.mesh.material.definition,\n texelCountHint: nodeInPage.mesh.material.texelCountHint,\n vertexCount: resources.vertexCount\n };\n this.conversionDump.setMaterialsDefinitions(this.materialDefinitions);\n await this.conversionDump.addNode(sourceTile.id, nodeInPage.index, dumpMetadata);\n }\n // write resources\n await this._writeResources(resources, node.id, sourceTile);\n }\n if (this.validate) {\n this.boundingVolumeWarnings = validateNodeBoundingVolumes(nodeData);\n if (this.boundingVolumeWarnings && this.boundingVolumeWarnings.length) {\n console.warn('Bounding Volume Warnings: ', ...this.boundingVolumeWarnings); //eslint-disable-line\n }\n }\n nodeIds.push(nodeInPage.index);\n nodesInPage.push(nodeInPage);\n }\n return nodes;\n }\n /**\n * Convert tile to one or more I3S nodes\n * @param sourceTile - source tile (3DTile)\n * @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n * @param boundingVolume - initialized bounding volume of the source tile\n * @param tileContent - content of the source tile\n * @param parentId - id of parent node in node pages\n * @param propertyTable - batch table from b3dm / feature properties from EXT_FEATURE_METADATA, EXT_MESH_FEATURES or EXT_STRUCTURAL_METADATA\n * @returns - converted node resources\n */\n async _convertResources({ sourceTile, transformationMatrix, boundingVolume, tileContent, parentId, propertyTable }) {\n if (!this.isContentSupported(sourceTile) || !tileContent) {\n return null;\n }\n const draftObb = {\n center: [],\n halfSize: [],\n quaternion: []\n };\n const resourcesData = await convertB3dmToI3sGeometry({\n tileContent,\n tileTransform: transformationMatrix,\n tileBoundingVolume: boundingVolume,\n addNodeToNodePage: async () => (await this.nodePages.push({ index: 0, obb: draftObb }, parentId)).index,\n propertyTable,\n featuresHashArray: this.featuresHashArray,\n attributeStorageInfo: this.attributeMetadataInfo.attributeStorageInfo,\n draco: this.options.draco,\n generateBoundingVolumes: this.generateBoundingVolumes,\n shouldMergeMaterials: this.options.mergeMaterials,\n geoidHeightModel: this.geoidHeightModel,\n libraries: this.loadOptions.modules,\n metadataClass: this.options.metadataClass\n });\n return resourcesData;\n }\n /**\n * Update node object (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/node.cmn.md)\n * in node pages (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/nodePage.cmn.md)\n * @param maxScreenThresholdSQ - Level of Details (LOD) metric\n * @param boundingVolumes - Bounding volumes\n * @param sourceTile - source tile (3DTile)\n * @param parentId - id of parent node in node pages\n * @param resources - the node resources data\n * @param resources.meshMaterial - PBR-like material object\n * @param resources.texture - texture image\n * @param resources.vertexCount - number of vertices in geometry\n * @param resources.featureCount - number of features\n * @param resources.geometry - Uint8Array with geometry attributes\n * @return the node object in node pages\n */\n // eslint-disable-next-line max-statements, complexity\n async _updateNodeInNodePages(maxScreenThresholdSQ, boundingVolumes, sourceTile, parentId, resources) {\n const { vertexCount, featureCount, geometry, hasUvRegions } = resources;\n const nodeInPage = {\n index: 0,\n lodThreshold: maxScreenThresholdSQ.maxError,\n obb: boundingVolumes.obb,\n children: []\n };\n if (geometry && this.isContentSupported(sourceTile)) {\n nodeInPage.mesh = {\n geometry: {\n definition: this.findOrCreateGeometryDefinition(Boolean(('texture' in resources && resources.texture) ||\n ('texelCountHint' in resources && resources.texelCountHint)), hasUvRegions),\n resource: 0\n },\n attribute: {\n resource: 0\n },\n material: {\n definition: 0\n }\n };\n }\n const nodeId = 'nodeId' in resources ? resources.nodeId : undefined;\n let node;\n if (!nodeId) {\n node = await this.nodePages.push(nodeInPage, parentId);\n }\n else {\n node = await this.nodePages.getNodeById(nodeId);\n }\n if (!nodeInPage.mesh) {\n // eslint-disable-next-line no-console\n console.log(`[warning]: node ${node.index} is created with empty content`);\n }\n NodePages.updateAll(node, nodeInPage);\n if ('meshMaterial' in resources && resources.meshMaterial) {\n NodePages.updateMaterialByNodeId(node, this._findOrCreateMaterial(resources.meshMaterial));\n }\n else if ('materialId' in resources && resources.materialId !== null) {\n NodePages.updateMaterialByNodeId(node, resources.materialId);\n }\n if ('texture' in resources && resources.texture) {\n const texelCountHint = resources.texture.image.height * resources.texture.image.width;\n NodePages.updateTexelCountHintByNodeId(node, texelCountHint);\n }\n else if ('texelCountHint' in resources && resources.texelCountHint) {\n NodePages.updateTexelCountHintByNodeId(node, resources.texelCountHint);\n }\n if (vertexCount) {\n this.vertexCounter += vertexCount;\n NodePages.updateVertexCountByNodeId(node, vertexCount);\n }\n NodePages.updateNodeAttributeByNodeId(node);\n if (featureCount) {\n NodePages.updateFeatureCountByNodeId(node, featureCount);\n }\n this.nodePages.saveNode(node);\n return node;\n }\n /**\n * Write node resources in files\n * @param resources - source tile (3DTile)\n * @param resources.geometry - Uint8Array with geometry attributes\n * @param resources.compressedGeometry - Uint8Array with compressed (draco) geometry\n * @param resources.texture - texture image\n * @param resources.sharedResources - shared resource data object\n * @param resources.attributes - feature attributes\n * @param nodePath - node path\n * @param sourceTile - source tile (3DTile)\n * @return {Promise<void>}\n */\n async _writeResources(resources, nodePath, sourceTile) {\n const { geometry: geometryBuffer, compressedGeometry, texture, sharedResources, attributes } = resources;\n const childPath = join(this.layers0Path, 'nodes', nodePath);\n const slpkChildPath = join('nodes', nodePath);\n await this._writeGeometries({\n geometryBuffer,\n compressedGeometry,\n childPath,\n slpkChildPath,\n sourceId: sourceTile.id || '',\n nodeId: parseInt(nodePath)\n });\n await this._writeShared({\n sharedResources,\n childPath,\n slpkChildPath,\n nodePath,\n sourceId: sourceTile.id || '',\n nodeId: parseInt(nodePath)\n });\n await this._writeTexture(texture, childPath, slpkChildPath, sourceTile.id || '', parseInt(nodePath));\n await this._writeAttributes(attributes, childPath, slpkChildPath, sourceTile.id || '', parseInt(nodePath));\n }\n /**\n * Write non-compressed and compressed geometries in files\n * @param geometryBuffer - Uint8Array with geometry attributes\n * @param compressedGeometry - Uint8Array with compressed (draco) geometry\n * @param childPath - a child path to write resources\n * @param slpkChildPath - resource path inside *slpk file\n * @param sourceId - source filename\n * @param nodeId - nodeId of a converted node for the writing\n */\n async _writeGeometries({ geometryBuffer, compressedGeometry, childPath, slpkChildPath, sourceId, nodeId }) {\n if (!geometryBuffer) {\n return;\n }\n this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.GEOMETRY, false);\n if (this.options.slpk) {\n const slpkGeometryPath = join(childPath, 'geometries');\n await this.writeQueue.enqueue({\n archiveKey: `${slpkChildPath}/geometries/0.bin.gz`,\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.GEOMETRY,\n writePromise: () => writeFileForSlpk(slpkGeometryPath, geometryBuffer, '0.bin')\n });\n }\n else {\n const geometryPath = join(childPath, 'geometries/0/');\n await this.writeQueue.enqueue({\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.GEOMETRY,\n writePromise: () => writeFile(geometryPath, geometryBuffer, 'index.bin')\n });\n }\n if (this.options.draco && compressedGeometry) {\n this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.DRACO_GEOMETRY, false);\n if (this.options.slpk) {\n const slpkCompressedGeometryPath = join(childPath, 'geometries');\n await this.writeQueue.enqueue({\n archiveKey: `${slpkChildPath}/geometries/1.bin.gz`,\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.DRACO_GEOMETRY,\n writePromise: () => writeFileForSlpk(slpkCompressedGeometryPath, compressedGeometry, '1.bin')\n });\n }\n else {\n const compressedGeometryPath = join(childPath, 'geometries/1/');\n await this.writeQueue.enqueue({\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.DRACO_GEOMETRY,\n writePromise: () => writeFile(compressedGeometryPath, compressedGeometry, 'index.bin')\n });\n }\n }\n }\n /**\n * Write shared resources in a file\n * @param sharedResources - shared resource data object\n * @param childPath - a child path to write resources\n * @param slpkChildPath - resource path inside *slpk file\n * @param nodePath - a node path\n * @param sourceId - source filename\n * @param nodeId - nodeId of a converted node for the writing\n */\n async _writeShared({ sharedResources, childPath, slpkChildPath, nodePath, sourceId, nodeId }) {\n if (!sharedResources) {\n return;\n }\n sharedResources.nodePath = nodePath;\n const sharedData = transform(sharedResources, sharedResourcesTemplate());\n const sharedDataStr = JSON.stringify(sharedData);\n this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.SHARED, false);\n if (this.options.slpk) {\n const slpkSharedPath = join(childPath, 'shared');\n await this.writeQueue.enqueue({\n archiveKey: `${slpkChildPath}/shared/sharedResource.json.gz`,\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.SHARED,\n writePromise: () => writeFileForSlpk(slpkSharedPath, sharedDataStr, 'sharedResource.json')\n });\n }\n else {\n const sharedPath = join(childPath, 'shared/');\n await this.writeQueue.enqueue({\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.SHARED,\n writePromise: () => writeFile(sharedPath, sharedDataStr)\n });\n }\n }\n /**\n * Generates textures based on texture mime type and fill in textureSetDefinitions data.\n * @param texture - the texture image\n * @param childPath - a child path to write resources\n * @param slpkChildPath - the resource path inside *slpk file\n * @param sourceId - source filename\n * @param nodeId - nodeId of a converted node for the writing\n */\n // eslint-disable-next-line max-statements\n async _writeTexture(texture, childPath, slpkChildPath, sourceId, nodeId) {\n if (texture) {\n const format = this._getFormatByMimeType(texture?.mimeType);\n const formats = [];\n const textureData = texture.bufferView.data;\n switch (format) {\n case 'jpg':\n case 'png': {\n formats.push({ name: '0', format });\n this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/${format}`, false);\n await this.writeTextureFile({\n textureData,\n name: '0',\n format,\n childPath,\n slpkChildPath,\n sourceId,\n nodeId\n });\n if (this.generateTextures) {\n formats.push({ name: '1', format: 'ktx2' });\n // For Node.js texture.image.data is type of Buffer\n const copyArrayBuffer = texture.image.data.subarray();\n const arrayToEncode = new Uint8Array(copyArrayBuffer);\n const ktx2TextureData = encode({ ...texture.image, data: arrayToEncode }, \n // @ts-expect-error - Worker encoder typing is still WIP\n KTX2BasisWriterWorker, {\n ...KTX2BasisWriterWorker.options,\n ['ktx2-basis-writer']: {\n // We need to load local fs workers because nodejs can't load workers from the Internet\n workerUrl: './modules/textures/dist/ktx2-basis-writer-worker-node.js'\n },\n reuseWorkers: true,\n _nodeWorkers: true,\n useLocalLibraries: true\n });\n this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/ktx2`, false);\n await this.writeTextureFile({\n textureData: ktx2TextureData,\n name: '1',\n format: 'ktx2',\n childPath,\n slpkChildPath,\n sourceId,\n nodeId\n });\n }\n break;\n }\n case 'ktx2': {\n formats.push({ name: '1', format });\n this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/${format}`, false);\n await this.writeTextureFile({\n textureData,\n name: '1',\n format,\n childPath,\n slpkChildPath,\n sourceId,\n nodeId\n });\n if (this.generateTextures) {\n formats.push({ name: '0', format: 'jpg' });\n const decodedFromKTX2TextureData = encode(texture.image.data[0], ImageWriter);\n this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/jpg`, false);\n await this.writeTextureFile({\n textureData: decodedFromKTX2TextureData,\n name: '0',\n format: 'jpg',\n childPath,\n slpkChildPath,\n sourceId,\n nodeId\n });\n }\n break;\n }\n default:\n }\n if (!this.layers0.textureSetDefinitions.length) {\n this.layers0.textureSetDefinitions.push({ formats });\n this.layers0.textureSetDefinitions.push({ formats, atlas: true });\n if (this.layers0.textureSetDefinitions) {\n this.conversionDump.addTexturesDefinitions(this.layers0.textureSetDefinitions);\n }\n }\n }\n }\n /**\n * Write the texture image in a file\n * @param textureData\n * @param name\n * @param format\n * @param childPath\n * @param slpkChildPath\n * @param sourceId\n * @param nodeId\n */\n async writeTextureFile({ textureData, name, format, childPath, slpkChildPath, sourceId, nodeId }) {\n if (this.options.slpk) {\n const slpkTexturePath = join(childPath, 'textures');\n const compress = false;\n await this.writeQueue.enqueue({\n archiveKey: `${slpkChildPath}/textures/${name}.${format}`,\n sourceId,\n outputId: nodeId,\n resourceType: `${ResourceType.TEXTURE}/${format}`,\n writePromise: () => writeFileForSlpk(slpkTexturePath, textureData, `${name}.${format}`, compress)\n });\n }\n else {\n const texturePath = join(childPath, `textures/${name}/`);\n await this.writeQueue.enqueue({\n sourceId,\n outputId: nodeId,\n resourceType: `${ResourceType.TEXTURE}/${format}`,\n writePromise: () => writeFile(texturePath, textureData, `index.${format}`)\n });\n }\n }\n /**\n * Write feature attributes in files\n * @param attributes - feature attributes\n * @param childPath - a child path to write resources\n * @param slpkChildPath - the resource path inside *slpk file\n * @param sourceId - source filename\n * @param nodeId - nodeId of a converted node for the writing\n */\n async _writeAttributes(attributes = [], childPath, slpkChildPath, sourceId, nodeId) {\n if (attributes?.length && this.attributeMetadataInfo.attributeStorageInfo.length) {\n const minimumLength = attributes.length < this.attributeMetadataInfo.attributeStorageInfo.length\n ? attributes.length\n : this.attributeMetadataInfo.attributeStorageInfo.length;\n for (let index = 0; index < minimumLength; index++) {\n const folderName = this.attributeMetadataInfo.attributeStorageInfo[index].key;\n const fileBuffer = new Uint8Array(attributes[index]);\n this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.ATTRIBUTES}/${folderName}`, false);\n if (this.options.slpk) {\n const slpkAttributesPath = join(childPath, 'attributes', folderName);\n await this.writeQueue.enqueue({\n archiveKey: `${slpkChildPath}/attributes/${folderName}.bin.gz`,\n sourceId,\n outputId: nodeId,\n resourceType: `${ResourceType.ATTRIBUTES}/${folderName}`,\n writePromise: () => writeFileForSlpk(slpkAttributesPath, fileBuffer, '0.bin')\n });\n }\n else {\n const attributesPath = join(childPath, `attributes/${folderName}/0`);\n await this.writeQueue.enqueue({\n sourceId,\n outputId: nodeId,\n resourceType: `${ResourceType.ATTRIBUTES}/${folderName}`,\n writePromise: () => writeFile(attributesPath, fileBuffer, 'index.bin')\n });\n }\n }\n }\n }\n /**\n * Return file format by its MIME type\n * @param mimeType - feature attributes\n */\n _getFormatByMimeType(mimeType) {\n switch (mimeType) {\n case 'image/jpeg':\n return 'jpg';\n case 'image/png':\n return 'png';\n case 'image/ktx2':\n return 'ktx2';\n default:\n return 'jpg';\n }\n }\n /**\n * Find or create material in materialDefinitions array\n * @param material - end-to-end index of the node\n * @return material id\n */\n _findOrCreateMaterial(material) {\n const hash = md5(JSON.stringify(material));\n if (this.materialMap.has(hash)) {\n return this.materialMap.get(hash) || 0;\n }\n const newMaterialId = this.materialDefinitions.push(material) - 1;\n this.materialMap.set(hash, newMaterialId);\n return newMaterialId;\n }\n /**\n * Get unique geometry configuration index\n * In the end of conversion configurations will be transformed to geometryDefinitions array\n * @param hasTexture\n * @param hasUvRegions\n * @returns\n */\n findOrCreateGeometryDefinition(hasTexture, hasUvRegions) {\n const geometryConfig = { hasTexture, hasUvRegions };\n const hash = md5(JSON.stringify(geometryConfig));\n if (this.geometryMap.has(hash)) {\n return this.geometryMap.get(hash) || 0;\n }\n const newGeometryId = this.geometryConfigs.push(geometryConfig) - 1;\n this.geometryMap.set(hash, newGeometryId);\n return newGeometryId;\n }\n /**\n * Creates attribute storage info based on either extension schema or property table.\n * @param tileContent - content of the source tile\n * @param propertyTable - feature properties from EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA\n */\n createAttributeStorageInfo(tileContent, propertyTable) {\n /*\n In case the tileset doesn't have either EXT_structural_metadata or EXT_feature_metadata\n that can be a source of attribute information so metadataClass is not specified\n we will collect attribute information for node attributes from the property table\n taken from each tile.\n */\n let attributeTypesMap = null;\n if (this.options.metadataClass) {\n if (!this.attributeMetadataInfo.attributeStorageInfo.length && tileContent?.gltf) {\n attributeTypesMap = getAttributeTypesMapFromSchema(tileContent.gltf, this.options.metadataClass);\n }\n }\n else if (propertyTable) {\n attributeTypesMap = getAttributeTypesMapFromPropertyTable(propertyTable);\n }\n if (attributeTypesMap) {\n // Add new storage attributes, fields and create popupInfo\n this.attributeMetadataInfo.addMetadataInfo(attributeTypesMap);\n }\n }\n /**\n * Print statistics in the end of conversion\n * @param params - output files data\n */\n async _finishConversion(params) {\n const { tilesCount, tilesWithAddRefineCount } = this.refinementCounter;\n const addRefinementPercentage = tilesWithAddRefineCount\n ? (tilesWithAddRefineCount / tilesCount) * 100\n : 0;\n const filesSize = await calculateFilesSize(params);\n const diff = process.hrtime(this.conversionStartTime);\n const conversionTime = timeConverter(diff);\n console.log('------------------------------------------------'); // eslint-disable-line no-undef, no-console\n console.log(`Finishing conversion of ${_3D_TILES}`); // eslint-disable-line no-undef, no-console\n console.log(`Total conversion time: ${conversionTime}`); // eslint-disable-line no-undef, no-console\n console.log('Vertex count: ', this.vertexCounter); // eslint-disable-line no-undef, no-console\n console.log('File(s) size: ', filesSize, ' bytes'); // eslint-disable-line no-undef, no-console\n console.log('Percentage of tiles with \"ADD\" refinement type:', addRefinementPercentage, '%'); // eslint-disable-line no-undef, no-console\n console.log('------------------------------------------------'); // eslint-disable-line no-undef, no-console\n }\n /**\n * Fetch preload options for ION tileset\n */\n async _fetchPreloadOptions() {\n if (!this.Loader.preload) {\n return {};\n }\n const options = {\n 'cesium-ion': { accessToken: this.options.token || ION_DEFAULT_TOKEN }\n };\n const preloadOptions = await this.Loader.preload(this.options.inputUrl, options);\n this.refreshTokenTime = process.hrtime();\n return { ...options, ...preloadOptions };\n }\n /**\n * Update options of source tileset\n */\n async _updateTilesetOptions() {\n const diff = process.hrtime(this.refreshTokenTime);\n if (diff[0] < REFRESH_TOKEN_TIMEOUT) {\n return;\n }\n this.refreshTokenTime = process.hrtime();\n const preloadOptions = await this._fetchPreloadOptions();\n if (preloadOptions.headers) {\n this.loadOptions.fetch = {\n ...this.loadOptions.fetch,\n headers: preloadOptions.headers\n };\n console.log('Authorization Bearer token has been updated'); // eslint-disable-line no-undef, no-console\n }\n }\n /** Do calculations of all tiles and tiles with \"ADD\" type of refinement.\n * @param tile\n */\n _checkAddRefinementTypeForTile(tile) {\n const ADD_TILE_REFINEMENT = TILE_REFINEMENT.ADD;\n if (tile.refine === ADD_TILE_REFINEMENT) {\n this.refinementCounter.tilesWithAddRefineCount += 1;\n console.warn('This tile uses \"ADD\" type of refinement'); // eslint-disable-line\n }\n this.refinementCounter.tilesCount += 1;\n }\n /**\n * Check if the tile's content format is supported by the converter\n * @param sourceTile\n * @returns\n */\n isContentSupported(sourceTile) {\n return ['b3dm', 'glTF', 'scenegraph'].includes(sourceTile.type || '');\n }\n}\n", "import { join } from 'path';\nimport transform from 'json-map-transform';\nimport { METADATA as metadataTemplate } from \"../json-templates/metadata.js\";\nimport { isFileExists, openJson } from \"../../lib/utils/file-utils.js\";\n/**\n * class NodePages - wrapper of nodePages array\n *\n * @example\n * import {writeFile} from './helpers/write-file';\n *\n * // create an instance of the class\n * const nodePages = new NodePages(writeFile, HARDCODED_NODES_PER_PAGE);\n * ...\n * // push root node\n * const parent = await nodePages.push({\n lodThreshold: HARDCODED_MAX_SCREEN_THRESHOLD_SQ,\n obb: coordinates.obb,\n children: []\n });\n * ...\n * // push node with parent relation\n * const nodeInPage = {\n lodThreshold: HARDCODED_MAX_SCREEN_THRESHOLD_SQ,\n obb: coordinates.obb,\n children: [],\n mesh: {\n geometry: {\n definition: 0\n }\n }\n };\n * const node = await this.nodePages.push(nodeInPage, parent.index);\n * ...\n * // save all the nodePages in the end of pushing all the nodes\n * await this.nodePages.save(layers0path);\n */\nexport default class NodePages {\n nodesPerPage;\n nodesCounter;\n writeFile;\n converter;\n nodePages;\n length = 0;\n /**\n * @constructs\n * Create a nodePages instance.\n * @param writeFileFunc - function to save one nodePage into a file\n * @param nodesPerPage - length limit for one nodePage. An additional nodePage is created when this limit is met\n */\n constructor(writeFileFunc, nodesPerPage, converter) {\n this.nodesPerPage = nodesPerPage;\n this.nodesCounter = 0;\n // @ts-expect-error\n this.nodePages = [{}];\n this.nodePages[0].nodes = [];\n this.writeFile = writeFileFunc;\n this.converter = converter;\n this.length = 0;\n }\n /**\n * Setup function to save node pages\n * @param func - function which should be used to save node pages\n */\n useWriteFunction(func) {\n this.writeFile = func;\n }\n /**\n * Get file path and file name of the node page with the particular id\n * @param nodePageId - node page id\n * @returns file path and file name\n */\n getNodePageFileName(nodePageId) {\n let filePath;\n let fileName;\n if (this.converter.options.slpk) {\n filePath = join(this.converter.layers0Path, 'nodepages');\n fileName = `${nodePageId.toString()}.json`;\n }\n else {\n filePath = join(this.converter.layers0Path, 'nodepages', nodePageId.toString());\n fileName = 'index.json';\n }\n return { filePath, fileName };\n }\n /**\n * Load node page from a file on the disk\n * @param nodePageId - node page id\n * @returns - node page data\n */\n async loadNodePage(nodePageId) {\n const { filePath, fileName } = this.getNodePageFileName(nodePageId);\n const fullName = join(filePath, fileName);\n if (await isFileExists(fullName)) {\n console.log(`load ${fullName}.`); // eslint-disable-line\n return (await openJson(filePath, fileName));\n }\n return { nodes: [] };\n }\n /**\n * Get nodepage id by node id\n * @param id node id\n * @returns node page id\n */\n getPageIndexByNodeId(id) {\n return Math.floor(id / this.nodesPerPage);\n }\n /**\n * Get node page data by node id\n * @param id node id\n * @returns node page data\n */\n async getPageByNodeId(id) {\n const pageIndex = this.getPageIndexByNodeId(id);\n if (this.converter.options.instantNodeWriting) {\n return await this.loadNodePage(pageIndex);\n }\n return this.nodePages[pageIndex];\n }\n /**\n * Get the node by its end-to-end index\n * @param id - end-to-end index of the node\n * @return the node object\n */\n async getNodeById(id, nodePage) {\n const nodeIndex = id % this.nodesPerPage;\n nodePage = nodePage || (await this.getPageByNodeId(id));\n return nodePage.nodes[nodeIndex];\n }\n /**\n * Add a child id into the parent node.children array\n * @param parentId - end-to-end parent node index\n * @param childId - end-to-end child node index\n */\n async addChildRelation(parentId, childId) {\n if (parentId === null || parentId === undefined) {\n return;\n }\n const parentNode = await this.getNodeById(parentId);\n parentNode.children?.push(childId);\n await this.saveNode(parentNode);\n }\n /**\n * Put new node in nodePages array\n * @param node - node object\n * @param parentId - index of parent node\n * @return\n */\n async push(node, parentId) {\n node.index = this.nodesCounter++;\n if (!this.converter.options.instantNodeWriting) {\n let currentNodePage = this.nodePages[this.nodePages.length - 1];\n if (currentNodePage.nodes.length === this.nodesPerPage) {\n currentNodePage = { nodes: [] };\n this.nodePages.push(currentNodePage);\n }\n currentNodePage.nodes.push(node);\n }\n await this.addChildRelation(parentId, node.index);\n NodePages.updateResourceInMesh(node);\n await this.saveNode(node);\n return node;\n }\n /**\n * Save node to the file on the disk\n * @param node - node data\n */\n async saveNode(node) {\n if (!this.converter.options.instantNodeWriting) {\n return;\n }\n const nodePageIndex = this.getPageIndexByNodeId(node.index);\n const nodePage = await this.getPageByNodeId(node.index);\n const { filePath, fileName } = this.getNodePageFileName(nodePageIndex);\n const nodeToUpdate = await this.getNodeById(node.index, nodePage);\n if (nodeToUpdate) {\n NodePages.updateAll(nodeToUpdate, node);\n }\n else {\n nodePage.nodes.push(node);\n }\n const nodePageStr = JSON.stringify(nodePage);\n if (this.converter.options.slpk) {\n await this.converter.writeQueue.enqueue({\n archiveKey: `nodePages/${nodePageIndex.toString()}.json.gz`,\n writePromise: () => this.writeFile(filePath, nodePageStr, fileName, true, this.converter.compressList)\n }, true);\n }\n else {\n await this.converter.writeQueue.enqueue({\n writePromise: () => this.writeFile(filePath, nodePageStr)\n }, true);\n }\n }\n /**\n * Save metadata file (for slpk only)\n */\n async saveMetadata() {\n const metadata = transform({ nodeCount: this.nodesCounter }, metadataTemplate());\n const compress = false;\n await this.converter.writeQueue.enqueue({\n archiveKey: 'metadata.json',\n writePromise: () => this.writeFile(this.converter.layers0Path, JSON.stringify(metadata), 'metadata.json', compress)\n });\n }\n /**\n * Save all the node pages\n * Run this method when all nodes is pushed in nodePages\n */\n async save() {\n if (this.converter.options.instantNodeWriting) {\n await this.saveMetadata();\n return;\n }\n if (this.converter.options.slpk) {\n for (const [index, nodePage] of this.nodePages.entries()) {\n const nodePageStr = JSON.stringify(nodePage);\n const slpkPath = join(this.converter.layers0Path, 'nodepages');\n await this.converter.writeQueue.enqueue({\n archiveKey: `nodePages/${index.toString()}.json.gz`,\n writePromise: () => this.writeFile(slpkPath, nodePageStr, `${index.toString()}.json`)\n });\n }\n await this.saveMetadata();\n }\n else {\n for (const [index, nodePage] of this.nodePages.entries()) {\n const nodePageStr = JSON.stringify(nodePage);\n const nodePagePath = join(this.converter.layers0Path, 'nodepages', index.toString());\n await this.converter.writeQueue.enqueue({\n writePromise: () => this.writeFile(nodePagePath, nodePageStr)\n });\n }\n }\n }\n /**\n * Update resource index in node.mesh object\n * @param node - node object\n */\n static updateResourceInMesh(node) {\n if (node.mesh && isFinite(node.index)) {\n node.mesh.geometry.resource = node.index;\n }\n }\n /**\n * Update all fields in the node excluding id\n * @param node - node object\n * @param data - NodeInPage data to replace original data\n */\n static updateAll(node, data) {\n Object.assign(node, data, { index: node.index });\n NodePages.updateResourceInMesh(node);\n return node;\n }\n /**\n * Update material in node.mesh object by node id\n * @param id - end-to-end index of the node\n * @param materialId - id from scene layer materialDefinitions\n */\n static updateMaterialByNodeId(node, materialId) {\n if (!node.mesh) {\n return;\n }\n node.mesh.material = {\n definition: materialId,\n resource: node.index\n };\n }\n /**\n * Update vertexCount in node.mesh.geometry object by node id\n * @param id - end-to-end index of the node\n * @param vertexCount - vertex count for particular node\n */\n static updateVertexCountByNodeId(node, vertexCount) {\n if (!node.mesh) {\n return;\n }\n node.mesh.geometry.vertexCount = vertexCount;\n }\n /**\n * Update resource in node.mesh.attribute object by node id\n * @param node - node object\n */\n static updateNodeAttributeByNodeId(node) {\n if (!node.mesh || !node.index) {\n return;\n }\n node.mesh.attribute.resource = node.index;\n }\n /**\n * Update featureCount in node.mesh.geometry object by node id\n * @param node - node object\n * @param featureCount - features count of the node\n */\n static updateFeatureCountByNodeId(node, featureCount) {\n if (!node.mesh) {\n return;\n }\n node.mesh.geometry.featureCount = featureCount;\n }\n /**\n * Update texelCountHint in node.mesh.material object by node id\n * @param node - node object\n * @param texelCountHint - texelCountHint of particular node\n */\n static updateTexelCountHintByNodeId(node, texelCountHint) {\n if (!node.mesh || !node.mesh.material) {\n return;\n }\n node.mesh.material.texelCountHint = texelCountHint;\n }\n}\n", "export const METADATA = () => ({\n folderPattern: {\n path: 'folderPattern',\n default: 'BASIC'\n },\n archiveCompressionType: {\n path: 'archiveCompressionType',\n default: 'STORE'\n },\n resourceCompressionType: {\n path: 'resourceCompressionType',\n default: 'GZIP'\n },\n I3SVersion: {\n path: 'I3SVersion',\n default: '1.8'\n },\n nodeCount: {\n path: 'nodeCount'\n }\n});\n", "import { load } from '@loaders.gl/core';\nimport { JSONLoader } from '@loaders.gl/loader-utils';\nimport { promises as fs } from 'fs';\nimport { isAbsolute, join } from 'path';\nimport { compressFileWithGzip } from \"./compress-util.js\";\n/**\n * Write a file with data and name fileName to path\n *\n * @param path - output path\n * @param data - file content\n * @param fileName - name of output file (default: index.json)\n */\nexport async function writeFile(path, data, fileName = 'index.json') {\n let toWriteData;\n if (data instanceof Promise) {\n toWriteData = new Uint8Array(await data);\n }\n else if (data instanceof ArrayBuffer) {\n toWriteData = new Uint8Array(data);\n }\n else {\n toWriteData = data;\n }\n await fs.mkdir(path, { recursive: true });\n const pathFile = join(path, fileName);\n try {\n await fs.writeFile(pathFile, toWriteData);\n }\n catch (err) {\n throw err;\n }\n console.log(`${pathFile} saved.`); // eslint-disable-line no-console\n return pathFile;\n}\n/**\n * Write a file with data and name fileName to path - specific one for further packaging into slpk\n *\n * @param path - output path\n * @param data - file content\n * @param fileName - name of output file (default: index.json)\n * @param compress - if need to compress file with gzip (default: true)\n * @param compressList - if set - the file should be added to this list and compressed in the end of conversion\n */\nexport async function writeFileForSlpk(path, data, fileName = 'index.json', compress = true, compressList) {\n const pathFile = await writeFile(path, data, fileName);\n if (compress) {\n if (compressList) {\n if (!compressList.includes(pathFile)) {\n compressList.push(pathFile);\n return `${pathFile}.gz`;\n }\n return null;\n }\n const pathGzFile = await compressFileWithGzip(pathFile);\n // After compression, we don't need an uncompressed file\n await removeFile(pathFile);\n return pathGzFile;\n }\n return pathFile;\n}\n/**\n * Open json file\n * @param path - path to the file\n * @param fileName - file name\n * @returns object\n */\nexport async function openJson(path, fileName) {\n return new Promise((resolve, reject) => {\n let count = 0;\n console.log(`load ${path}/${fileName}.`); // eslint-disable-line no-console\n const intervalId = setInterval(() => {\n const pathFile = join(path, fileName);\n load(pathFile, JSONLoader)\n .then((result) => {\n clearInterval(intervalId);\n resolve(result);\n })\n .catch(() => {\n count++;\n if (count > 100) {\n clearInterval(intervalId);\n reject(new Error(`Cannon load ${path}/${fileName}.`));\n }\n });\n }, 200);\n });\n}\n/**\n * Check if the file exists\n * @param fileName - full name of file\n * @returns true if file exists, otherwise - false\n */\nexport async function isFileExists(fileName) {\n try {\n await fs.stat(fileName);\n return true;\n }\n catch {\n return false;\n }\n}\n/**\n * Remove dir with path\n *\n * @param path\n */\nexport function removeDir(path) {\n // (node:35607) [DEP0147] DeprecationWarning: In future versions of Node.js, fs.rmdir(path, { recursive: true }) will be removed. Use fs.rm(path, { recursive: true }) instead\n // @ts-ignore\n return fs.rm(path, { recursive: true });\n}\n/**\n * Remove file with path\n *\n * @param path\n */\nexport function removeFile(path) {\n return fs.unlink(path);\n}\n/**\n * Generates absolute file path\n * @param filePath\n */\nexport function getAbsoluteFilePath(filePath) {\n return isAbsolute(filePath) ? filePath : join(process.cwd(), filePath);\n}\n/**\n * Rename file with old path by new path\n * @param oldPath\n * @param newPath\n */\nexport async function renameFile(oldPath, newPath) {\n try {\n await fs.rename(oldPath, newPath);\n }\n catch (err) {\n // prettier-ignore\n console.log('Can\\'t rename file', err); // eslint-disable-line no-console\n }\n}\n", "import { createGzip } from 'zlib';\nimport { createReadStream, createWriteStream } from 'fs';\n/**\n * Compress file to gzip file\n *\n * @param pathFile - the path to the file\n * @return the path to the gzip file\n */\nexport function compressFileWithGzip(pathFile) {\n const compressedPathFile = `${pathFile}.gz`;\n const gzip = createGzip();\n const input = createReadStream(pathFile);\n const output = createWriteStream(compressedPathFile);\n return new Promise((resolve, reject) => {\n input.on('end', () => {\n console.log(`${compressedPathFile} compressed and saved.`); // eslint-disable-line no-undef,no-console\n resolve(compressedPathFile);\n });\n input.on('error', (error) => {\n console.log(`${compressedPathFile}: compression error!`); // eslint-disable-line no-undef,no-console\n reject(error);\n });\n input.pipe(gzip).pipe(output);\n });\n}\n", "import { join } from 'path';\nimport { promises as fs } from 'fs';\nimport { getAbsoluteFilePath } from \"./file-utils.js\";\n/**\n * Converts time value to string.\n * @param time - high-resolution real time in a [seconds, nanoseconds] tuple Array, or a value on milliseconds.\n * @returns string representation of the time\n */\nexport function timeConverter(time) {\n if (typeof time === 'number') {\n // time - real time in milli-seconds\n const milliSecondsInSecond = 1e3;\n const timeInSeconds = Math.floor(time / milliSecondsInSecond);\n const milliseconds = time - timeInSeconds * milliSecondsInSecond;\n return timeConverterFromSecondsAndMilliseconds(timeInSeconds, milliseconds);\n }\n // time - high-resolution real time in a [seconds, nanoseconds] tuple Array\n const nanoSecondsInMillisecond = 1e6;\n const timeInSeconds = time[0];\n const milliseconds = time[1] / nanoSecondsInMillisecond;\n return timeConverterFromSecondsAndMilliseconds(timeInSeconds, milliseconds);\n}\nfunction timeConverterFromSecondsAndMilliseconds(timeInSeconds, milliseconds) {\n const hours = Math.floor(timeInSeconds / 3600);\n timeInSeconds = timeInSeconds - hours * 3600;\n const minutes = Math.floor(timeInSeconds / 60);\n timeInSeconds = timeInSeconds - minutes * 60;\n const seconds = Math.floor(timeInSeconds);\n let result = '';\n if (hours) {\n result += `${hours}h `;\n }\n if (minutes) {\n result += `${minutes}m `;\n }\n if (seconds) {\n result += `${seconds}s`;\n }\n if (!result) {\n result += `${Math.floor(milliseconds)}ms`;\n }\n return result;\n}\nexport async function calculateFilesSize(params) {\n const { slpk, outputPath, tilesetName } = params;\n const fullOutputPath = getAbsoluteFilePath(outputPath);\n try {\n if (slpk) {\n const slpkPath = join(fullOutputPath, `${tilesetName}.slpk`);\n const stat = await fs.stat(slpkPath);\n return stat.size;\n }\n const directoryPath = join(fullOutputPath, tilesetName);\n const totalSize = await getTotalFilesSize(directoryPath);\n return totalSize;\n }\n catch (error) {\n console.log('Calculate file sizes error: ', error); // eslint-disable-line\n return null;\n }\n}\nasync function getTotalFilesSize(dirPath) {\n let totalFileSize = 0;\n const files = await fs.readdir(dirPath);\n for (const file of files) {\n const fileStat = await fs.stat(join(dirPath, file));\n if (fileStat.isDirectory()) {\n totalFileSize += await getTotalFilesSize(join(dirPath, file));\n }\n else {\n totalFileSize += fileStat.size;\n }\n }\n return totalFileSize;\n}\n", "import { Vector3, Matrix4, Vector4 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\nimport { DracoWriterWorker } from '@loaders.gl/draco';\nimport { assert, encode } from '@loaders.gl/core';\nimport { concatenateArrayBuffers, concatenateTypedArrays } from '@loaders.gl/loader-utils';\nimport md5 from 'md5';\nimport { v4 as uuidv4 } from 'uuid';\nimport { generateAttributes } from \"./geometry-attributes.js\";\nimport { createBoundingVolumesFromGeometry } from \"./coordinate-converter.js\";\nimport { prepareDataForAttributesConversion } from \"./gltf-attributes.js\";\nimport { getTextureByMetadataClass, handleBatchIdsExtensions } from \"./batch-ids-extensions.js\";\nimport { checkPropertiesLength, flattenPropertyTableByFeatureIds } from \"./feature-attributes.js\";\nimport { GL } from '@loaders.gl/math';\nimport { generateSyntheticIndices } from \"../../lib/utils/geometry-utils.js\";\nimport { EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA } from '@loaders.gl/gltf';\n// Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md\nconst DEFAULT_ROUGHNESS_FACTOR = 1;\nconst DEFAULT_METALLIC_FACTOR = 1;\nconst VALUES_PER_VERTEX = 3;\nconst VALUES_PER_TEX_COORD = 2;\nconst VALUES_PER_COLOR_ELEMENT = 4;\nconst STRING_TYPE = 'string';\nconst SHORT_INT_TYPE = 'Int32';\nconst DOUBLE_TYPE = 'Float64';\nconst OBJECT_ID_TYPE = 'Oid32';\n/*\n * 'CUSTOM_ATTRIBUTE_2' - Attribute name which includes batch info and used by New York map.\n * _BATCHID - Default attribute name which includes batch info.\n * BATCHID - Legacy attribute name which includes batch info.\n */\nconst BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES = ['CUSTOM_ATTRIBUTE_2', '_BATCHID', 'BATCHID'];\nlet scratchVector = new Vector3();\n/**\n * Convert binary data from b3dm file to i3s resources\n *\n * @param tileContent - 3d tile content\n * @param tileTransform - transformation matrix of the tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n * @param tileBoundingVolume - initialized bounding volume of the source tile\n * @param addNodeToNodePage - function to add new node to node pages\n * @param propertyTable - batch table (corresponding to feature attributes data)\n * @param featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes\n * @param attributeStorageInfo - attributes metadata from 3DSceneLayer json\n * @param draco - is converter should create draco compressed geometry\n * @param generateBoundingVolumes - is converter should create accurate bounding voulmes from geometry attributes\n * @param shouldMergeMaterials - Try to merge similar materials to be able to merge meshes into one node\n * @param geoidHeightModel - model to convert elevation from elipsoidal to geoid\n * @param libraries - dynamicaly loaded 3rd-party libraries\n * @param metadataClass `- user selected feature metadata class name`\n * @returns Array of node resources to create one or more i3s nodes\n */\nexport default async function convertB3dmToI3sGeometry({ tileContent, tileTransform, tileBoundingVolume, addNodeToNodePage, propertyTable, featuresHashArray, attributeStorageInfo, draco, generateBoundingVolumes, shouldMergeMaterials, geoidHeightModel, libraries, metadataClass }) {\n const useCartesianPositions = generateBoundingVolumes;\n const materialAndTextureList = await convertMaterials(tileContent.gltf?.materials, shouldMergeMaterials);\n const dataForAttributesConversion = prepareDataForAttributesConversion(tileContent, tileTransform, tileBoundingVolume);\n const featureTexture = getTextureByMetadataClass(tileContent, metadataClass);\n const convertedAttributesMap = await convertAttributes(dataForAttributesConversion, materialAndTextureList, useCartesianPositions, featureTexture);\n /** Usage of worker here brings more overhead than advantage */\n // const convertedAttributesMap: Map<string, ConvertedAttributes> =\n // await transformI3SAttributesOnWorker(dataForAttributesConversion, {\n // reuseWorkers: true,\n // _nodeWorkers: true,\n // useCartesianPositions,\n // source: workerSource.I3SAttributes\n // });\n if (generateBoundingVolumes) {\n _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeightModel);\n }\n const result = [];\n for (const materialAndTexture of materialAndTextureList) {\n const originarMaterialId = materialAndTexture.mergedMaterials[0].originalMaterialId;\n if (!convertedAttributesMap.has(originarMaterialId)) {\n continue; // eslint-disable-line no-continue\n }\n const convertedAttributes = convertedAttributesMap.get(originarMaterialId);\n if (!convertedAttributes) {\n continue; // eslint-disable-line no-continue\n }\n const { material, texture } = materialAndTexture;\n const nodeId = await addNodeToNodePage();\n result.push(await _makeNodeResources({\n convertedAttributes,\n material,\n texture,\n tileContent,\n nodeId,\n featuresHashArray,\n propertyTable,\n attributeStorageInfo,\n draco,\n libraries\n }));\n }\n if (!result.length) {\n return null;\n }\n return result;\n}\n/**\n * Create bounding volumes based on positions\n * @param convertedAttributesMap - geometry attributes map\n * @param geoidHeightModel - geoid height model to convert elevation from elipsoidal to geoid\n */\nfunction _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeightModel) {\n for (const attributes of convertedAttributesMap.values()) {\n const boundingVolumes = createBoundingVolumesFromGeometry(attributes.positions, geoidHeightModel);\n attributes.boundingVolumes = boundingVolumes;\n const cartographicOrigin = boundingVolumes.obb.center;\n for (let index = 0; index < attributes.positions.length; index += VALUES_PER_VERTEX) {\n const vertex = attributes.positions.subarray(index, index + VALUES_PER_VERTEX);\n Ellipsoid.WGS84.cartesianToCartographic(Array.from(vertex), scratchVector);\n scratchVector[2] =\n scratchVector[2] - geoidHeightModel.getHeight(scratchVector[1], scratchVector[0]);\n scratchVector = scratchVector.subtract(cartographicOrigin);\n attributes.positions.set(scratchVector, index);\n }\n }\n}\n/**\n *\n * @param params\n * @param params.convertedAttributes - Converted geometry attributes\n * @param params.material - I3S PBR-like material definition\n * @param params.texture - texture content\n * @param params.tileContent - 3DTiles decoded content\n * @param params.nodeId - new node ID\n * @param params.featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes\n * @param params.propertyTable - batch table (corresponding to feature attributes data)\n * @param params.attributeStorageInfo - attributes metadata from 3DSceneLayer json\n * @param params.draco - is converter should create draco compressed geometry\n * @param libraries - dynamicaly loaded 3rd-party libraries\n * @returns Array of I3S node resources\n */\nasync function _makeNodeResources({ convertedAttributes, material, texture, tileContent, nodeId, featuresHashArray, propertyTable, attributeStorageInfo, draco, libraries }) {\n const boundingVolumes = convertedAttributes.boundingVolumes;\n const vertexCount = convertedAttributes.positions.length / VALUES_PER_VERTEX;\n const { faceRange, featureIds, positions, normals, colors, uvRegions, texCoords, featureCount } = generateAttributes(convertedAttributes);\n let featureIdsMap = {};\n if (propertyTable) {\n /**\n * 3DTiles has featureIndices unique only for one tile.\n * In I3S featureIds are unique layer-wide. We create featureIds from all feature properties.\n * If 3DTiles features has equal set of properties they are considered as same feature in I3S.\n */\n featureIdsMap = makeFeatureIdsUnique(featureIds, convertedAttributes.featureIndices, featuresHashArray, propertyTable);\n }\n const header = new Uint32Array(2);\n const typedFeatureIds = generateBigUint64Array(featureIds);\n header.set([vertexCount, featureCount], 0);\n const fileBuffer = new Uint8Array(concatenateArrayBuffers(header.buffer, positions.buffer, normals.buffer, texture ? texCoords.buffer : new ArrayBuffer(0), colors.buffer, uvRegions, typedFeatureIds.buffer, faceRange.buffer));\n // prettier-ignore\n const compressedGeometry = draco\n ? generateCompressedGeometry(vertexCount, convertedAttributes, {\n positions,\n normals,\n texCoords: texture ? texCoords : new Float32Array(0),\n colors,\n uvRegions,\n featureIds,\n faceRange\n }, libraries)\n : null;\n let attributes = [];\n if (attributeStorageInfo && propertyTable) {\n attributes = convertPropertyTableToAttributeBuffers(featureIds, featureIdsMap, propertyTable, attributeStorageInfo);\n }\n return {\n nodeId,\n geometry: fileBuffer,\n compressedGeometry,\n texture,\n hasUvRegions: Boolean(uvRegions.length),\n sharedResources: getSharedResources(tileContent.gltf?.materials || [], nodeId),\n meshMaterial: material,\n vertexCount,\n attributes,\n featureCount,\n boundingVolumes\n };\n}\n/**\n * Convert attributes from the gltf nodes tree to i3s plain geometry\n * @param attributesData - geometry attributes from gltf\n * @param materialAndTextureList - array of data about materials and textures of the content\n * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.\n * Cartesian coordinates will be required for creating bounding voulmest from geometry positions\n * @param featureTexture - feature texture key\n * @returns map of converted geometry attributes\n */\nexport async function convertAttributes(attributesData, materialAndTextureList, useCartesianPositions, featureTexture) {\n const { nodes, images, cartographicOrigin, cartesianModelMatrix } = attributesData;\n const attributesMap = new Map();\n for (const materialAndTexture of materialAndTextureList) {\n const attributes = {\n positions: new Float32Array(0),\n normals: new Float32Array(0),\n texCoords: new Float32Array(0),\n colors: new Uint8Array(0),\n uvRegions: new Uint16Array(0),\n featureIndicesGroups: [],\n featureIndices: [],\n boundingVolumes: null,\n mergedMaterials: materialAndTexture.mergedMaterials\n };\n for (const mergedMaterial of materialAndTexture.mergedMaterials) {\n attributesMap.set(mergedMaterial.originalMaterialId, attributes);\n }\n }\n convertNodes({\n nodes,\n images,\n cartographicOrigin,\n cartesianModelMatrix,\n attributesMap,\n useCartesianPositions,\n featureTexture\n });\n for (const attrKey of attributesMap.keys()) {\n const attributes = attributesMap.get(attrKey);\n if (!attributes) {\n continue; // eslint-disable-line no-continue\n }\n if (attributes.positions.length === 0) {\n attributesMap.delete(attrKey);\n continue; // eslint-disable-line no-continue\n }\n if (attributes.featureIndicesGroups) {\n attributes.featureIndices = attributes.featureIndicesGroups.reduce((acc, value) => acc.concat(value));\n delete attributes.featureIndicesGroups;\n }\n }\n return attributesMap;\n}\n/**\n * glTF has hierarchical structure of nodes. This function converts nodes starting from those which are in gltf scene object.\n * The goal is applying tranformation matrix for all children. Functions \"convertNodes\" and \"convertNode\" work together recursively.\n * @param nodes - gltf nodes array\n * @param images - gltf images array\n * @param cartographicOrigin - cartographic origin of bounding volume\n * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic\n * @param attributesMap - for recursive concatenation of attributes\n * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.\n * Cartesian coordinates will be required for creating bounding voulmest from geometry positions\n * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @param featureTexture - feature texture key\n * @returns {void}\n */\nfunction convertNodes({ nodes, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]), featureTexture }) {\n if (nodes) {\n for (const node of nodes) {\n convertNode({\n node,\n images,\n cartographicOrigin,\n cartesianModelMatrix,\n attributesMap,\n useCartesianPositions,\n matrix,\n featureTexture\n });\n }\n }\n}\n/**\n * Generate transformation matrix for node\n * Aapply all gltf transformations to initial transformation matrix.\n * @param node\n * @param matrix\n */\nfunction getCompositeTransformationMatrix(node, matrix) {\n let transformationMatrix = matrix;\n const { matrix: nodeMatrix, rotation, scale, translation } = node;\n if (nodeMatrix) {\n transformationMatrix = matrix.multiplyRight(nodeMatrix);\n }\n if (translation) {\n transformationMatrix = transformationMatrix.translate(translation);\n }\n if (rotation) {\n transformationMatrix = transformationMatrix.rotateXYZ(rotation);\n }\n if (scale) {\n transformationMatrix = transformationMatrix.scale(scale);\n }\n return transformationMatrix;\n}\n/**\n * Convert all primitives of node and all children nodes\n * @param node - gltf node\n * @param images - gltf images array\n * @param cartographicOrigin - cartographic origin of bounding volume\n * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic\n * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of\n * attributes\n * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.\n * Cartesian coordinates will be required for creating bounding voulmest from geometry positions\n * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @param featureTexture - feature texture key\n */\nfunction convertNode({ node, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]), featureTexture }) {\n const transformationMatrix = getCompositeTransformationMatrix(node, matrix);\n const mesh = node.mesh;\n if (mesh) {\n convertMesh({\n mesh,\n images,\n cartographicOrigin,\n cartesianModelMatrix,\n attributesMap,\n useCartesianPositions,\n matrix: transformationMatrix,\n featureTexture\n });\n }\n convertNodes({\n nodes: node.children || [],\n images,\n cartographicOrigin,\n cartesianModelMatrix,\n attributesMap,\n useCartesianPositions,\n matrix: transformationMatrix,\n featureTexture\n });\n}\n/**\n * Convert all primitives of the mesh\n * @param mesh - gltf mesh data\n * @param images - gltf images array\n * @param cartographicOrigin - cartographic origin of bounding volume\n * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic\n * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of\n * attributes\n * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.\n * Cartesian coordinates will be required for creating bounding voulmest from geometry positions\n * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of\n * attributes\n * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @param featureTexture - feature texture key\n */\nfunction convertMesh({ mesh, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions = false, matrix, featureTexture }) {\n for (const primitive of mesh.primitives) {\n let outputAttributes = null;\n let materialUvRegion;\n if (primitive.material) {\n outputAttributes = attributesMap.get(primitive.material.id);\n materialUvRegion = outputAttributes?.mergedMaterials.find(({ originalMaterialId }) => originalMaterialId === primitive.material?.id)?.uvRegion;\n }\n else if (attributesMap.has('default')) {\n outputAttributes = attributesMap.get('default');\n }\n assert(outputAttributes !== null, 'Primitive - material mapping failed');\n // Per the spec https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode\n // GL.TRIANGLES is default. So in case `mode` is `undefined`, it is 'TRIANGLES'\n assert(primitive.mode === undefined ||\n primitive.mode === GL.TRIANGLES ||\n primitive.mode === GL.TRIANGLE_STRIP, `Primitive - unsupported mode ${primitive.mode}`);\n const attributes = primitive.attributes;\n if (!outputAttributes) {\n continue; // eslint-disable-line no-continue\n }\n const indices = normalizeIndices(primitive);\n outputAttributes.positions = concatenateTypedArrays(outputAttributes.positions, transformVertexArray({\n vertices: attributes.POSITION.value,\n cartographicOrigin,\n cartesianModelMatrix,\n nodeMatrix: matrix,\n indices,\n attributeSpecificTransformation: transformVertexPositions,\n useCartesianPositions\n }));\n outputAttributes.normals = concatenateTypedArrays(outputAttributes.normals, transformVertexArray({\n vertices: attributes.NORMAL && attributes.NORMAL.value,\n cartographicOrigin,\n cartesianModelMatrix,\n nodeMatrix: matrix,\n indices,\n attributeSpecificTransformation: transformVertexNormals,\n useCartesianPositions: false\n }));\n outputAttributes.texCoords = concatenateTypedArrays(outputAttributes.texCoords, flattenTexCoords(attributes.TEXCOORD_0 && attributes.TEXCOORD_0.value, indices));\n outputAttributes.colors = concatenateTypedArrays(outputAttributes.colors, flattenColors(attributes.COLOR_0, indices));\n if (materialUvRegion) {\n outputAttributes.uvRegions = concatenateTypedArrays(outputAttributes.uvRegions, createUvRegion(materialUvRegion, indices));\n }\n outputAttributes.featureIndicesGroups = outputAttributes.featureIndicesGroups || [];\n outputAttributes.featureIndicesGroups.push(flattenBatchIds(getBatchIds(attributes, primitive, images, featureTexture), indices));\n }\n}\n/**\n * Converts TRIANGLE-STRIPS to independent TRIANGLES\n * @param primitive - the primitive to get the indices from\n * @returns indices of vertices of the independent triangles\n */\nfunction normalizeIndices(primitive) {\n let indices = primitive.indices?.value;\n if (!indices) {\n const positions = primitive.attributes.POSITION.value;\n return generateSyntheticIndices(positions.length / VALUES_PER_VERTEX);\n }\n if (indices && primitive.mode === GL.TRIANGLE_STRIP) {\n /*\n TRIANGLE_STRIP geometry contains n+2 vertices for n triangles;\n TRIANGLE geometry contains n*3 vertices for n triangles.\n The conversion from TRIANGLE_STRIP to TRIANGLE implies duplicating adjacent vertices.\n */\n const TypedArrayConstructor = indices.constructor;\n const newIndices = new TypedArrayConstructor((indices.length - 2) * 3);\n // Copy the first triangle indices with no modification like [i0, i1, i2, ...] -> [i0, i1, i2, ...]\n let triangleIndex = 0;\n let currentTriangle = indices.slice(0, 3);\n newIndices.set(currentTriangle, 0);\n // The rest triangle indices are being taken from strips using the following logic:\n // [i1, i2, i3, i4, i5, i6, ...] -> [i3, i2, i1, i2, i3, i4, i5, i4, i3, i4, i5, i6, ...]\n for (let i = 1; i + 2 < indices.length; i++) {\n triangleIndex += 3;\n currentTriangle = indices.slice(i, i + 3);\n if (i % 2 === 0) {\n newIndices.set(currentTriangle, triangleIndex);\n }\n else {\n // The following \"reverce\" is necessary to calculate normals correctly\n newIndices.set(currentTriangle.reverse(), triangleIndex);\n }\n }\n indices = newIndices;\n }\n return indices;\n}\n/**\n * Convert vertices attributes (POSITIONS or NORMALS) to i3s compatible format\n * @param args\n * @param args.vertices - gltf primitive POSITION or NORMAL attribute\n * @param args.cartographicOrigin - cartographic origin coordinates\n * @param args.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format\n * @param args.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @param args.indices - gltf primitive indices\n * @param args.attributeSpecificTransformation - function to do attribute - specific transformations\n * @param args.useCartesianPositions - use coordinates as it is.\n * @returns\n */\nfunction transformVertexArray(args) {\n const { vertices, indices, attributeSpecificTransformation } = args;\n const newVertices = new Float32Array(indices.length * VALUES_PER_VERTEX);\n if (!vertices) {\n return newVertices;\n }\n for (let i = 0; i < indices.length; i++) {\n const coordIndex = indices[i] * VALUES_PER_VERTEX;\n const vertex = vertices.subarray(coordIndex, coordIndex + VALUES_PER_VERTEX);\n let vertexVector = new Vector3(Array.from(vertex));\n vertexVector = attributeSpecificTransformation(vertexVector, args);\n newVertices[i * VALUES_PER_VERTEX] = vertexVector.x;\n newVertices[i * VALUES_PER_VERTEX + 1] = vertexVector.y;\n newVertices[i * VALUES_PER_VERTEX + 2] = vertexVector.z;\n }\n return newVertices;\n}\n/**\n * Trasform positions vector with the attribute specific transformations\n * @param vertexVector - source positions vector to transform\n * @param calleeArgs\n * @param calleeArgs.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format\n * @param calleeArgs.cartographicOrigin - cartographic origin coordinates\n * @param calleeArgs.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @param calleeArgs.useCartesianPositions - use coordinates as it is.\n * @returns transformed positions vector\n */\nfunction transformVertexPositions(vertexVector, calleeArgs) {\n const { cartesianModelMatrix, cartographicOrigin, nodeMatrix, useCartesianPositions } = calleeArgs;\n if (nodeMatrix) {\n vertexVector = vertexVector.transform(nodeMatrix);\n }\n vertexVector = vertexVector.transform(cartesianModelMatrix);\n if (useCartesianPositions) {\n return vertexVector;\n }\n Ellipsoid.WGS84.cartesianToCartographic([vertexVector[0], vertexVector[1], vertexVector[2]], vertexVector);\n vertexVector = vertexVector.subtract(cartographicOrigin);\n return vertexVector;\n}\n/**\n * Trasform normals vector with the attribute specific transformations\n * @param vertexVector - source normals vector to transform\n * @param calleeArgs\n * @param calleeArgs.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format\n * @param calleeArgs.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @returns transformed normals vector\n */\nfunction transformVertexNormals(vertexVector, calleeArgs) {\n const { cartesianModelMatrix, nodeMatrix } = calleeArgs;\n if (nodeMatrix) {\n vertexVector = vertexVector.transformAsVector(nodeMatrix);\n }\n vertexVector = vertexVector.transformAsVector(cartesianModelMatrix);\n return vertexVector;\n}\n/**\n * Convert uv0 (texture coordinates) from coords based on indices to plain arrays, compatible with i3s\n * @param texCoords - gltf primitive TEXCOORD_0 attribute\n * @param indices - gltf primitive indices\n * @returns flattened texture coordinates\n */\nfunction flattenTexCoords(texCoords, indices) {\n const newTexCoords = new Float32Array(indices.length * VALUES_PER_TEX_COORD);\n if (!texCoords) {\n // We need dummy UV0s because it is required in 1.6\n // https://github.com/Esri/i3s-spec/blob/master/docs/1.6/vertexAttribute.cmn.md\n newTexCoords.fill(1);\n return newTexCoords;\n }\n for (let i = 0; i < indices.length; i++) {\n const coordIndex = indices[i] * VALUES_PER_TEX_COORD;\n const texCoord = texCoords.subarray(coordIndex, coordIndex + VALUES_PER_TEX_COORD);\n newTexCoords[i * VALUES_PER_TEX_COORD] = texCoord[0];\n newTexCoords[i * VALUES_PER_TEX_COORD + 1] = texCoord[1];\n }\n return newTexCoords;\n}\n/**\n * Convert color from COLOR_0 based on indices to plain arrays, compatible with i3s\n * @param colorsAttribute - gltf primitive COLOR_0 attribute\n * @param indices - gltf primitive indices\n * @returns flattened colors attribute\n */\nfunction flattenColors(colorsAttribute, indices) {\n const components = colorsAttribute?.components || VALUES_PER_COLOR_ELEMENT;\n const newColors = new Uint8Array(indices.length * components);\n if (!colorsAttribute) {\n // Vertex color multiplies by material color so it must be normalized 1 by default\n newColors.fill(255);\n return newColors;\n }\n const colors = colorsAttribute.value;\n for (let i = 0; i < indices.length; i++) {\n const colorIndex = indices[i] * components;\n const color = colors.subarray(colorIndex, colorIndex + components);\n const colorUint8 = new Uint8Array(components);\n for (let j = 0; j < color.length; j++) {\n colorUint8[j] = color[j] * 255;\n }\n newColors.set(colorUint8, i * components);\n }\n return newColors;\n}\n/**\n * Create per-vertex uv-region array\n * @param materialUvRegion - uv-region fragment for a single vertex\n * @param indices - geometry indices data\n * @returns - uv-region array\n */\nfunction createUvRegion(materialUvRegion, indices) {\n const result = new Uint16Array(indices.length * 4);\n for (let i = 0; i < result.length; i += 4) {\n result.set(materialUvRegion, i);\n }\n return result;\n}\n/**\n * Flatten batchedIds list based on indices to right ordered array, compatible with i3s\n * @param batchedIds - gltf primitive\n * @param indices - gltf primitive indices\n * @returns flattened batch ids\n */\nfunction flattenBatchIds(batchedIds, indices) {\n if (!batchedIds.length || !indices.length) {\n return [];\n }\n const newBatchIds = [];\n for (let i = 0; i < indices.length; i++) {\n const coordIndex = indices[i];\n newBatchIds.push(batchedIds[coordIndex]);\n }\n return newBatchIds;\n}\n/**\n * Get batchIds for featureIds creation\n * @param attributes - gltf accessors\n * @param primitive - gltf primitive data\n * @param images - gltf texture images\n * @param featureTexture - feature texture key\n * @return batch IDs\n */\nfunction getBatchIds(attributes, primitive, images, featureTexture) {\n const batchIds = handleBatchIdsExtensions(attributes, primitive, images, featureTexture);\n if (batchIds.length) {\n return batchIds;\n }\n for (let index = 0; index < BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES.length; index++) {\n const possibleBatchIdAttributeName = BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES[index];\n if (attributes[possibleBatchIdAttributeName] &&\n attributes[possibleBatchIdAttributeName].value) {\n return attributes[possibleBatchIdAttributeName].value;\n }\n }\n return [];\n}\n/**\n * Convert GLTF material to I3S material definitions and textures\n * @param sourceMaterials Source GLTF materials\n * @param shouldMergeMaterials - if true - the converter will try to merge similar materials\n * to be able to merge primitives having those materials\n * @returns Array of Couples I3SMaterialDefinition + texture content\n */\nasync function convertMaterials(sourceMaterials = [], shouldMergeMaterials) {\n let materials = [];\n for (const sourceMaterial of sourceMaterials) {\n materials.push(convertMaterial(sourceMaterial));\n }\n if (shouldMergeMaterials) {\n materials = await mergeAllMaterials(materials);\n }\n return materials;\n}\n/**\n * Merge materials when possible\n * @param materials materials array\n * @returns merged materials array\n */\n// eslint-disable-next-line max-statements, complexity\nasync function mergeAllMaterials(materials) {\n const result = [];\n while (materials.length > 0) {\n let newMaterial = materials.splice(0, 1)[0];\n const mergedIndices = [];\n for (let i = 0; i < materials.length; i++) {\n const material = materials[i];\n if ((newMaterial.texture && material.texture) ||\n (!newMaterial.texture && !material.texture)) {\n newMaterial = await mergeMaterials(newMaterial, material);\n mergedIndices.push(i);\n }\n }\n if (newMaterial.texture && mergedIndices.length) {\n const newWidth = newMaterial.mergedMaterials?.reduce((accum, { textureSize }) => accum + (textureSize?.width || 0), 0);\n const newHeight = newMaterial.mergedMaterials?.reduce((accum, { textureSize }) => Math.max(accum, textureSize?.height || 0), 0);\n let currentX = -1;\n for (const aTextureMetadata of newMaterial.mergedMaterials) {\n if (aTextureMetadata.textureSize) {\n const newX = currentX +\n 1 +\n (aTextureMetadata.textureSize.width / newWidth) *\n 2 ** (Uint16Array.BYTES_PER_ELEMENT * 8) -\n 1;\n aTextureMetadata.uvRegion = new Uint16Array([\n currentX + 1,\n 0,\n newX,\n (aTextureMetadata.textureSize.height / newHeight) *\n 2 ** (Uint16Array.BYTES_PER_ELEMENT * 8) -\n 1\n ]);\n currentX = newX;\n }\n }\n newMaterial.texture.image.width = newWidth;\n newMaterial.texture.image.height = newHeight;\n }\n for (const index of mergedIndices.reverse()) {\n materials.splice(index, 1);\n }\n result.push(newMaterial);\n }\n if (!result.length) {\n result.push({\n material: getDefaultMaterial(),\n mergedMaterials: [{ originalMaterialId: 'default' }]\n });\n }\n return result;\n}\n/**\n * Merge 2 materials including texture\n * @param material1\n * @param material2\n * @returns\n */\nasync function mergeMaterials(material1, material2) {\n if (material1.texture?.bufferView &&\n material2.texture?.bufferView &&\n material1.mergedMaterials &&\n material2.mergedMaterials) {\n const buffer1 = Buffer.from(material1.texture.bufferView.data);\n const buffer2 = Buffer.from(material2.texture.bufferView.data);\n try {\n // @ts-ignore\n const { joinImages } = await import('join-images');\n const sharpData = await joinImages([buffer1, buffer2], { direction: 'horizontal' });\n material1.texture.bufferView.data = await sharpData\n .toFormat(material1.texture.mimeType === 'image/png' ? 'png' : 'jpeg')\n .toBuffer();\n }\n catch (error) {\n // eslint-disable-next-line no-console\n console.log('Join images into a texture atlas has failed. Consider usage `--split-nodes` option. (See documentation https://loaders.gl/modules/tile-converter/docs/cli-reference/tile-converter)');\n throw error;\n }\n // @ts-ignore\n material1.material.pbrMetallicRoughness.baseColorTexture.textureSetDefinitionId = 1;\n }\n material1.mergedMaterials = material1.mergedMaterials.concat(material2.mergedMaterials);\n return material1;\n}\n/**\n * Convert texture and material from gltf 2.0 material object\n * @param sourceMaterial - material object\n * @returns I3S material definition and texture\n */\nfunction convertMaterial(sourceMaterial) {\n const material = {\n doubleSided: sourceMaterial.doubleSided,\n emissiveFactor: sourceMaterial.emissiveFactor?.map((c) => Math.round(c * 255)),\n // It is in upper case in GLTF: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#alpha-coverage\n // But it is in lower case in I3S: https://github.com/Esri/i3s-spec/blob/master/docs/1.7/materialDefinitions.cmn.md\n alphaMode: convertAlphaMode(sourceMaterial.alphaMode),\n pbrMetallicRoughness: {\n roughnessFactor: sourceMaterial?.pbrMetallicRoughness?.roughnessFactor || DEFAULT_ROUGHNESS_FACTOR,\n metallicFactor: sourceMaterial?.pbrMetallicRoughness?.metallicFactor || DEFAULT_METALLIC_FACTOR\n }\n };\n let texture;\n if (sourceMaterial?.pbrMetallicRoughness?.baseColorTexture) {\n texture = sourceMaterial.pbrMetallicRoughness.baseColorTexture.texture.source;\n material.pbrMetallicRoughness.baseColorTexture = {\n textureSetDefinitionId: 0\n };\n }\n else if (sourceMaterial.emissiveTexture) {\n texture = sourceMaterial.emissiveTexture.texture.source;\n // ArcGIS webscene doesn't show emissiveTexture but shows baseColorTexture\n material.pbrMetallicRoughness.baseColorTexture = {\n textureSetDefinitionId: 0\n };\n }\n sourceMaterial.id = Number.isFinite(sourceMaterial.id) ? sourceMaterial.id : uuidv4();\n const mergedMaterials = [{ originalMaterialId: sourceMaterial.id }];\n if (!texture) {\n // Should use default baseColorFactor if it is not present in source material\n // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-pbrmetallicroughness\n const baseColorFactor = sourceMaterial?.pbrMetallicRoughness?.baseColorFactor;\n material.pbrMetallicRoughness.baseColorFactor =\n (baseColorFactor && baseColorFactor.map((c) => Math.round(c * 255))) || undefined;\n }\n else {\n mergedMaterials[0].textureSize = { width: texture.image.width, height: texture.image.height };\n }\n return { material, texture, mergedMaterials };\n}\n/**\n * Converts from `alphaMode` material property from GLTF to I3S format\n * @param gltfAlphaMode glTF material `alphaMode` property\n * @returns I3SMaterialDefinition.alphaMode property\n */\nfunction convertAlphaMode(gltfAlphaMode) {\n switch (gltfAlphaMode) {\n case 'OPAQUE':\n return 'opaque';\n case 'MASK':\n return 'mask';\n case 'BLEND':\n return 'blend';\n default:\n return 'opaque';\n }\n}\n/**\n * Form default I3SMaterialDefinition\n * @returns I3S material definition\n */\nfunction getDefaultMaterial() {\n return {\n alphaMode: 'opaque',\n pbrMetallicRoughness: {\n metallicFactor: 1,\n roughnessFactor: 1\n }\n };\n}\n/**\n * Form \"sharedResources\" from gltf materials array\n * @param gltfMaterials - GLTF materials array\n * @param nodeId - I3S node ID\n * @returns {materialDefinitionInfos: Object[], textureDefinitionInfos: Object[]} -\n * 2 arrays in format of i3s sharedResources data https://github.com/Esri/i3s-spec/blob/master/docs/1.7/sharedResource.cmn.md\n */\nfunction getSharedResources(gltfMaterials, nodeId) {\n const i3sResources = {};\n if (!gltfMaterials || !gltfMaterials.length) {\n return i3sResources;\n }\n i3sResources.materialDefinitionInfos = [];\n for (const gltfMaterial of gltfMaterials) {\n const { materialDefinitionInfo, textureDefinitionInfo } = convertGLTFMaterialToI3sSharedResources(gltfMaterial, nodeId);\n i3sResources.materialDefinitionInfos.push(materialDefinitionInfo);\n if (textureDefinitionInfo) {\n i3sResources.textureDefinitionInfos = i3sResources.textureDefinitionInfos || [];\n i3sResources.textureDefinitionInfos.push(textureDefinitionInfo);\n }\n }\n return i3sResources;\n}\n/**\n * Convert gltf material into I3S sharedResources data\n * @param gltfMaterial - gltf material data\n * @param nodeId - I3S node ID\n * @returns - Couple {materialDefinitionInfo, textureDefinitionInfo} extracted from gltf material data\n */\nfunction convertGLTFMaterialToI3sSharedResources(gltfMaterial, nodeId) {\n const texture = gltfMaterial?.pbrMetallicRoughness?.baseColorTexture || gltfMaterial.emissiveTexture;\n let textureDefinitionInfo = null;\n if (texture) {\n textureDefinitionInfo = extractSharedResourcesTextureInfo(texture.texture, nodeId);\n }\n const { baseColorFactor, metallicFactor } = gltfMaterial?.pbrMetallicRoughness || {};\n let colorFactor = baseColorFactor;\n // If alpha channel is 0 try to get emissive factor from gltf material.\n if ((!baseColorFactor || baseColorFactor[3] === 0) && gltfMaterial.emissiveFactor) {\n colorFactor = gltfMaterial.emissiveFactor;\n colorFactor[3] = colorFactor[3] || 1;\n }\n return {\n materialDefinitionInfo: extractSharedResourcesMaterialInfo(colorFactor || [1, 1, 1, 1], metallicFactor),\n textureDefinitionInfo\n };\n}\n/**\n * Form \"materialDefinition\" which is part of \"sharedResouces\"\n * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materials\n * See formulas in appendix \"Appendix B: BRDF Implementation\":\n * const dielectricSpecular = rgb(0.04, 0.04, 0.04)\n * const black = rgb(0, 0, 0)\n * cdiff = lerp(baseColor.rgb * (1 - dielectricSpecular.r), black, metallic)\n * F0 = lerp(dieletricSpecular, baseColor.rgb, metallic)\n *\n * Assumption: F0 - specular in i3s (\"specular reflection\" <-> \"reflectance value at normal incidence\")\n * cdiff - diffuse in i3s (\"Diffuse color\" <-> \"'c' diffuse\" (c means color?))\n * @param baseColorFactor - RGBA color in 0..1 format\n * @param metallicFactor - \"metallicFactor\" attribute of gltf material object\n * @returns material definition info for I3S shared resource\n */\nfunction extractSharedResourcesMaterialInfo(baseColorFactor, metallicFactor = 1) {\n const matDielectricColorComponent = 0.04 / 255; // Color from rgb (255) to 0..1 resolution\n // All color resolutions are 0..1\n const black = new Vector4(0, 0, 0, 1);\n const unitVector = new Vector4(1, 1, 1, 1);\n const dielectricSpecular = new Vector4(matDielectricColorComponent, matDielectricColorComponent, matDielectricColorComponent, 0);\n const baseColorVector = new Vector4(baseColorFactor);\n // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material\n // Formulas for Cdiff & F0\n const firstOperand = unitVector.subtract(dielectricSpecular).multiply(baseColorVector);\n const diffuse = firstOperand.lerp(firstOperand, black, metallicFactor);\n dielectricSpecular[3] = 1;\n const specular = dielectricSpecular.lerp(dielectricSpecular, baseColorVector, metallicFactor);\n return {\n params: {\n // @ts-expect-error NumericArray\n diffuse: diffuse.toArray(),\n // @ts-expect-error NumericArray\n specular: specular.toArray(),\n renderMode: 'solid'\n }\n };\n}\n/**\n * Form \"textureDefinition\" which is part of \"sharedResouces\"\n * @param texture - texture image info\n * @param nodeId - I3S node ID\n * @returns texture definition infor for shared resource\n */\nfunction extractSharedResourcesTextureInfo(texture, nodeId) {\n return {\n encoding: texture?.source?.mimeType ? [texture.source.mimeType] : undefined,\n images: [\n {\n // 'i3s' has just size which is width of the image. Images are supposed to be square.\n // https://github.com/Esri/i3s-spec/blob/master/docs/1.7/image.cmn.md\n id: generateImageId(texture, nodeId),\n size: texture.source?.image.width,\n length: texture.source?.image.data.length ? [texture.source?.image.data.length] : undefined\n }\n ]\n };\n}\n/**\n * Formula for calculating imageId:\n * https://github.com/Esri/i3s-spec/blob/0a6366a9249b831db8436c322f8d27521e86cf07/format/Indexed%203d%20Scene%20Layer%20Format%20Specification.md#generating-image-ids\n * @param texture - texture image info\n * @param nodeId - I3S node ID\n * @returns calculate image ID according to the spec\n */\nfunction generateImageId(texture, nodeId) {\n const { width, height } = texture.source?.image || {};\n if (!width || !height) {\n return '';\n }\n const levelCountOfTexture = 1;\n const indexOfLevel = 0;\n const indexOfTextureInStore = nodeId + 1;\n const zerosCount = 32 - indexOfTextureInStore.toString(2).length;\n const rightHalf = '0'.repeat(zerosCount).concat(indexOfTextureInStore.toString(2));\n const shiftedLevelCountOfTexture = levelCountOfTexture << 28;\n const shiftedIndexOfLevel = indexOfLevel << 24;\n const shiftedWidth = (width - 1) << 12;\n const shiftedHeight = (height - 1) << 0;\n const leftHalf = shiftedLevelCountOfTexture + shiftedIndexOfLevel + shiftedWidth + shiftedHeight;\n const imageId = BigInt(`0b${leftHalf.toString(2)}${rightHalf}`);\n return imageId.toString();\n}\n/**\n * Make all feature ids unique through all nodes in layout.\n * @param featureIds\n * @param featureIndices\n * @param featuresHashArray\n * @param batchTable\n * @returns propertyTable indices to map featureIds\n */\nfunction makeFeatureIdsUnique(featureIds, featureIndices, featuresHashArray, batchTable) {\n const replaceMap = getFeaturesReplaceMap(featureIds, batchTable, featuresHashArray);\n replaceIndicesByUnique(featureIndices, replaceMap);\n replaceIndicesByUnique(featureIds, replaceMap);\n return replaceMap;\n}\n/**\n * Generate replace map to make featureIds unique.\n * @param featureIds\n * @param batchTable\n * @param featuresHashArray\n * @returns\n */\nfunction getFeaturesReplaceMap(featureIds, batchTable, featuresHashArray) {\n const featureMap = {};\n for (let index = 0; index < featureIds.length; index++) {\n const oldFeatureId = featureIds[index];\n const uniqueFeatureId = getOrCreateUniqueFeatureId(index, batchTable, featuresHashArray);\n featureMap[oldFeatureId.toString()] = uniqueFeatureId;\n }\n return featureMap;\n}\n/**\n * Generates string for unique batch id creation.\n * @param batchTable\n * @param index\n * @returns\n */\nfunction generateStringFromBatchTableByIndex(batchTable, index) {\n let str = '';\n for (const key in batchTable) {\n str += batchTable[key][index];\n }\n return str;\n}\n/**\n * Return already exited featureId or creates and returns new to support unique feature ids throw nodes.\n * @param index\n * @param batchTable\n * @param featuresHashArray\n * @returns\n */\nfunction getOrCreateUniqueFeatureId(index, batchTable, featuresHashArray) {\n const batchTableStr = generateStringFromBatchTableByIndex(batchTable, index);\n const hash = md5(batchTableStr);\n if (featuresHashArray.includes(hash)) {\n return featuresHashArray.indexOf(hash);\n }\n return featuresHashArray.push(hash) - 1;\n}\n/**\n * Do replacement of indices for making them unique through all nodes.\n * @param indicesArray\n * @param featureMap\n * @returns\n */\nfunction replaceIndicesByUnique(indicesArray, featureMap) {\n for (let index = 0; index < indicesArray.length; index++) {\n indicesArray[index] = featureMap[indicesArray[index]];\n }\n}\n/**\n * Convert property table data to attribute buffers.\n * @param featureIds\n * @param propertyTable - table with metadata for particular feature.\n * @param attributeStorageInfo\n * @returns - Array of file buffers.\n */\nfunction convertPropertyTableToAttributeBuffers(featureIds, featureIdsMap, propertyTable, attributeStorageInfo) {\n const attributeBuffers = [];\n const needFlattenPropertyTable = checkPropertiesLength(featureIds, propertyTable);\n const properties = needFlattenPropertyTable\n ? flattenPropertyTableByFeatureIds(featureIdsMap, propertyTable)\n : propertyTable;\n const propertyTableWithObjectIds = {\n OBJECTID: featureIds,\n ...properties\n };\n for (const propertyName in propertyTableWithObjectIds) {\n const type = getAttributeType(propertyName, attributeStorageInfo);\n if (type) {\n const value = propertyTableWithObjectIds[propertyName];\n const attributeBuffer = generateAttributeBuffer(type, value);\n attributeBuffers.push(attributeBuffer);\n }\n }\n return attributeBuffers;\n}\n/**\n * Generates attribute buffer based on attribute type\n * @param type\n * @param value\n */\nfunction generateAttributeBuffer(type, value) {\n let attributeBuffer;\n switch (type) {\n case OBJECT_ID_TYPE:\n case SHORT_INT_TYPE:\n attributeBuffer = generateShortIntegerAttributeBuffer(value);\n break;\n case DOUBLE_TYPE:\n attributeBuffer = generateDoubleAttributeBuffer(value);\n break;\n case STRING_TYPE:\n attributeBuffer = generateStringAttributeBuffer(value);\n break;\n default:\n attributeBuffer = generateStringAttributeBuffer(value);\n }\n return attributeBuffer;\n}\n/**\n * Return attribute type.\n * @param key\n * @param attributeStorageInfo\n * @returns attribute type.\n */\nfunction getAttributeType(key, attributeStorageInfo) {\n const attribute = attributeStorageInfo.find((attr) => attr.name === key);\n if (!attribute) {\n // eslint-disable-next-line no-console\n console.error(`attribute is null, key=${key}, attributeStorageInfo=${JSON.stringify(attributeStorageInfo, null, 2)}`);\n return '';\n }\n if (!attribute.attributeValues) {\n // eslint-disable-next-line no-console\n console.error(`attributeValues is null, attribute=${attribute}`);\n return '';\n }\n return attribute.attributeValues.valueType;\n}\n/**\n * Convert short integer to attribute arrayBuffer.\n * @param featureIds\n * @returns - Buffer with objectId data.\n */\nfunction generateShortIntegerAttributeBuffer(featureIds) {\n const count = new Uint32Array([featureIds.length]);\n const valuesArray = new Uint32Array(featureIds);\n return concatenateArrayBuffers(count.buffer, valuesArray.buffer);\n}\n/**\n * Convert double to attribute arrayBuffer.\n * @param featureIds\n * @returns - Buffer with objectId data.\n */\nfunction generateDoubleAttributeBuffer(featureIds) {\n const count = new Uint32Array([featureIds.length]);\n const padding = new Uint8Array(4);\n const valuesArray = new Float64Array(featureIds);\n return concatenateArrayBuffers(count.buffer, padding.buffer, valuesArray.buffer);\n}\n/**\n * Convert batch table attributes to array buffer with batch table data.\n * @param batchAttributes\n * @returns - Buffer with batch table data.\n */\nfunction generateStringAttributeBuffer(batchAttributes) {\n const stringCountArray = new Uint32Array([batchAttributes.length]);\n let totalNumberOfBytes = 0;\n const stringSizesArray = new Uint32Array(batchAttributes.length);\n const stringBufferArray = [];\n for (let index = 0; index < batchAttributes.length; index++) {\n const currentString = `${String(batchAttributes[index])}\\0`;\n const currentStringBuffer = Buffer.from(currentString);\n const currentStringSize = currentStringBuffer.length;\n totalNumberOfBytes += currentStringSize;\n stringSizesArray[index] = currentStringSize;\n stringBufferArray.push(currentStringBuffer);\n }\n const totalBytes = new Uint32Array([totalNumberOfBytes]);\n return concatenateArrayBuffers(stringCountArray.buffer, totalBytes.buffer, stringSizesArray.buffer, ...stringBufferArray);\n}\n/**\n * Convert featureIds to BigUint64Array.\n * @param featureIds\n * @returns - Array of feature ids in BigUint64 format.\n */\nfunction generateBigUint64Array(featureIds) {\n const typedFeatureIds = new BigUint64Array(featureIds.length);\n for (let index = 0; index < featureIds.length; index++) {\n typedFeatureIds[index] = BigInt(featureIds[index]);\n }\n return typedFeatureIds;\n}\n/**\n * Generates draco compressed geometry\n * @param vertexCount\n * @param convertedAttributes - get rid of this argument here\n * @param attributes - geometry attributes to compress\n * @param libraries - dynamicaly loaded 3rd-party libraries\n * @returns - Compressed geometry.\n */\nasync function generateCompressedGeometry(vertexCount, convertedAttributes, attributes, libraries) {\n const { positions, normals, texCoords, colors, uvRegions, featureIds, faceRange } = attributes;\n const indices = new Uint32Array(vertexCount);\n for (let index = 0; index < indices.length; index++) {\n indices.set([index], index);\n }\n const featureIndices = new Uint32Array(convertedAttributes.featureIndices.length ? convertedAttributes.featureIndices : vertexCount);\n const featureIndex = generateFeatureIndexAttribute(featureIndices, faceRange);\n const compressedAttributes = {\n positions,\n normals,\n colors,\n 'feature-index': featureIndex\n };\n if (texCoords.length) {\n compressedAttributes.texCoords = texCoords;\n }\n const attributesMetadata = {\n 'feature-index': {\n 'i3s-attribute-type': 'feature-index',\n 'i3s-feature-ids': new Int32Array(featureIds)\n }\n };\n if (uvRegions.length) {\n compressedAttributes['uv-region'] = uvRegions;\n attributesMetadata['uv-region'] = {\n 'i3s-attribute-type': 'uv-region'\n };\n }\n return encode({ attributes: compressedAttributes, indices }, \n // @ts-expect-error if encoded supports worker writer, we should update its type signature\n DracoWriterWorker, {\n ...DracoWriterWorker.options,\n reuseWorkers: true,\n _nodeWorkers: true,\n modules: libraries,\n useLocalLibraries: true,\n draco: {\n method: 'MESH_SEQUENTIAL_ENCODING',\n attributesMetadata\n },\n ['draco-writer']: {\n // We need to load local fs workers because nodejs can't load workers from the Internet\n workerUrl: './modules/draco/dist/draco-writer-worker-node.js'\n }\n });\n}\n/**\n * Generates ordered feature indices based on face range\n * @param featureIndex\n * @param faceRange\n * @returns\n */\nfunction generateFeatureIndexAttribute(featureIndex, faceRange) {\n const orderedFeatureIndices = new Uint32Array(featureIndex.length);\n let fillIndex = 0;\n let startIndex = 0;\n for (let index = 1; index < faceRange.length; index += 2) {\n const endIndex = (faceRange[index] + 1) * VALUES_PER_VERTEX;\n orderedFeatureIndices.fill(fillIndex, startIndex, endIndex);\n fillIndex++;\n startIndex = endIndex + 1;\n }\n return orderedFeatureIndices;\n}\n/**\n * Find property table in tile\n * For example it can be batchTable for b3dm files or property table in gLTF extension.\n * @param tileContent - 3DTiles tile content\n * @param metadataClass - user selected feature metadata class name\n * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA or EXT_STRUCTURAL_METADATA.\n */\nexport function getPropertyTable(tileContent, metadataClass) {\n if (!tileContent) {\n return null;\n }\n let propertyTable;\n const batchTableJson = tileContent.batchTableJson;\n if (batchTableJson) {\n return batchTableJson;\n }\n const { extensionName, extension } = getPropertyTableExtension(tileContent);\n switch (extensionName) {\n case EXT_STRUCTURAL_METADATA: {\n propertyTable = getPropertyTableFromExtStructuralMetadata(extension, metadataClass);\n return propertyTable;\n }\n case EXT_FEATURE_METADATA: {\n propertyTable = getPropertyTableFromExtFeatureMetadata(extension, metadataClass);\n return propertyTable;\n }\n default:\n return null;\n }\n}\n/**\n * Handles EXT_structural_metadata to get property table.\n * @param extension - Global level of EXT_STRUCTURAL_METADATA extension.\n * @param metadataClass - User selected feature metadata class name.\n * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.\n */\nfunction getPropertyTableFromExtStructuralMetadata(extension, metadataClass) {\n /**\n * Note, 3dTiles is able to have multiple featureId attributes and multiple feature tables.\n * In I3S we should decide which featureIds attribute will be passed to geometry data.\n * So, we take only the feature table / feature texture to generate attributes storage info object.\n * If the user has selected the metadataClass, the table with the corresponding class will be used,\n * or just the first one otherwise.\n */\n if (extension.propertyTables) {\n for (const propertyTable of extension.propertyTables) {\n if (propertyTable.class === metadataClass || !metadataClass) {\n return getPropertyData(propertyTable);\n }\n }\n }\n if (extension.propertyTextures) {\n for (const propertyTexture of extension.propertyTextures) {\n if (propertyTexture.class === metadataClass || !metadataClass) {\n return getPropertyData(propertyTexture);\n }\n }\n }\n return null;\n}\n/**\n * Handles EXT_feature_metadata to get property table.\n * @param extension - Global level of EXT_FEATURE_METADATA extension.\n * @param metadataClass - User selected feature metadata class name.\n * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.\n */\nfunction getPropertyTableFromExtFeatureMetadata(extension, metadataClass) {\n /**\n * Note, 3dTiles is able to have multiple featureId attributes and multiple feature tables.\n * In I3S we should decide which featureIds attribute will be passed to geometry data.\n * So, we take only the feature table / feature texture to generate attributes storage info object.\n * If the user has selected the metadataClass, the table with the corresponding class will be used,\n * or just the first one otherwise.\n */\n if (extension.featureTables) {\n for (const featureTableName in extension.featureTables) {\n const featureTable = extension.featureTables[featureTableName];\n if (featureTable.class === metadataClass || !metadataClass) {\n return getPropertyData(featureTable);\n }\n }\n }\n if (extension.featureTextures) {\n for (const featureTextureName in extension.featureTextures) {\n const featureTexture = extension.featureTextures[featureTextureName];\n if (featureTexture.class === metadataClass || !metadataClass) {\n return getPropertyData(featureTexture);\n }\n }\n }\n return null;\n}\n/**\n * Gets data from Property Table or Property Texture\n * @param featureObject - property table or texture from the extension\n * @returns Table containing property data\n */\nfunction getPropertyData(featureObject) {\n const propertyTableWithData = {};\n for (const propertyName in featureObject.properties) {\n propertyTableWithData[propertyName] = featureObject.properties[propertyName].data;\n }\n return propertyTableWithData;\n}\n/**\n * Check extensions which can be with property table inside.\n * @param tileContent - 3DTiles tile content\n */\nfunction getPropertyTableExtension(tileContent) {\n const extensionsWithPropertyTables = [EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA];\n const extensionsUsed = tileContent?.gltf?.extensionsUsed;\n if (!extensionsUsed) {\n return { extensionName: null, extension: null };\n }\n let extensionName = '';\n for (const extensionItem of tileContent?.gltf?.extensionsUsed || []) {\n if (extensionsWithPropertyTables.includes(extensionItem)) {\n extensionName = extensionItem;\n /*\n It returns the first extension containing the property table.\n We assume that there can be only one extension containing the property table:\n either EXT_FEATURE_METADATA, which is a depricated extension,\n or EXT_STRUCTURAL_METADATA.\n */\n break;\n }\n }\n if (!extensionName) {\n return { extensionName: null, extension: null };\n }\n const extension = tileContent?.gltf?.extensions?.[extensionName];\n return { extensionName, extension };\n}\n", "import { concatenateTypedArrays } from '@loaders.gl/loader-utils';\nconst VALUES_PER_VERTEX = 3;\nconst POSITIONS_AND_NORMALS_PER_TRIANGLE = 9;\n/**\n * Generate geometry attributes with faceRange and featureCount\n * @param attributes\n * @returns attirbutes with featureCount, featureIds and changed faceRange.\n */\nexport function generateAttributes(attributes) {\n const { positions, normals, texCoords, colors, uvRegions, featureIndices } = attributes;\n const triangleCount = positions.length / POSITIONS_AND_NORMALS_PER_TRIANGLE;\n if (!featureIndices.length) {\n return {\n faceRange: new Uint32Array([0, triangleCount - 1]),\n featureIds: [0],\n featureCount: 1,\n positions,\n normals,\n texCoords,\n colors,\n uvRegions\n };\n }\n const data = calculateFaceRangesAndFeaturesCount(featureIndices);\n const attributeObjects = makeAttributeObjects({ ...data, ...attributes });\n const unifiedAttributeObjectsByFeatureIds = unifyObjectsByFeatureId(attributeObjects);\n const groupedAttributes = groupAttributesAndRangesByFeatureId(unifiedAttributeObjectsByFeatureIds, data.featureCount);\n return groupedAttributes;\n}\n/**\n * Calculates face Ranges and feature count based on featureIndices.\n * @param featureIndices\n * @returns Object with featureCount, reordered attributes and changed faceRange.\n */\nfunction calculateFaceRangesAndFeaturesCount(featureIndices) {\n let rangeIndex = 1;\n let featureIndex = 1;\n let currentFeatureId = getFrequentValue(featureIndices.slice(0, VALUES_PER_VERTEX));\n const faceRangeList = [];\n const featureIds = [];\n const uniqueFeatureIds = [currentFeatureId];\n faceRangeList[0] = 0;\n featureIds[0] = currentFeatureId;\n for (let index = VALUES_PER_VERTEX; index < featureIndices.length; index += VALUES_PER_VERTEX) {\n const newFeatureId = getFrequentValue(featureIndices.slice(index, index + VALUES_PER_VERTEX));\n if (currentFeatureId !== newFeatureId) {\n faceRangeList[rangeIndex] = index / VALUES_PER_VERTEX - 1;\n faceRangeList[rangeIndex + 1] = index / VALUES_PER_VERTEX;\n featureIds[featureIndex] = newFeatureId;\n if (!uniqueFeatureIds.includes(newFeatureId)) {\n uniqueFeatureIds.push(newFeatureId);\n }\n rangeIndex += 2;\n featureIndex += 1;\n }\n currentFeatureId = newFeatureId;\n }\n faceRangeList[rangeIndex] = featureIndices.length / VALUES_PER_VERTEX - 1;\n const faceRange = new Uint32Array(faceRangeList);\n const featureCount = uniqueFeatureIds.length;\n return { faceRange, featureCount, featureIds };\n}\n/**\n * Find most frequent value to avoid situation where one vertex can be part of multiple features (objects).\n * @param values\n */\nfunction getFrequentValue(values) {\n const map = {};\n let mostFrequentValue = values[0];\n let maxCount = 1;\n for (const value of values) {\n // Save item and it's frequency count to the map.\n map[value] = (map[value] || 0) + 1;\n // Find max count of frequency.\n maxCount = maxCount > map[value] ? maxCount : map[value];\n // Find the most frequent value.\n mostFrequentValue = maxCount > map[value] ? mostFrequentValue : value;\n }\n return mostFrequentValue;\n}\n/**\n * Generate list of attribute object grouped by feature ids.\n * @param attributes\n * @returns sorted list of attribute objects.\n */\n// eslint-disable-next-line max-statements\nfunction makeAttributeObjects(attributes) {\n const { featureIds, positions, normals, colors, uvRegions, texCoords, faceRange = new Uint32Array(0) } = attributes;\n const groupedData = [];\n const positionsList = new Float32Array(positions);\n const normalsList = new Float32Array(normals);\n const colorsList = new Uint8Array(colors);\n const texCoordsList = new Float32Array(texCoords);\n const uvRegionsList = new Uint16Array(uvRegions);\n let positionsOffset = 0;\n let normalsOffset = 0;\n let colorsOffset = 0;\n let uvRegionsOffset = 0;\n let texCoordsOffset = 0;\n for (let index = 0; index < featureIds.length; index++) {\n const startIndex = faceRange[index * 2];\n const endIndex = faceRange[index * 2 + 1];\n const positionsCount = getSliceAttributeCount('positions', startIndex, endIndex);\n const normalsCount = getSliceAttributeCount('normals', startIndex, endIndex);\n const colorsCount = getSliceAttributeCount('colors', startIndex, endIndex);\n const uvRegionsCount = getSliceAttributeCount('uvRegions', startIndex, endIndex);\n const texCoordsCount = getSliceAttributeCount('texCoords', startIndex, endIndex);\n groupedData.push({\n featureId: featureIds[index],\n positions: positionsList.subarray(positionsOffset, positionsOffset + positionsCount),\n normals: normalsList.subarray(normalsOffset, normalsOffset + normalsCount),\n colors: colorsList.subarray(colorsOffset, colorsOffset + colorsCount),\n uvRegions: uvRegionsList.subarray(uvRegionsOffset, uvRegionsOffset + uvRegionsCount),\n texCoords: texCoordsList.subarray(texCoordsOffset, texCoordsOffset + texCoordsCount)\n });\n positionsOffset += positionsCount;\n normalsOffset += normalsCount;\n colorsOffset += colorsCount;\n uvRegionsOffset += uvRegionsCount;\n texCoordsOffset += texCoordsCount;\n }\n return groupedData;\n}\n/**\n * Generate sliced count for generating attribute objects depends on attribute name and range.\n * @param attributeName\n * @param startIndex\n * @param endIndex\n * @returns sliced count\n */\nfunction getSliceAttributeCount(attributeName, startIndex, endIndex) {\n const itemsPerVertex4 = 4;\n const texCoordsPerVertex = 2;\n const trianglesCount = endIndex - startIndex + 1;\n const vertexCount = trianglesCount * 3;\n switch (attributeName) {\n case 'positions':\n case 'normals':\n return trianglesCount * POSITIONS_AND_NORMALS_PER_TRIANGLE;\n case 'colors':\n case 'uvRegions':\n return vertexCount * itemsPerVertex4;\n case 'texCoords':\n return vertexCount * texCoordsPerVertex;\n default:\n return 0;\n }\n}\n/**\n * Generates unique object list depends on feature ids and concantenate their attributes.\n * @param sortedData\n * @returns unique list of objects\n */\nfunction unifyObjectsByFeatureId(sortedData) {\n const groupedMetadata = [];\n for (const data of sortedData) {\n const existingObject = groupedMetadata.find((obj) => obj.featureId === data.featureId);\n if (existingObject) {\n existingObject.attributes.push(data);\n }\n else {\n groupedMetadata.push({\n featureId: data.featureId,\n attributes: [data]\n });\n }\n }\n const uniqueObjects = [];\n for (const metatada of groupedMetadata) {\n const attributes = concatenateAttributes(metatada.attributes);\n uniqueObjects.push({\n featureId: metatada.featureId,\n ...attributes\n });\n }\n return uniqueObjects;\n}\n/**\n * Generates attribute objects with new faceRange and reordered attributes.\n * @param unifiedObjects\n * @returns generated attributes with new faceRange.\n */\nfunction groupAttributesAndRangesByFeatureId(unifiedObjects, featureCount) {\n const firstAttributeObject = unifiedObjects[0];\n const featureIds = [firstAttributeObject.featureId || 0];\n const range = [0];\n let objIndex = 0;\n let sum = 0;\n for (let index = 1; index < unifiedObjects.length; index++) {\n const currentAttributesObject = unifiedObjects[index];\n featureIds.push(currentAttributesObject.featureId || 0);\n const groupedObject = unifiedObjects[objIndex];\n range.push(groupedObject.positions.length / POSITIONS_AND_NORMALS_PER_TRIANGLE - 1 + sum);\n range.push(groupedObject.positions.length / POSITIONS_AND_NORMALS_PER_TRIANGLE + sum);\n sum += groupedObject.positions.length / POSITIONS_AND_NORMALS_PER_TRIANGLE;\n objIndex += 1;\n }\n const attributes = concatenateAttributes(unifiedObjects);\n range.push(attributes.positions.length / POSITIONS_AND_NORMALS_PER_TRIANGLE - 1);\n const faceRange = new Uint32Array(range);\n return { faceRange, featureIds, featureCount, ...attributes };\n}\n/**\n * Concatenate attributes typed arrays\n * @param attributes - grouped by featureId typed arrays\n * @returns - concatenated typed array list\n */\nfunction concatenateAttributes(attributes) {\n const positionGroups = attributes.map(({ positions }) => positions);\n const positions = positionGroups.length > 1 ? concatenateTypedArrays(...positionGroups) : positionGroups[0];\n const normalGroups = attributes.map(({ normals }) => normals);\n const normals = normalGroups.length > 1 ? concatenateTypedArrays(...normalGroups) : normalGroups[0];\n const colorGroups = attributes.map(({ colors }) => colors);\n const colors = colorGroups.length > 1 ? concatenateTypedArrays(...colorGroups) : colorGroups[0];\n const texCoordGroups = attributes.map(({ texCoords }) => texCoords);\n const texCoords = texCoordGroups.length > 1 ? concatenateTypedArrays(...texCoordGroups) : texCoordGroups[0];\n const uvRegionGroups = attributes.map(({ uvRegions }) => uvRegions);\n const uvRegions = uvRegionGroups.length > 1 ? concatenateTypedArrays(...uvRegionGroups) : uvRegionGroups[0];\n return {\n positions,\n normals,\n colors,\n texCoords,\n uvRegions\n };\n}\n", "import { Matrix3, Quaternion, Vector3 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\nimport { OrientedBoundingBox, makeOrientedBoundingBoxFromPoints, makeBoundingSphereFromPoints, BoundingSphere } from '@math.gl/culling';\n/**\n * Create bounding volumes object from tile and geoid height model.\n * @param sourceBoundingVolume - initialized bounding volume of the source tile\n * @param geoidHeightModel - instance of Geoid class that converts elevation from geoidal to ellipsoidal and back\n * @returns - Bounding volumes object\n */\nexport function createBoundingVolumes(sourceBoundingVolume, geoidHeightModel) {\n let radius;\n let halfSize;\n let quaternion;\n const cartographicCenter = Ellipsoid.WGS84.cartesianToCartographic(sourceBoundingVolume.center, new Vector3());\n cartographicCenter[2] =\n cartographicCenter[2] -\n geoidHeightModel.getHeight(cartographicCenter[1], cartographicCenter[0]);\n if (sourceBoundingVolume instanceof OrientedBoundingBox) {\n halfSize = sourceBoundingVolume.halfSize;\n radius = new Vector3(halfSize[0], halfSize[1], halfSize[2]).len();\n quaternion = sourceBoundingVolume.quaternion;\n }\n else {\n radius = sourceBoundingVolume.radius;\n halfSize = [radius, radius, radius];\n quaternion = new Quaternion()\n .fromMatrix3(new Matrix3([halfSize[0], 0, 0, 0, halfSize[1], 0, 0, 0, halfSize[2]]))\n .normalize();\n }\n return {\n mbs: [cartographicCenter[0], cartographicCenter[1], cartographicCenter[2], radius],\n obb: {\n center: [cartographicCenter[0], cartographicCenter[1], cartographicCenter[2]],\n halfSize,\n quaternion\n }\n };\n}\n/**\n * Generates bounding volumes from geometry positions\n * @param cartesianPositions\n * @param geoidHeightModel\n */\nexport function createBoundingVolumesFromGeometry(cartesianPositions, geoidHeightModel) {\n const positionVectors = convertPositionsToVectors(cartesianPositions);\n const geometryObb = makeOrientedBoundingBoxFromPoints(positionVectors);\n const geometryMbs = makeBoundingSphereFromPoints(positionVectors);\n const mbsCenter = Ellipsoid.WGS84.cartesianToCartographic(geometryMbs.center, new Vector3());\n const obbCenter = Ellipsoid.WGS84.cartesianToCartographic(geometryObb.center, new Vector3());\n mbsCenter[2] = mbsCenter[2] - geoidHeightModel.getHeight(mbsCenter[1], mbsCenter[0]);\n obbCenter[2] = obbCenter[2] - geoidHeightModel.getHeight(obbCenter[1], obbCenter[0]);\n return {\n mbs: [mbsCenter[0], mbsCenter[1], mbsCenter[2], geometryMbs.radius],\n obb: {\n center: obbCenter,\n halfSize: geometryObb.halfSize,\n quaternion: geometryObb.quaternion\n }\n };\n}\n/**\n * Create array of posisitons where each vertex is vector\n * @param {array} positions\n * @returns {Vector3[]}\n */\nexport function convertPositionsToVectors(positions) {\n const result = [];\n for (let i = 0; i < positions.length; i += 3) {\n // TODO: (perf) new Vector3 is not optimal but required in `makeOrientedBoundingBoxFromPoints`.\n // modify `makeOrientedBoundingBoxFromPoints` to use scratch vectors\n const positionVector = new Vector3([positions[i], positions[i + 1], positions[i + 2]]);\n result.push(positionVector);\n }\n return result;\n}\n/**\n * Convert common coordinate to fullExtent https://github.com/Esri/i3s-spec/blob/master/docs/1.8/fullExtent.cmn.md\n * @param boundingVolume\n * @returns - fullExtent object\n */\nexport function convertBoundingVolumeToI3SFullExtent(boundingVolume) {\n let sphere;\n if (boundingVolume instanceof BoundingSphere) {\n sphere = boundingVolume;\n }\n else {\n sphere = boundingVolume.getBoundingSphere();\n }\n const center = sphere.center;\n const radius = sphere.radius;\n const vertexMax = Ellipsoid.WGS84.cartesianToCartographic(new Vector3(center[0] + radius, center[1] + radius, center[2] + radius), new Vector3());\n const vertexMin = Ellipsoid.WGS84.cartesianToCartographic(new Vector3(center[0] - radius, center[1] - radius, center[2] - radius), new Vector3());\n // Converter sometimes returns min values that are bigger then max,\n // so we should check and take bigger value from max and smaller for nim\n return {\n xmin: Math.min(vertexMin[0], vertexMax[0]),\n xmax: Math.max(vertexMin[0], vertexMax[0]),\n ymin: Math.min(vertexMin[1], vertexMax[1]),\n ymax: Math.max(vertexMin[1], vertexMax[1]),\n zmin: Math.min(vertexMin[2], vertexMax[2]),\n zmax: Math.max(vertexMin[2], vertexMax[2])\n };\n}\n/**\n * Creates oriented boundinb box from mbs.\n * @param mbs - Minimum Bounding Sphere\n * @returns - Oriented Bounding Box\n */\nexport function createObbFromMbs(mbs) {\n const radius = mbs[3];\n const center = new Vector3(mbs[0], mbs[1], mbs[2]);\n const halfAxex = new Matrix3([radius, 0, 0, 0, radius, 0, 0, 0, radius]);\n return new OrientedBoundingBox(center, halfAxex);\n}\n", "import { Matrix4, Vector3 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\n/**\n * Prepare attributes for conversion to avoid binary data breaking in worker thread.\n * @param tileContent - 3DTiles tile content\n * @param tileTransform - transformation matrix of the tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n * @param boundingVolume - initialized bounding volume of the source tile\n * @returns 3DTiles content data, prepared for conversion\n */\nexport function prepareDataForAttributesConversion(tileContent, tileTransform, boundingVolume) {\n const nodes = tileContent.gltf?.scene?.nodes ||\n tileContent.gltf?.scenes?.[0]?.nodes ||\n tileContent.gltf?.nodes ||\n [];\n const images = tileContent.gltf?.images?.map((imageObject) => {\n // Need data only for uncompressed images because we can't get batchIds from compressed textures.\n if (imageObject?.image?.compressed) {\n return null;\n }\n const data = imageObject?.image?.data;\n const dataCopy = new Uint8Array(data.length);\n dataCopy.set(data);\n return {\n data: dataCopy,\n compressed: false,\n height: imageObject.image.height,\n width: imageObject.image.width,\n components: imageObject.image.components,\n mimeType: imageObject.mimeType\n };\n }) || [];\n prepareNodes(nodes);\n const { cartographicOrigin, modelMatrix: cartesianModelMatrix } = calculateTransformProps(tileContent, tileTransform, boundingVolume);\n return {\n nodes,\n images,\n cartographicOrigin,\n cartesianModelMatrix\n };\n}\n/**\n * Keep only values for glTF attributes to pass data to worker thread.\n * @param attributes - geometry attributes\n * @returns attributes with only `value` item\n */\nfunction getB3DMAttributesWithoutBufferView(attributes) {\n const attributesWithoutBufferView = {};\n for (const attributeName in attributes) {\n attributesWithoutBufferView[attributeName] = {\n value: attributes[attributeName].value\n };\n }\n return attributesWithoutBufferView;\n}\n/**\n * Calculate transformation properties to transform vertex attributes (POSITION, NORMAL, etc.)\n * from METER_OFFSET coorditantes to LNGLAT_OFFSET coordinates\n * @param tileContent - 3DTiles tile content\n * @param tileTransform - transformation matrix of the tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n * @param boundingVolume - initialized bounding volume of the source tile\n * @returns modelMatrix - transformation matrix to transform coordinates to cartographic coordinates\n * cartographicOrigin - tile origin coordinates to calculate offsets\n */\nexport function calculateTransformProps(tileContent, tileTransform, boundingVolume) {\n const { rtcCenter, gltfUpAxis } = tileContent;\n const { center } = boundingVolume;\n let modelMatrix = new Matrix4(tileTransform);\n // Translate if appropriate\n if (rtcCenter) {\n modelMatrix.translate(rtcCenter);\n }\n // glTF models need to be rotated from Y to Z up\n // https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#y-up-to-z-up\n switch (gltfUpAxis) {\n case 'Z':\n break;\n case 'Y':\n const rotationY = new Matrix4().rotateX(Math.PI / 2);\n modelMatrix = modelMatrix.multiplyRight(rotationY);\n break;\n case 'X':\n const rotationX = new Matrix4().rotateY(-Math.PI / 2);\n modelMatrix = modelMatrix.multiplyRight(rotationX);\n break;\n default:\n break;\n }\n const cartesianOrigin = new Vector3(center);\n const cartographicOrigin = Ellipsoid.WGS84.cartesianToCartographic(cartesianOrigin, new Vector3());\n return { modelMatrix, cartographicOrigin };\n}\n/**\n * Traverse all nodes to replace all sensible data with copy to avoid data corruption in worker.\n * @param nodes\n */\nfunction prepareNodes(nodes) {\n for (let index = 0; index < nodes.length; index++) {\n const node = nodes[index];\n if (node.mesh) {\n nodes[index] = {\n ...node,\n mesh: {\n ...node.mesh,\n primitives: node.mesh?.primitives.map((primitive) => ({\n ...primitive,\n indices: { value: primitive?.indices?.value },\n attributes: getB3DMAttributesWithoutBufferView(primitive.attributes),\n material: {\n id: primitive?.material?.id,\n uniqueId: primitive?.material?.uniqueId\n }\n }))\n }\n };\n }\n if (node.children) {\n prepareNodes(node.children);\n }\n }\n}\n", "import { emod } from '@loaders.gl/math';\nimport { EXT_MESH_FEATURES, EXT_FEATURE_METADATA } from '@loaders.gl/gltf';\n/**\n * Get featureTexture by a metadata class.\n * Metadata classes come from a structural metadata extesion (EXT_feature_metadata or EXT_structural_metadata).\n * The glTF might contain multiple texel-level metadata textures related to different classes. Having only one metadata class\n * selected to convert to I3S, we have to pick only one texture to convert to per-vertex property.\n * @param tileContent - 3d tile content\n * @param metadataClass - user selected feature metadata class name\n * @returns featureTexture key\n */\nexport function getTextureByMetadataClass(tileContent, metadataClass) {\n const extFeatureMetadata = tileContent.gltf?.extensions?.[EXT_FEATURE_METADATA];\n if (!extFeatureMetadata?.featureTextures) {\n return null;\n }\n for (const textureKey in extFeatureMetadata.featureTextures) {\n const texture = extFeatureMetadata.featureTextures[textureKey];\n if (texture.class === metadataClass) {\n return textureKey;\n }\n }\n return null;\n}\n/**\n * Getting batchIds from 3DTilesNext extensions.\n * @param attributes - gltf accessors\n * @param primitive - gltf primitive data\n * @param images - gltf texture images\n * @param featureTexture - feature texture key\n * @return array of batch IDs\n */\nexport function handleBatchIdsExtensions(attributes, primitive, images, featureTexture) {\n const extensions = primitive?.extensions;\n if (!extensions) {\n return [];\n }\n for (const [extensionName, extensionData] of Object.entries(extensions || {})) {\n switch (extensionName) {\n case EXT_FEATURE_METADATA:\n return handleExtFeatureMetadataExtension(attributes, extensionData, images, featureTexture);\n case EXT_MESH_FEATURES:\n return handleExtMeshFeaturesExtension(attributes, extensionData);\n default:\n return [];\n }\n }\n return [];\n}\n/**\n * Getting batchIds from EXT_mesh_features extensions.\n * @param attributes - gltf accessors\n * @param extMeshFeatures - EXT_mesh_features extension\n * @returns an array of attribute values\n */\nfunction handleExtMeshFeaturesExtension(attributes, extMeshFeatures) {\n for (const ids of extMeshFeatures.featureIds) {\n if (typeof ids.propertyTable !== 'undefined') {\n // propertyTable is an index that can be 0\n // return the first featureID set that corresponts to property table.\n return ids.data;\n }\n }\n return [];\n}\n/**\n * Get batchIds from EXT_feature_metadata extension.\n * @see - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata\n * @param attributes - glTF attributes\n * @param extFeatureMetadata - primitive-level EXT_FEATURE_METADATA extension data\n * @param textures - texture images\n * @param featureTexture - feature texture key\n */\nfunction handleExtFeatureMetadataExtension(attributes, extFeatureMetadata, images, featureTexture) {\n // Take only first extension object to get batchIds attribute name.\n const featureIdAttribute = extFeatureMetadata?.featureIdAttributes?.[0];\n if (featureIdAttribute?.featureIds?.attribute) {\n const batchIdsAttribute = attributes[featureIdAttribute.featureIds.attribute];\n return batchIdsAttribute.value;\n }\n if (featureIdAttribute?.featureIds?.hasOwnProperty('constant') &&\n featureIdAttribute?.featureIds?.hasOwnProperty('divisor')) {\n const featuresCount = attributes?.POSITIONS?.value.length / 3 || 0;\n return generateImplicitFeatureIds(featuresCount, featureIdAttribute.featureIds.constant, featureIdAttribute.featureIds.divisor);\n }\n // Take only first extension object to get batchIds attribute name.\n const featureIdTexture = extFeatureMetadata?.featureIdTextures && extFeatureMetadata?.featureIdTextures[0];\n if (featureIdTexture) {\n const textureAttributeIndex = featureIdTexture?.featureIds?.texture?.texCoord || 0;\n const textCoordAttribute = `TEXCOORD_${textureAttributeIndex}`;\n const textureCoordinates = attributes[textCoordAttribute].value;\n return generateBatchIdsFromTexture(featureIdTexture, textureCoordinates, images);\n }\n if (featureTexture) {\n const batchIdsAttribute = attributes[featureTexture];\n return batchIdsAttribute.value;\n }\n return [];\n}\n/**\n * Generates implicit feature ids\n * @see - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#implicit-feature-ids\n * @param featuresCount\n * @param constant\n * @param devisor\n */\nfunction generateImplicitFeatureIds(featuresCount, constant = 0, divisor = 0) {\n let featureIds = [];\n if (divisor > 0) {\n let currentValue = constant;\n let devisorCounter = divisor;\n for (let index = 0; index < featuresCount; index++) {\n featureIds.push(currentValue);\n devisorCounter -= 1;\n if (devisorCounter === 0) {\n currentValue++;\n devisorCounter = divisor;\n }\n }\n }\n else {\n featureIds = Array(featuresCount).fill(constant, 0, featuresCount);\n }\n return featureIds;\n}\n/**\n * Get batchIds from texture.\n * @param primitive\n * @param featureIdTextures\n */\nfunction generateBatchIdsFromTexture(featureIdTexture, textureCoordinates, images) {\n if (!images?.length) {\n return [];\n }\n const CHANNELS_MAP = {\n r: 0,\n g: 1,\n b: 2,\n a: 3\n };\n const textureIndex = featureIdTexture?.featureIds?.texture?.index;\n const featureChannel = featureIdTexture?.featureIds?.channels;\n if (!featureChannel || textureIndex === undefined) {\n return [];\n }\n const image = images[textureIndex];\n const batchIds = [];\n const channels = CHANNELS_MAP[featureChannel];\n if (image && image?.width && image?.height && image?.components) {\n for (let index = 0; index < textureCoordinates.length; index += 2) {\n const u = textureCoordinates[index];\n const v = textureCoordinates[index + 1];\n const tx = Math.min((emod(u) * image.width) | 0, image.width - 1);\n const ty = Math.min((emod(v) * image.height) | 0, image.height - 1);\n const offset = (ty * image.width + tx) * image.components + channels;\n const batchId = new Uint8Array(image.data)[offset];\n batchIds.push(batchId);\n }\n }\n else {\n // eslint-disable-next-line no-console\n console.warn(`Can't get batch Ids from ${image?.mimeType || ''} compressed texture`);\n }\n return batchIds;\n}\n", "import { AttributeType } from \"../types.js\";\nimport { EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA } from '@loaders.gl/gltf';\n/**\n * Takes attributes from property table based on featureIdsMap.\n * If there is no property value for particular featureId (index) the property will be null.\n * Example:\n * Initial data:\n * OBJECTID: {0: 0, 3: 33, 4: 333}\n * component: ['Windows', 'Frames', 'Wall', 'Roof', 'Skylight']\n * Result:\n * OBJECTID: [0, 33, 333]\n * component: ['Windows', 'Roof', 'Skylight']\n * @param featureIdsMap\n * @param propertyTable\n */\nexport function flattenPropertyTableByFeatureIds(featureIdsMap, propertyTable) {\n const resultPropertyTable = {};\n for (const propertyName in propertyTable) {\n const properties = propertyTable[propertyName];\n resultPropertyTable[propertyName] = getPropertiesByFeatureIds(properties, featureIdsMap);\n }\n return resultPropertyTable;\n}\n/**\n * Getting properties by featureId index\n * @param properties\n * @param featureIdsMap\n */\nfunction getPropertiesByFeatureIds(properties, featureIdsMap) {\n const resultProperties = [];\n if (properties) {\n for (const featureIdKey in featureIdsMap) {\n const property = properties[featureIdKey] || null;\n resultProperties.push(property);\n }\n }\n return resultProperties;\n}\n/**\n * Check that all attributes in propertyTable have the same length as FeatureIds.\n * If there are differencies between lengths we should flatten property table based on exiesting featureIds.\n * @param featureIds\n * @param propertyTable\n * @returns\n */\nexport function checkPropertiesLength(featureIds, propertyTable) {\n let needFlatten = false;\n for (const attribute of Object.values(propertyTable)) {\n if (!featureIds || !attribute || featureIds.length !== attribute.length) {\n needFlatten = true;\n }\n }\n return needFlatten;\n}\n/**\n * Get the attribute type for attributeStorageInfo https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md\n * @param attribute - attribute taken from propertyTable\n */\nexport function getAttributeType(attribute) {\n if (typeof attribute === 'string' || typeof attribute === 'bigint') {\n return AttributeType.STRING_TYPE;\n }\n else if (typeof attribute === 'number') {\n return Number.isInteger(attribute) ? AttributeType.SHORT_INT_TYPE : AttributeType.DOUBLE_TYPE;\n }\n return AttributeType.STRING_TYPE;\n}\n/**\n * Gets attribute's types based on the property table records.\n * @param propertyTable - Table with layer meta data.\n * @returns set of attribute types\n * @example of returned object:\n * {\n * \"opt_uint8\": \"Int32\",\n * \"opt_uint64\": \"string\"\n * }\n */\nexport function getAttributeTypesMapFromPropertyTable(propertyTable) {\n const attributeTypesMap = {};\n for (const key in propertyTable) {\n // Get attribute type based on the first element of each property.\n const firstAttribute = propertyTable[key][0];\n const attributeType = getAttributeType(firstAttribute);\n attributeTypesMap[key] = attributeType;\n }\n return attributeTypesMap;\n}\n/**\n * Gets attribute's types from the extension schema selected by the class name 'metadataClass'.\n * @param gltfJson - JSON part of GLB content\n * @param metadataClass - name of the schema class\n * @returns set of attribute's types\n * @example of returned object:\n * {\n * \"opt_uint8\": \"Int32\",\n * \"opt_uint64\": \"string\"\n * }\n */\nexport const getAttributeTypesMapFromSchema = (gltfJson, metadataClass) => {\n const attributeTypesMap = {};\n const extFeatureMetadataSchemaClass = gltfJson.extensions?.[EXT_FEATURE_METADATA]?.schema?.classes?.[metadataClass];\n if (extFeatureMetadataSchemaClass) {\n for (const propertyName in extFeatureMetadataSchemaClass.properties) {\n const property = extFeatureMetadataSchemaClass.properties[propertyName];\n const attributeProperty = getAttributeTypeFromExtFeatureMetadata(property);\n attributeTypesMap[propertyName] = attributeProperty;\n }\n return attributeTypesMap;\n }\n const extStructuralMetadataSchemaClass = gltfJson.extensions?.[EXT_STRUCTURAL_METADATA]?.schema?.classes?.[metadataClass];\n if (extStructuralMetadataSchemaClass) {\n for (const propertyName in extStructuralMetadataSchemaClass.properties) {\n const property = extStructuralMetadataSchemaClass.properties[propertyName];\n const attributeProperty = getAttributeTypeFromExtStructuralMetadata(property);\n attributeTypesMap[propertyName] = attributeProperty;\n }\n return attributeTypesMap;\n }\n return null;\n};\n/**\n * Gets the attribute type according to the Ext_feature_metadata extension class schema\n * @see https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md\n * @param property - schema of the class property for Ext_feature_metadata\n * @returns attribute's type\n */\n// eslint-disable-next-line complexity\nconst getAttributeTypeFromExtFeatureMetadata = (property) => {\n let attributeType;\n switch (property.type) {\n case 'INT8':\n case 'UINT8':\n case 'INT16':\n case 'UINT16':\n case 'INT32':\n case 'UINT32':\n attributeType = AttributeType.SHORT_INT_TYPE;\n break;\n case 'FLOAT32':\n case 'FLOAT64':\n attributeType = AttributeType.DOUBLE_TYPE;\n break;\n case 'INT64':\n case 'UINT64':\n case 'BOOLEAN':\n case 'ENUM':\n case 'STRING':\n case 'ARRAY':\n attributeType = AttributeType.STRING_TYPE;\n break;\n default:\n attributeType = AttributeType.STRING_TYPE;\n break;\n }\n return attributeType;\n};\n/**\n * Gets the attribute type according to the Ext_structural_metadata extension class schema\n * @see https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md\n * @param property - schema of the class property for Ext_structural_metadata\n * @returns attribute's type\n */\n// eslint-disable-next-line complexity\nconst getAttributeTypeFromExtStructuralMetadata = (property) => {\n let attributeType;\n if (property.array) {\n attributeType = AttributeType.STRING_TYPE;\n }\n else {\n switch (property.componentType) {\n case 'INT8':\n case 'UINT8':\n case 'INT16':\n case 'UINT16':\n case 'INT32':\n case 'UINT32':\n attributeType = AttributeType.SHORT_INT_TYPE;\n break;\n case 'FLOAT32':\n case 'FLOAT64':\n attributeType = AttributeType.DOUBLE_TYPE;\n break;\n case 'INT64':\n case 'UINT64':\n attributeType = AttributeType.STRING_TYPE;\n break;\n default:\n attributeType = AttributeType.STRING_TYPE;\n break;\n }\n }\n return attributeType;\n};\n", "/**\n * luma.gl can not work without indices now:\n * https://github.com/visgl/luma.gl/blob/d8cad75b9f8ca3e578cf078ed9d19e619c2ddbc9/modules/experimental/src/gltf/gltf-instantiator.js#L115\n * This method generates syntetic indices array: [0, 1, 2, 3, .... , vertexCount-1]\n * @param {number} vertexCount - vertex count in the geometry\n * @returns {Uint32Array} indices array.\n */\nexport const generateSyntheticIndices = (vertexCount) => {\n const result = new Uint32Array(vertexCount);\n for (let index = 0; index < vertexCount; index++) {\n result[index] = index;\n }\n return result;\n};\n", "import { v4 as uuidv4 } from 'uuid';\nimport transform from 'json-map-transform';\nimport { join } from 'path';\nimport { SCENE_SERVER as sceneServerTemplate } from \"../json-templates/scene-server.js\";\nimport { writeFile } from \"../../lib/utils/file-utils.js\";\n/**\n * Form and save sceneServer meta data into a file\n * @param layerName - layer name to display\n * @param layers0 - layer object embedded into sceneServer meta data\n * @param rootPath - root path of new converted tileset\n */\nexport async function createSceneServerPath(layerName, layers0, rootPath) {\n const sceneServerData = {\n serviceItemId: uuidv4().replace(/-/gi, ''),\n layerName,\n layers0\n };\n const sceneServer = transform(sceneServerData, sceneServerTemplate());\n const nodePagePath = join(rootPath, 'SceneServer');\n await writeFile(nodePagePath, JSON.stringify(sceneServer));\n}\n", "export const SCENE_SERVER = () => ({\n serviceItemId: {\n path: 'serviceItemId'\n },\n serviceName: {\n path: 'layerName'\n },\n name: {\n path: 'layerName'\n },\n currentVersion: {\n path: 'currentVersion',\n default: 10.7\n },\n serviceVersion: {\n path: 'serviceVersion',\n default: '1.8'\n },\n supportedBindings: {\n path: 'supportedBindings',\n default: ['REST']\n },\n layers: {\n path: 'layers0',\n transform: (layers0) => [layers0]\n }\n});\n", "// https://cesium.com/docs/cesiumjs-ref-doc/Cesium3DTileset.html\nconst DEFAULT_MAXIMUM_SCREEN_SPACE_ERROR = 16;\n/**\n * Do conversion from geometric error to screen threshold\n *\n * In 3DTiles we have HLOD logic and parent tile also has bigger lodMetric value then its children.\n * In I3s we have reverse logic related to maxError. Parent has lower maxError than its child.\n * In nodes where are no children tile.lodMetricValue is 0. This is because of logic of HLOD in 3DTiles\n * 3DTiles spec:\n * https://github.com/CesiumGS/3d-tiles/tree/master/specification#geometric-error\n * I3S spec:\n * https://github.com/Esri/i3s-spec/blob/master/docs/1.7/lodSelection.cmn.md\n * To avoid infinity values when we do calculations of maxError we shold replace 0 with value which allows us\n * to make child maxError bigger than his parent maxError.\n *\n * @param tile - 3d-tiles tile JSON\n * @param coordinates - node converted coordinates\n * @returns An array of LOD metrics in format compatible with i3s 3DNodeIndexDocument.lodSelection\n * @example\n * [\n {\n \"metricType\": \"maxScreenThresholdSQ\",\n \"maxError\": 870638.071285568\n },\n {\n \"metricType\": \"maxScreenThreshold\",\n \"maxError\": 1052.8679031638949\n }\n ]\n */\nexport function convertGeometricErrorToScreenThreshold(tile, coordinates) {\n const lodSelection = [];\n const boundingVolume = tile.boundingVolume;\n const lodMetricValue = tile.lodMetricValue || 0.1;\n const maxScreenThreshold = {\n metricType: 'maxScreenThreshold',\n maxError: (coordinates.mbs[3] * 2 * DEFAULT_MAXIMUM_SCREEN_SPACE_ERROR) / lodMetricValue\n };\n const maxScreenThresholdSQ = {\n metricType: 'maxScreenThresholdSQ',\n maxError: Math.PI * 0.25 * maxScreenThreshold.maxError * maxScreenThreshold.maxError\n };\n if (boundingVolume.constructor.name === 'OrientedBoundingBox') {\n lodSelection.push(maxScreenThresholdSQ);\n lodSelection.push(maxScreenThreshold);\n }\n else {\n lodSelection.push(maxScreenThreshold);\n lodSelection.push(maxScreenThresholdSQ);\n }\n return lodSelection;\n}\n/**\n * Convert LOD metric from \"Screen Threshold\" to \"Screen Space Error\"\n * @param node - i3s node data\n * @returns lod metric in 3d-tiles format\n */\nexport function convertScreenThresholdToGeometricError(node) {\n const metricData = node.lodSelection?.find((metric) => metric.metricType === 'maxScreenThreshold');\n let maxError = metricData?.maxError;\n if (!maxError) {\n const sqMetricData = node.lodSelection?.find((metric) => metric.metricType === 'maxScreenThresholdSQ');\n if (sqMetricData) {\n maxError = Math.sqrt(sqMetricData.maxError / (Math.PI * 0.25));\n }\n }\n if (!maxError) {\n maxError = DEFAULT_MAXIMUM_SCREEN_SPACE_ERROR;\n }\n return (node.mbs[3] * 2 * DEFAULT_MAXIMUM_SCREEN_SPACE_ERROR) / maxError;\n}\n", "import { Geoid, parsePGM } from '@math.gl/geoid';\n// __VERSION__ is injected by babel-plugin-version-inline\n// @ts-ignore TS2304: Cannot find name '__VERSION__'.\nconst VERSION = typeof \"4.2.0-beta.1\" !== 'undefined' ? \"4.2.0-beta.1\" : 'latest';\nexport { Geoid };\n/**\n * Loader for PGM - Netpbm grayscale image format\n */\nexport const PGMLoader = {\n dataType: null,\n batchType: null,\n name: 'PGM - Netpbm grayscale image format',\n id: 'pgm',\n module: 'tile-converter',\n version: VERSION,\n mimeTypes: ['image/x-portable-graymap'],\n parse: async (arrayBuffer, options) => parsePGM(new Uint8Array(arrayBuffer), options?.pgm || {}),\n extensions: ['pgm'],\n options: {\n pgm: {\n cubic: false\n }\n }\n};\n", "import transform from 'json-map-transform';\nimport { STORE } from \"./store.js\";\nconst SPATIAL_REFERENCE = () => ({\n wkid: {\n path: 'wkid',\n default: 4326\n },\n latestWkid: {\n path: 'latestWkid',\n default: 4326\n },\n vcsWkid: {\n path: 'vcsWkid',\n default: 5773\n },\n latestVcsWkid: {\n path: 'latestVcsWkid',\n default: 5773\n }\n});\nconst HEIGHT_MODEL_INFO = () => ({\n heightModel: {\n path: 'heightModel',\n default: 'gravity_related_height'\n },\n vertCRS: {\n path: 'vertCRS',\n default: 'EGM96_Geoid'\n },\n heightUnit: {\n path: 'heightUnit',\n default: 'meter'\n }\n});\nconst NODE_PAGES = () => ({\n nodesPerPage: {\n path: 'nodesPerPage'\n },\n lodSelectionMetricType: {\n path: 'lodSelectionMetricType',\n default: 'maxScreenThresholdSQ'\n }\n});\nconst FULL_EXTENT = () => ({\n xmin: {\n path: 'xmin'\n },\n ymin: {\n path: 'ymin'\n },\n xmax: {\n path: 'xmax'\n },\n ymax: {\n path: 'ymax'\n },\n zmin: {\n path: 'zmin'\n },\n zmax: {\n path: 'zmax'\n }\n});\nexport const LAYERS = () => ({\n version: {\n path: 'version',\n transform: (val) => val.toUpperCase()\n },\n id: {\n path: 'id',\n default: 0\n },\n name: {\n path: 'name'\n },\n href: {\n path: 'href',\n default: './layers/0'\n },\n layerType: {\n path: 'layerType',\n default: 'IntegratedMesh'\n },\n spatialReference: {\n path: 'spatialReference',\n transform: (val) => transform(val, SPATIAL_REFERENCE())\n },\n capabilities: {\n path: 'capabilities',\n default: ['View', 'Query']\n },\n store: {\n path: 'store',\n transform: (val) => transform(val, STORE)\n },\n fullExtent: {\n path: 'fullExtent',\n transform: (val) => transform(val, FULL_EXTENT())\n },\n heightModelInfo: {\n path: 'heightModelInfo',\n transform: (val) => transform(val, HEIGHT_MODEL_INFO())\n },\n nodePages: {\n path: 'nodePages',\n transform: (val) => transform(val, NODE_PAGES())\n },\n materialDefinitions: {\n path: 'materialDefinitions',\n default: []\n },\n textureSetDefinitions: {\n path: 'textureSetDefinitions',\n default: []\n },\n geometryDefinitions: {\n path: 'geometryDefinitions',\n default: []\n },\n attributeStorageInfo: {\n path: 'attributeStorageInfo',\n default: []\n },\n fields: {\n path: 'fields',\n default: []\n },\n popupInfo: {\n path: 'popupInfo',\n default: null\n }\n});\n", "export const STORE = {\n id: {\n path: 'id',\n transform: (val) => val.toUpperCase()\n },\n profile: {\n path: 'profile',\n default: 'meshpyramids'\n },\n version: {\n path: 'version',\n default: '1.8'\n },\n resourcePattern: {\n path: 'resourcePattern',\n default: ['3dNodeIndexDocument', 'Attributes', 'SharedResource', 'Geometry']\n },\n rootNode: {\n path: 'rootNode',\n default: './nodes/root'\n },\n extent: {\n path: 'extent'\n },\n indexCRS: {\n path: 'indexCRS',\n default: 'http://www.opengis.net/def/crs/EPSG/0/4326'\n },\n vertexCRS: {\n path: 'vertexCRS',\n default: 'http://www.opengis.net/def/crs/EPSG/0/4326'\n },\n normalReferenceFrame: {\n path: 'normalReferenceFrame',\n default: 'east-north-up'\n },\n attributeEncoding: {\n path: 'attributeEncoding',\n default: 'application/octet-stream; version=1.6'\n },\n textureEncoding: {\n path: 'textureEncoding',\n default: ['image/jpeg', 'image/ktx2']\n },\n lodType: {\n path: 'lodType',\n default: 'MeshPyramid'\n },\n lodModel: {\n path: 'lodModel',\n default: 'node-switching'\n },\n defaultGeometrySchema: {\n path: 'defaultGeometrySchema',\n default: {\n geometryType: 'triangles',\n header: [\n {\n property: 'vertexCount',\n type: 'UInt32'\n },\n {\n property: 'featureCount',\n type: 'UInt32'\n }\n ],\n topology: 'PerAttributeArray',\n ordering: ['position', 'normal', 'uv0', 'color'],\n vertexAttributes: {\n position: {\n valueType: 'Float32',\n valuesPerElement: 3\n },\n normal: {\n valueType: 'Float32',\n valuesPerElement: 3\n },\n uv0: {\n valueType: 'Float32',\n valuesPerElement: 2\n },\n color: {\n valueType: 'UInt8',\n valuesPerElement: 4\n }\n },\n featureAttributeOrder: ['id', 'faceRange'],\n featureAttributes: {\n id: {\n valueType: 'UInt64',\n valuesPerElement: 1\n },\n faceRange: {\n valueType: 'UInt32',\n valuesPerElement: 2\n }\n }\n }\n }\n};\n", "import transform from 'json-map-transform';\nconst PLAIN_GEOMETRY_DEFINITION = () => ({\n offset: {\n default: 8\n },\n position: {\n default: {\n type: 'Float32',\n component: 3\n }\n },\n normal: {\n default: {\n type: 'Float32',\n component: 3\n }\n },\n uv0: {\n path: 'hasTexture',\n transform: (val) => (val && { type: 'Float32', component: 2 }) || false,\n omitValues: [false]\n },\n color: {\n default: {\n type: 'UInt8',\n component: 4\n }\n },\n uvRegion: {\n path: 'hasUvRegions',\n transform: (val) => (val && { type: 'UInt16', component: 4 }) || false,\n omitValues: [false]\n },\n featureId: {\n default: {\n binding: 'per-feature',\n type: 'UInt64',\n component: 1\n }\n },\n faceRange: {\n default: {\n binding: 'per-feature',\n type: 'UInt32',\n component: 2\n }\n }\n});\nconst COMPRESSED_GEOMETRY_DEFINITION = () => ({\n 'compressedAttributes.encoding': {\n default: 'draco'\n },\n 'compressedAttributes.attributes': {\n path: 'geometryConfig',\n transform: (val) => {\n const result = ['position', 'normal'];\n if (val.hasTexture) {\n result.push('uv0');\n }\n result.push('color');\n if (val.hasUvRegions) {\n result.push('uv-region');\n }\n result.push('feature-index');\n return result;\n }\n }\n});\nexport const GEOMETRY_DEFINITION = () => ({\n geometryBuffers: {\n path: 'geometryConfig',\n transform: (val) => {\n const result = [transform(val, PLAIN_GEOMETRY_DEFINITION())];\n if (val.draco) {\n result.push(transform({ geometryConfig: val }, COMPRESSED_GEOMETRY_DEFINITION()));\n }\n return result;\n }\n }\n});\n", "import transform from 'json-map-transform';\nconst MATERIAL_DEFINITION_INFO_PARAMS = () => ({\n renderMode: {\n path: 'renderMode',\n default: 'solid'\n },\n shininess: {\n path: 'shininess',\n default: 1\n },\n reflectivity: {\n path: 'reflectivity',\n default: 0\n },\n ambient: {\n path: 'ambient',\n default: [1, 1, 1]\n },\n diffuse: {\n path: 'diffuse',\n default: [1, 1, 1]\n },\n specular: {\n path: 'specular',\n default: [0, 0, 0]\n },\n useVertexColorAlpha: {\n path: 'useVertexColorAlpha',\n default: false\n },\n vertexRegions: {\n path: 'vertexRegions',\n default: false\n },\n vertexColors: {\n path: 'vertexColors',\n default: true\n }\n});\nconst MATERIAL_DEFINITION_INFO = () => ({\n name: {\n path: 'name',\n default: 'standard'\n },\n type: {\n path: 'type',\n default: 'standard'\n },\n params: {\n path: 'params',\n transform: (val, thisObject, originalObject) => transform(originalObject, MATERIAL_DEFINITION_INFO_PARAMS())\n }\n});\nconst TEXTURE_DEFINITION_IMAGE = () => ({\n id: {\n path: 'id'\n },\n size: {\n path: 'size'\n },\n href: {\n path: 'href',\n default: ['../textures/0']\n },\n length: {\n path: 'length'\n }\n});\nconst TEXTURE_DEFINITION_INFO = () => ({\n encoding: {\n path: 'encoding'\n },\n wrap: {\n path: 'wrap',\n default: ['none']\n },\n atlas: {\n path: 'atlas',\n default: false\n },\n uvSet: {\n path: 'uvSet',\n default: 'uv0'\n },\n channels: {\n path: 'channels',\n default: 'rgb'\n },\n images: {\n path: 'images',\n transform: (val, thisObject, originalObject) => val.map((image) => transform(image, TEXTURE_DEFINITION_IMAGE()))\n }\n});\nexport const SHARED_RESOURCES = () => ({\n materialDefinitions: {\n path: 'materialDefinitionInfos',\n transform: transfromMaterialDefinitions\n },\n textureDefinitions: {\n path: 'textureDefinitionInfos',\n transform: transfromTextureDefinitions\n }\n});\nfunction transfromMaterialDefinitions(materialDefinitionInfos, thisObject, originalObject) {\n const result = {};\n for (const [index, materialDefinitionInfo] of materialDefinitionInfos.entries()) {\n result[`Mat${originalObject.nodePath}${index}`] = transform(materialDefinitionInfo, MATERIAL_DEFINITION_INFO());\n }\n return result;\n}\nfunction transfromTextureDefinitions(textureDefinitionInfos, thisObject, originalObject) {\n if (!textureDefinitionInfos) {\n return null;\n }\n const result = {};\n for (const [index, textureDefinitionInfo] of textureDefinitionInfos.entries()) {\n const imageIndex = `${originalObject.nodePath}${index}`;\n textureDefinitionInfo.imageIndex = imageIndex;\n result[imageIndex] = transform(textureDefinitionInfo, TEXTURE_DEFINITION_INFO());\n }\n return result;\n}\n", "import { OrientedBoundingBox, BoundingSphere } from '@math.gl/culling';\nimport { Vector3 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\n// prettier-ignore\nconst CUBE_POSITIONS = new Float32Array([\n -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1,\n -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1,\n -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1,\n -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1,\n 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1,\n -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1\n]);\n// TODO Unite Tile validation logic in i3s-17-and-debug with this code.\n/**\n * Do validation of bounding volumes for particular node.\n * Generates special warnings if there are some issues.\n * @param node\n */\nexport function validateNodeBoundingVolumes(node) {\n if (!node?.parentNode?.obb || !node?.parentNode?.mbs) {\n return [];\n }\n const tileWarnings = [];\n validateObb(tileWarnings, node);\n validateMbs(tileWarnings, node);\n return tileWarnings;\n}\n/**\n * Check if child Obb fit into parent Obb.\n * @param tileWarnings\n * @param node\n */\nfunction validateObb(tileWarnings, node) {\n // @ts-expect-error\n const parentObb = createBoundingBoxFromTileObb(node.parentNode.obb);\n const tileVertices = getTileObbVertices(node);\n const isTileObbInsideParentObb = isAllVerticesInsideBoundingVolume(parentObb, tileVertices);\n if (isTileObbInsideParentObb) {\n return;\n }\n const title = `OBB of Tile (${node.id}) doesn't fit into Parent (${node.parentNode?.id}) tile OBB`;\n tileWarnings.push(title);\n}\n/**\n * Check if child Mbs fit into parent Mbs.\n * @param tileWarnings\n * @param node\n */\nfunction validateMbs(tileWarnings, node) {\n // @ts-expect-error\n const tileMbs = createBoundingSphereFromTileMbs(node.mbs);\n // @ts-expect-error\n const parentMbs = createBoundingSphereFromTileMbs(node.parentNode.mbs);\n const distanceBetweenCenters = tileMbs.center.distanceTo(parentMbs.center);\n if (distanceBetweenCenters + tileMbs.radius > parentMbs.radius) {\n const title = `MBS of Tile (${node.id}) doesn't fit into Parent (${node.parentNode?.id}) tile MBS`;\n tileWarnings.push(title);\n }\n}\n/**\n * Generates bounding sphere from mbs\n * @param mbs\n */\nfunction createBoundingSphereFromTileMbs(mbs) {\n return new BoundingSphere([mbs[0], mbs[1], mbs[2]], mbs[3]);\n}\n/**\n * Generates oriented bounding box from tile obb\n * @param obb\n * @returns\n */\nfunction createBoundingBoxFromTileObb(obb) {\n const { center, halfSize, quaternion } = obb;\n return new OrientedBoundingBox().fromCenterHalfSizeQuaternion(center, halfSize, quaternion);\n}\n/**\n * Get vertices fromnode obb\n * TODO check if Obb generates properly\n * @param node\n */\nfunction getTileObbVertices(node) {\n // @ts-expect-error\n const halfSize = node.obb.halfSize;\n const positions = CUBE_POSITIONS;\n // @ts-expect-error\n const obbCenterCartesian = Ellipsoid.WGS84.cartographicToCartesian(node.obb.center);\n let vertices = [];\n for (let i = 0; i < positions.length; i += 3) {\n const positionsVector = new Vector3((positions[i] *= halfSize[0]), (positions[i + 1] *= halfSize[1]), (positions[i + 2] *= halfSize[2]));\n const rotatedPositions = positionsVector\n // @ts-expect-error\n .transformByQuaternion(node.obb.quaternion)\n .add(obbCenterCartesian);\n // @ts-expect-error\n vertices = vertices.concat(rotatedPositions);\n }\n return vertices;\n}\n/**\n * Check if all vertices inside bounding volume\n * @param boundingVolume\n * @param positions\n */\nfunction isAllVerticesInsideBoundingVolume(boundingVolume, positions) {\n let isVerticesInsideObb = true;\n for (let index = 0; index < positions.length / 3; index += 3) {\n const point = [positions[index], positions[index + 1], positions[index + 2]];\n const cartographicPoint = Ellipsoid.WGS84.cartesianToCartographic(point);\n const distance = boundingVolume.distanceTo(cartographicPoint);\n if (distance > 0) {\n isVerticesInsideObb = false;\n break;\n }\n }\n return isVerticesInsideObb;\n}\n", "export class Queue extends Array {\n enqueue(val) {\n this.push(val);\n }\n dequeue() {\n return this.shift();\n }\n peek() {\n return this[0];\n }\n isEmpty() {\n return this.length === 0;\n }\n}\n", "import { Queue } from \"./queue.js\";\nimport process from 'process';\n/** Memory limit size is based on testing */\nconst MEMORY_LIMIT = 4 * 1024 * 1024 * 1024; // 4GB\nexport default class WriteQueue extends Queue {\n intervalId; // eslint-disable-line no-undef\n conversionDump;\n writePromise = null;\n fileMap = {};\n listeningInterval;\n writeConcurrency;\n constructor(conversionDump, listeningInterval = 2000, writeConcurrency = 400) {\n super();\n this.conversionDump = conversionDump;\n this.listeningInterval = listeningInterval;\n this.writeConcurrency = writeConcurrency;\n }\n async enqueue(val, writeImmediately = false) {\n if (writeImmediately) {\n const { archiveKey, writePromise } = val;\n const result = await writePromise();\n if (archiveKey && result) {\n this.fileMap[archiveKey] = result;\n }\n }\n else {\n super.enqueue(val);\n /** https://nodejs.org/docs/latest-v14.x/api/process.html#process_process_memoryusage */\n if (process.memoryUsage().rss > MEMORY_LIMIT) {\n await this.startWrite();\n }\n }\n }\n startListening() {\n this.intervalId = setInterval(() => this.startWrite.bind(this), this.listeningInterval);\n }\n stopListening() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n async startWrite() {\n if (!this.writePromise) {\n this.writePromise = this.doWrite();\n }\n await this.writePromise;\n this.writePromise = null;\n }\n async finalize() {\n this.stopListening();\n await this.startWrite();\n }\n async doWrite() {\n while (this.length) {\n const promises = [];\n const archiveKeys = [];\n const changedRecords = [];\n for (let i = 0; i < this.writeConcurrency; i++) {\n const item = this.dequeue();\n if (!item) {\n break;\n }\n const { archiveKey, sourceId, outputId, resourceType, writePromise } = item;\n archiveKeys.push(archiveKey);\n changedRecords.push({ sourceId, outputId, resourceType });\n const promise = writePromise();\n promises.push(promise);\n }\n const writeResults = await Promise.allSettled(promises);\n this.updateFileMap(archiveKeys, writeResults);\n await this.conversionDump.updateConvertedTilesDump(changedRecords, writeResults);\n }\n }\n updateFileMap(archiveKeys, writeResults) {\n for (let i = 0; i < archiveKeys.length; i++) {\n const archiveKey = archiveKeys[i];\n if (archiveKey && 'value' in writeResults[i]) {\n this.fileMap[archiveKey] = writeResults[i].value;\n }\n }\n }\n}\n", "export const BROWSER_ERROR_MESSAGE = 'Tile converter does not work in browser, only in node js environment';\nexport const DUMP_FILE_SUFFIX = '.dump.json';\n", "import { join } from 'path';\nimport transform from 'json-map-transform';\nimport { v4 as uuidv4 } from 'uuid';\nimport { openJson, writeFile, writeFileForSlpk } from \"../../lib/utils/file-utils.js\";\nimport { NODE as nodeTemplate } from \"../json-templates/node.js\";\n/**\n * Wrapper for https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md data\n * The class allows working with 3DNodeIndexDocument in 2 modes:\n * in memory: the data is stored in `data` field\n * on disk: the data is written on disk in a file. The file can be rewritten when new childrend or neighbors have to be added\n */\nexport class NodeIndexDocument {\n /** Node id */\n id;\n /** Id in node pages */\n inPageId;\n /** 3DNodeIndexDocument data */\n data = null;\n /** children */\n children = [];\n /** converter instance */\n converter;\n /**\n * Finalized property. It means that all child nodes are saved and their data\n * is unloaded\n */\n _finalized = false;\n get finalized() {\n return this._finalized;\n }\n /**\n * Constructor\n * @param id - id of the node in node pages\n * @param converter - converter instance\n */\n constructor(id, converter) {\n this.inPageId = id;\n this.id = id === 0 ? 'root' : id.toString();\n this.converter = converter;\n }\n /**\n * Add Node3DIndexDocument data to the node\n * @param data Node3DIndexDocument data\n * @returns this NodeIndexDocument instance (to recurring with constructor)\n */\n async addData(data) {\n if (this.converter.options.instantNodeWriting) {\n await this.write(data);\n }\n else {\n this.data = data;\n }\n return this;\n }\n /**\n * Add child node references\n * @param childNodes - child NodeIndexDocument instances\n */\n async addChildren(childNodes) {\n const newChildren = [];\n for (const node of childNodes) {\n const nodeData = await node.load();\n newChildren.push({\n id: node.id,\n href: `../${node.id}`,\n obb: nodeData.obb,\n mbs: nodeData.mbs\n });\n }\n this.children = this.children.concat(childNodes);\n let data = this.data;\n if (this.converter.options.instantNodeWriting) {\n data = await this.load();\n }\n if (data) {\n data.children = data.children ?? [];\n data.children = data.children.concat(newChildren);\n }\n if (this.converter.options.instantNodeWriting && data) {\n await this.write(data);\n }\n }\n /**\n * Add neighbors to child nodes of this node\n */\n async addNeighbors() {\n if (this.finalized) {\n return;\n }\n const nodeData = await this.load();\n for (const childNode of this.children) {\n const childNodeData = await childNode.load();\n childNodeData.neighbors = childNodeData.neighbors ?? [];\n // Don't do large amount of \"neightbors\" to avoid big memory consumption\n if (Number(nodeData?.children?.length) < 1000) {\n for (const neighbor of nodeData.children || []) {\n if (childNode.id === neighbor.id) {\n continue; // eslint-disable-line\n }\n childNodeData.neighbors.push({ ...neighbor });\n }\n }\n else {\n // eslint-disable-next-line no-console, no-undef\n console.warn(`Node ${childNode.id}: neighbors attribute is omited because of large number of neigbors`);\n delete childNodeData.neighbors;\n }\n if (this.converter.options.instantNodeWriting && childNodeData) {\n await childNode.write(childNodeData);\n }\n await childNode.save();\n }\n // The save after adding neighbors is the last one. Finalize the the node\n this.finalize();\n }\n /** Save 3DNodeIndexDocument in file on disk */\n async save() {\n if (this.data) {\n await this.write(this.data);\n }\n }\n /** Finalize the node */\n finalize() {\n this._finalized = true;\n for (const child of this.children) {\n child.flush();\n }\n }\n /**\n * Write 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md\n * @param node - Node3DIndexDocument object\n */\n async write(node) {\n const path = join(this.converter.layers0Path, 'nodes', this.id);\n if (this.converter.options.slpk) {\n await this.converter.writeQueue.enqueue({\n archiveKey: `nodes/${this.id}/3dNodeIndexDocument.json.gz`,\n writePromise: () => writeFileForSlpk(path, JSON.stringify(node), '3dNodeIndexDocument.json', true, this.converter.compressList)\n }, true);\n }\n else {\n await this.converter.writeQueue.enqueue({ writePromise: () => writeFile(path, JSON.stringify(node)) }, true);\n }\n }\n /**\n * Load 3DNodeIndexDocument data from file on disk\n * @returns 3DNodeIndexDocument object\n */\n async load() {\n if (this.data) {\n return this.data;\n }\n const path = this.id;\n const parentNodePath = join(this.converter.layers0Path, 'nodes', path);\n let parentNodeFileName = 'index.json';\n if (this.converter.options.slpk) {\n parentNodeFileName = '3dNodeIndexDocument.json';\n }\n return (await openJson(parentNodePath, parentNodeFileName));\n }\n /**\n * Unload the Node data\n */\n flush() {\n this.data = null;\n }\n /**\n * Create root node of the tree\n * @param boundingVolumes - MBS and OOB bounding volumes data\n * @param converter - I3SConverter instance\n * @returns instance of NodeIndexDocument\n */\n static async createRootNode(boundingVolumes, converter) {\n const rootData = NodeIndexDocument.createRootNodeIndexDocument(boundingVolumes);\n const rootNode = await new NodeIndexDocument(0, converter).addData(rootData);\n return rootNode;\n }\n /**\n * Create NodeIndexDocument instance\n * @param parentNode - parent NodeIndexDocument\n * @param boundingVolumes - MBS and OOB bounding volumes data\n * @param lodSelection - LOD metrics data\n * @param nodeInPage - node data in node pages\n * @param resources - resources extracted from gltf/b3dm file\n * @param converter - I3SConverter instance\n * @returns NodeIndexDocument instance\n */\n static async createNode({ parentNode, boundingVolumes, lodSelection, nodeInPage, resources, converter }) {\n const data = await NodeIndexDocument.createNodeIndexDocument(parentNode, boundingVolumes, lodSelection, nodeInPage, resources);\n const node = await new NodeIndexDocument(nodeInPage.index, converter).addData(data);\n return node;\n }\n /**\n * Form 3DNodeIndexDocument data for the root node\n * @param boundingVolumes - mbs and obb data about node's bounding volume\n * @return 3DNodeIndexDocument data https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md\n */\n static createRootNodeIndexDocument(boundingVolumes) {\n const root0data = {\n version: `{${uuidv4().toUpperCase()}}`,\n id: 'root',\n level: 0,\n lodSelection: [\n {\n metricType: 'maxScreenThresholdSQ',\n maxError: 0\n },\n {\n metricType: 'maxScreenThreshold',\n maxError: 0\n }\n ],\n ...boundingVolumes,\n children: []\n };\n return transform(root0data, nodeTemplate());\n }\n /**\n * Create a new Node3DIndexDocument\n * @param parentNode - 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md object of the parent node\n * @param boundingVolumes - Bounding volumes\n * @param lodSelection - Level of Details (LOD) metrics\n * @param nodeInPage - corresponding node object in a node page\n * @param resources - the node resources data\n * @param resources.texture - texture image\n * @param resources.attributes - feature attributes\n * @return 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md object\n */\n // eslint-disable-next-line complexity\n static async createNodeIndexDocument(parentNode, boundingVolumes, lodSelection, nodeInPage, resources) {\n const nodeId = nodeInPage.index;\n const parentNodeData = await parentNode.load();\n const nodeData = {\n version: parentNodeData.version,\n id: nodeId.toString(),\n level: parentNodeData.level + 1,\n ...boundingVolumes,\n lodSelection,\n parentNode: {\n id: parentNode.id,\n href: `../${parentNode.id}`,\n mbs: parentNodeData.mbs,\n obb: parentNodeData.obb\n },\n children: [],\n neighbors: []\n };\n const node = transform(nodeData, nodeTemplate());\n if (nodeInPage.mesh) {\n node.geometryData = [{ href: './geometries/0' }];\n node.sharedResource = { href: './shared' };\n if (('texture' in resources && resources.texture) ||\n ('texelCountHint' in resources && resources.texelCountHint)) {\n node.textureData = [{ href: './textures/0' }, { href: './textures/1' }];\n }\n if (('attributes' in resources &&\n resources.attributes &&\n resources.attributes.length &&\n parentNode.converter.layers0?.attributeStorageInfo?.length) ||\n ('attributesCount' in resources &&\n resources.attributesCount &&\n parentNode.converter.layers0?.attributeStorageInfo?.length)) {\n const attributesLength = ('attributes' in resources ? resources.attributes?.length : resources.attributesCount) ||\n 0;\n node.attributeData = [];\n const minimumLength = attributesLength < parentNode.converter.layers0.attributeStorageInfo.length\n ? attributesLength\n : parentNode.converter.layers0.attributeStorageInfo.length;\n for (let index = 0; index < minimumLength; index++) {\n const folderName = parentNode.converter.layers0.attributeStorageInfo[index].key;\n node.attributeData.push({ href: `./attributes/${folderName}/0` });\n }\n }\n }\n return node;\n }\n}\n", "import transform from 'json-map-transform';\nconst COORDINATES = () => ({\n mbs: {\n path: 'mbs'\n },\n obb: {\n path: 'obb'\n }\n});\nconst HREF = () => ({\n href: {\n path: 'href'\n }\n});\nconst PARENT_NODE = () => ({\n id: {\n path: 'id'\n },\n ...HREF(),\n ...COORDINATES()\n});\nexport const NODE = () => ({\n version: {\n path: 'version'\n },\n id: {\n path: 'id'\n },\n path: {\n path: 'path'\n },\n level: {\n path: 'level'\n },\n ...COORDINATES(),\n lodSelection: {\n path: 'lodSelection',\n default: [\n {\n metricType: 'maxScreenThresholdSQ',\n maxError: 196349.54374999998\n },\n {\n metricType: 'maxScreenThreshold',\n maxError: 999.9999999999999\n }\n ]\n },\n children: {\n path: 'children',\n default: null\n },\n neighbors: {\n path: 'neighbors',\n default: null\n },\n parentNode: {\n path: 'parentNode',\n transform: (val) => transform(val, PARENT_NODE()),\n default: null\n },\n sharedResource: {\n path: 'sharedResource',\n default: null\n },\n featureData: {\n path: 'featureData',\n default: null\n },\n geometryData: {\n path: 'geometryData',\n default: null\n },\n textureData: {\n path: 'textureData',\n default: null\n },\n attributeData: {\n path: 'attributeData',\n default: null\n }\n});\n", "import { Tiles3DArchive } from '@loaders.gl/3d-tiles';\nimport { load } from '@loaders.gl/core';\nimport { FileHandleFile } from '@loaders.gl/loader-utils';\nimport { CD_HEADER_SIGNATURE, ZipFileSystem, parseHashTable, parseZipCDFileHeader, parseZipLocalFileHeader, searchFromTheEnd } from '@loaders.gl/zip';\n/**\n * Load nested 3DTiles tileset. If the sourceTile is not nested tileset - do nothing\n * @param sourceTileset - source root tileset JSON\n * @param sourceTile - source tile JSON that is supposed to has link to nested tileset\n * @param tilesetLoadOptions - load options for Tiles3DLoader\n * @returns nothing\n */\nexport const loadNestedTileset = async (sourceTileset, sourceTile, tilesetLoadOptions) => {\n const isTileset = isNestedTileset(sourceTile);\n if (!sourceTileset || !sourceTile.contentUrl || !isTileset) {\n return;\n }\n const loadOptions = {\n ...tilesetLoadOptions,\n [sourceTileset.loader.id]: {\n isTileset,\n assetGltfUpAxis: (sourceTileset.asset && sourceTileset.asset.gltfUpAxis) || 'Y'\n }\n };\n const tileContent = await loadFromArchive(sourceTile.contentUrl, sourceTileset.loader, loadOptions);\n if (tileContent.root) {\n sourceTile.children = [tileContent.root];\n }\n};\n/**\n * Load 3DTiles tile content, that includes glTF object\n * @param sourceTileset - source root tileset JSON\n * @param sourceTile - source tile JSON that has link to content data\n * @param tilesetLoadOptions - load options for Tiles3DLoader\n * @returns - 3DTiles tile content or null\n */\nexport const loadTile3DContent = async (sourceTileset, sourceTile, tilesetLoadOptions) => {\n const isTileset = isNestedTileset(sourceTile);\n if (!sourceTileset || !sourceTile.contentUrl || isTileset) {\n return null;\n }\n const loadOptions = {\n ...tilesetLoadOptions,\n [sourceTileset.loader.id]: {\n // @ts-ignore\n ...(tilesetLoadOptions[sourceTileset.loader.id] || {}),\n isTileset,\n assetGltfUpAxis: (sourceTileset.asset && sourceTileset.asset.gltfUpAxis) || 'Y'\n }\n };\n const tileContent = await loadFromArchive(sourceTile.contentUrl, sourceTileset.loader, loadOptions);\n return tileContent;\n};\n/**\n * Load a resource with load options and .3tz format support\n * @param url - resource URL\n * @param loader - loader to parse data (Tiles3DLoader / CesiumIonLoader)\n * @param loadOptions - 3d-tiles loader options\n * @returns 3d-tiles resource\n */\nexport async function loadFromArchive(url, loader, loadOptions) {\n const tz3UrlParts = url.split('.3tz');\n let filename;\n // No '.3tz'. The file will be loaded with global fetch function\n if (tz3UrlParts.length === 1) {\n filename = null;\n }\n else if (tz3UrlParts.length === 2) {\n filename = tz3UrlParts[1].slice(1);\n if (filename === '') {\n filename = 'tileset.json';\n }\n }\n else {\n throw new Error('Unexpected URL format');\n }\n if (filename) {\n const tz3Path = `${tz3UrlParts[0]}.3tz`;\n const fileProvider = new FileHandleFile(tz3Path);\n const hashTable = await loadHashTable(fileProvider);\n const archive = new Tiles3DArchive(fileProvider, hashTable, tz3Path);\n const fileSystem = new ZipFileSystem(archive);\n const content = await load(filename, loader, {\n ...loadOptions,\n fetch: fileSystem.fetch.bind(fileSystem)\n });\n await fileSystem.destroy();\n return content;\n }\n return await load(url, loader, loadOptions);\n}\n/**\n * Check if tile is nested tileset\n * @param tile - 3DTiles header data\n * @returns true if tile is nested tileset\n */\nexport function isNestedTileset(tile) {\n return tile?.type === 'json' || tile?.type === '3tz';\n}\n/**\n * Load hash file from 3TZ\n * @param fileProvider - binary reader of 3TZ\n * @returns hash table of the 3TZ file content or undefined if the hash file is not presented inside\n */\nasync function loadHashTable(fileProvider) {\n let hashTable;\n const hashCDOffset = await searchFromTheEnd(fileProvider, CD_HEADER_SIGNATURE);\n const cdFileHeader = await parseZipCDFileHeader(hashCDOffset, fileProvider);\n // '@3dtilesIndex1@' is index file that must be the last in the archive. It allows\n // to improve load and read performance when the archive contains a very large number\n // of files.\n if (cdFileHeader?.fileName === '@3dtilesIndex1@') {\n const localFileHeader = await parseZipLocalFileHeader(cdFileHeader.localHeaderOffset, fileProvider);\n if (!localFileHeader) {\n throw new Error('corrupted 3tz');\n }\n const fileDataOffset = localFileHeader.fileDataOffset;\n const hashFile = await fileProvider.slice(fileDataOffset, fileDataOffset + localFileHeader.compressedSize);\n hashTable = parseHashTable(hashFile);\n }\n return hashTable;\n}\n", "/**\n * Travesal of 3DTile tiles tree with making specific actions with each tile\n * @param tile - 3DTiles tile JSON metadata\n * @param traversalProps - traversal props used to pass data through recursive calls\n * @param processTile - callback to make some actions with the current tile\n * @param postprocessTile - callback to make some action after processing of the current tile and all the subtree\n * @param maxDepth - max recursive calls number the travesal function will do. If not set, the traversal function will\n * go through all the tree.\n * This value is used to limit the convertion with only partial number of levels of the tileset\n * @param level - counter to keep recursive calls number of the tiles tree. This value used to be able to break\n * traversal at the some level of the tree\n * @returns void\n */\nexport const traverseDatasetWith = async ({ tile, traversalProps, processTile, postprocessTile, maxDepth, level = 0 }) => {\n if (maxDepth && level > maxDepth) {\n return;\n }\n const processResults = [];\n const newTraversalProps = await processTile(tile, traversalProps);\n processResults.push(newTraversalProps);\n for (const childTile of tile.children) {\n await traverseDatasetWith({\n tile: childTile,\n traversalProps: newTraversalProps,\n processTile,\n postprocessTile,\n maxDepth,\n level: level + 1\n });\n }\n if (postprocessTile) {\n await postprocessTile(processResults, traversalProps);\n }\n};\n", "import { GLTFPrimitiveModeString } from \"../types.js\";\nimport { EXT_STRUCTURAL_METADATA, GLTFLoader } from '@loaders.gl/gltf';\nimport { parse } from '@loaders.gl/core';\nimport { EXT_FEATURE_METADATA } from '@loaders.gl/gltf';\n/**\n * glTF primitive modes\n * @see https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode\n */\nexport const GLTF_PRIMITIVE_MODES = [\n GLTFPrimitiveModeString.POINTS, // 0\n GLTFPrimitiveModeString.LINES, // 1\n GLTFPrimitiveModeString.LINE_LOOP, // 2\n GLTFPrimitiveModeString.LINE_STRIP, // 3\n GLTFPrimitiveModeString.TRIANGLES, // 4\n GLTFPrimitiveModeString.TRIANGLE_STRIP, // 5\n GLTFPrimitiveModeString.TRIANGLE_FAN // 6\n];\n/**\n * Analyze tile content. This function is used during preprocess stage of\n * conversion\n * @param tileContent - 3DTiles tile content ArrayBuffer\n * @returns\n */\nexport const analyzeTileContent = async (tileContent) => {\n const defaultResult = {\n meshTopologyTypes: new Set(),\n metadataClasses: new Set()\n };\n if (!tileContent?.gltfArrayBuffer) {\n return defaultResult;\n }\n const gltfData = await parse(tileContent.gltfArrayBuffer, GLTFLoader, {\n gltf: { normalize: false, loadBuffers: false, loadImages: false, decompressMeshes: false }\n });\n const gltf = gltfData.json;\n if (!gltf) {\n return defaultResult;\n }\n const meshTopologyTypes = getMeshTypesFromGLTF(gltf);\n const metadataClasses = getMetadataClassesFromGLTF(gltf);\n return {\n meshTopologyTypes,\n metadataClasses\n };\n};\n/**\n * Get mesh topology types that the glb content has\n * @param gltfJson - JSON part of GLB content\n * @returns array of mesh types found\n */\nconst getMeshTypesFromGLTF = (gltfJson) => {\n const result = new Set();\n for (const mesh of gltfJson.meshes || []) {\n for (const primitive of mesh.primitives) {\n let { mode } = primitive;\n if (typeof mode !== 'number') {\n mode = 4; // Default is 4 - TRIANGLES\n }\n result.add(GLTF_PRIMITIVE_MODES[mode]);\n }\n }\n return result;\n};\n/**\n * Get feature metadata classes from glTF\n * The tileset might contain multiple metadata classes provided by EXT_feature_metadata and EXT_structural_metadata extensions.\n * Every class is a set of properties. But I3S can consume only one set of properties.\n * On the pre-process we collect all classes from the tileset in order to show the prompt to select one class for conversion to I3S.\n * @param gltfJson - JSON part of GLB content\n * @returns array of classes\n */\nconst getMetadataClassesFromGLTF = (gltfJson) => {\n const result = new Set();\n // Try to parse from EXT_feature_metadata\n const extFeatureMetadataClasses = gltfJson.extensions?.[EXT_FEATURE_METADATA]?.schema?.classes;\n if (extFeatureMetadataClasses) {\n for (const classKey of Object.keys(extFeatureMetadataClasses)) {\n result.add(classKey);\n }\n }\n // Try to parse from EXT_structural_metadata\n const extStructuralMetadataClasses = gltfJson.extensions?.[EXT_STRUCTURAL_METADATA]?.schema?.classes;\n if (extStructuralMetadataClasses) {\n for (const classKey of Object.keys(extStructuralMetadataClasses)) {\n result.add(classKey);\n }\n }\n return result;\n};\n/**\n * Merge object2 into object1\n * @param object1\n * @param object2\n * @returns nothing\n */\nexport const mergePreprocessData = (object1, object2) => {\n // Merge topology mesh types info\n for (const type of object2.meshTopologyTypes) {\n object1.meshTopologyTypes.add(type);\n }\n // Merge feature metadata classes\n for (const metadataClass of object2.metadataClasses) {\n object1.metadataClasses.add(metadataClass);\n }\n};\n", "import process from 'process';\nimport { timeConverter } from \"../../lib/utils/statistic-utills.js\";\n/** Defines a threshold that is used to check if the process velocity can be consifered trust. */\nconst THRESHOLD_DEFAULT = 0.2;\n/**\n * Implements methods to keep track on the progress of a long process.\n */\nexport class Progress {\n /** Total amount of work, e.g. number of files to save or number of bytes to send */\n _stepsTotal = 0;\n /** Amount of work already done */\n _stepsDone = 0;\n /** Time in milli-seconds when the process started */\n startTime = 0;\n /** Time in milli-seconds when the process stopped */\n stopTime = 0;\n /** Time in milli-seconds when stepsDone was updated */\n timeOfUpdatingStepsDone = 0;\n /** Time in milli-seconds spent for performing one step*/\n milliSecForOneStep = 0;\n trust = false;\n /**\n * The number of digits to appear after decimal point in the string representation of the count of steps already done.\n * It's calculated based on the total count of steps.\n */\n numberOfDigitsInPercentage = 0;\n /** Defines a threshold that is used to check if the process velocity can be consifered trust. */\n threshold;\n /** Function that is used to get the time stamp */\n getTime;\n constructor(options = {}) {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.getTime = options.getTime || process.hrtime.bigint;\n this.threshold = options.threshold || THRESHOLD_DEFAULT;\n }\n /** Total amount of work, e.g. number of files to save or number of bytes to send */\n get stepsTotal() {\n return this._stepsTotal;\n }\n set stepsTotal(stepsTotal) {\n this._stepsTotal = stepsTotal;\n this.numberOfDigitsInPercentage =\n this.stepsTotal > 100 ? Math.ceil(Math.log10(this.stepsTotal)) - 2 : 0;\n }\n /** Amount of work already done */\n get stepsDone() {\n return this._stepsDone;\n }\n set stepsDone(stepsDone) {\n this._stepsDone = stepsDone;\n this.timeOfUpdatingStepsDone = this.getCurrentTimeInMilliSeconds();\n if (this._stepsDone) {\n const diff = this.timeOfUpdatingStepsDone - this.startTime;\n const milliSecForOneStep = diff / this._stepsDone;\n this.trust = this.isVelocityTrust(milliSecForOneStep, this.milliSecForOneStep);\n this.milliSecForOneStep = milliSecForOneStep;\n }\n }\n /**\n * Saves the current time as we start monitoring the process.\n */\n startMonitoring() {\n this.startTime = this.getCurrentTimeInMilliSeconds();\n this.milliSecForOneStep = 0;\n this.trust = false;\n this.timeOfUpdatingStepsDone = 0;\n this.stopTime = 0;\n this.stepsDone = 0;\n }\n /**\n * Saves the current time as we stop monitoring the process.\n */\n stopMonitoring() {\n this.stopTime = this.getCurrentTimeInMilliSeconds();\n }\n /**\n * Gets percentage of the work already done.\n * @returns percentage of the work already done.\n */\n getPercent() {\n if (!this._stepsTotal) {\n return null;\n }\n const percent = (this._stepsDone / this._stepsTotal) * 100.0;\n return percent;\n }\n /**\n * Gets string representation of percentage of the work already done.\n * @returns string representation of percentage or an empty string if the percetage value cannot be calculated.\n */\n getPercentString() {\n const percent = this.getPercent();\n return percent !== null ? percent.toFixed(this.numberOfDigitsInPercentage) : '';\n }\n /**\n * Gets the time elapsed since the monitoring started\n * @returns Number of milliseconds elapsed\n */\n getTimeCurrentlyElapsed() {\n const currentTime = this.stopTime ? this.stopTime : this.getCurrentTimeInMilliSeconds();\n const diff = currentTime - this.startTime;\n return diff;\n }\n /**\n * Gets the time remaining (expected at the moment of updating 'stepsDone') to complete the work.\n * @returns Number of milliseconds remaining\n */\n getTimeRemaining() {\n if (!this._stepsTotal || !this._stepsDone || !this.startTime) {\n return null;\n }\n const timeRemainingInMilliSeconds = (this._stepsTotal - this._stepsDone) * this.milliSecForOneStep;\n return { timeRemaining: timeRemainingInMilliSeconds, trust: this.trust };\n }\n /**\n * Gets the string representation of the time remaining (expected at the moment of updating 'stepsDone') to complete the work.\n * @returns string representation of the time remaining.\n * It's an empty string if the time cannot be pedicted or it's still being calculated.\n */\n getTimeRemainingString() {\n const timeRemainingObject = this.getTimeRemaining();\n return timeRemainingObject?.trust ? timeConverter(timeRemainingObject.timeRemaining) : '';\n }\n /**\n * Check if the computed velociy of the process can be considered trust.\n * At the beginning of the process the number of samples collected ('time necessary to perform one step' averaged) is too small,\n * which results in huge deviation of the cumputed velocity of the process.\n * It makes sense to perform the check before reporting the time remainig so the end user is not confused.\n * @param current - current value\n * @param previous - previous value\n * @returns true if the computed velociy can be considered trust, or false otherwise\n */\n isVelocityTrust(current, previous) {\n if (previous) {\n const dev = Math.abs((current - previous) / previous);\n return dev < this.threshold;\n }\n return false;\n }\n /**\n * Gets current time in milliseconds.\n * @returns current time in milliseconds.\n */\n getCurrentTimeInMilliSeconds() {\n // process.hrtime.bigint() returns the time in nanoseconds. We need the time in milliseconds.\n return Number(this.getTime() / BigInt(1e6));\n }\n}\n", "import { isDeepStrictEqual } from 'util';\nimport { DUMP_FILE_SUFFIX } from \"../../constants.js\";\nimport { isFileExists, openJson, removeFile, renameFile, writeFile } from \"./file-utils.js\";\nimport { join } from 'path';\nimport process from 'process';\nimport Ajv from 'ajv';\nimport { dumpJsonSchema } from \"../json-schemas/conversion-dump-json-schema.js\";\nexport class ConversionDump {\n /** Restored/resumed dump indicator */\n restored = false;\n /** Conversion options */\n options;\n /** Tiles conversion progress status map */\n tilesConverted;\n /** Textures formats definitions */\n textureSetDefinitions;\n /** Attributes Metadata */\n attributeMetadataInfo;\n /** Array of materials definitions */\n materialDefinitions;\n constructor() {\n this.tilesConverted = {};\n }\n /**\n * Create a dump with convertion options\n * @param currentOptions - converter options\n */\n async createDump(currentOptions) {\n const { tilesetName, slpk, egmFilePath, inputUrl, outputPath, draco = true, maxDepth, token, generateTextures, generateBoundingVolumes, mergeMaterials = true, metadataClass, analyze = false } = currentOptions;\n this.options = {\n tilesetName,\n slpk,\n egmFilePath,\n inputUrl,\n outputPath,\n draco,\n maxDepth,\n token,\n generateTextures,\n generateBoundingVolumes,\n mergeMaterials,\n metadataClass,\n analyze\n };\n const dumpFilename = join(this.options.outputPath, this.options.tilesetName, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`);\n if (await isFileExists(dumpFilename)) {\n try {\n const dump = await openJson(join(this.options.outputPath, this.options.tilesetName), `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`);\n const { options, tilesConverted, textureSetDefinitions, attributeMetadataInfo, materialDefinitions } = dump;\n const ajv = new Ajv();\n const dumpJsonValidate = ajv.compile(dumpJsonSchema);\n const isDumpValid = dumpJsonValidate(dump);\n if (isDumpValid && isDeepStrictEqual(options, JSON.parse(JSON.stringify(this.options)))) {\n this.tilesConverted = tilesConverted;\n this.textureSetDefinitions = textureSetDefinitions;\n this.attributeMetadataInfo = attributeMetadataInfo;\n this.materialDefinitions = materialDefinitions;\n this.restored = true;\n return;\n }\n }\n catch (error) {\n // prettier-ignore\n console.log('Can\\'t open dump file', error); // eslint-disable-line no-console\n }\n }\n await this.deleteDumpFile();\n }\n /**\n * Reset a dump\n */\n reset() {\n this.restored = false;\n this.tilesConverted = {};\n if (this.textureSetDefinitions) {\n delete this.textureSetDefinitions;\n }\n if (this.attributeMetadataInfo) {\n delete this.attributeMetadataInfo;\n }\n if (this.materialDefinitions) {\n delete this.materialDefinitions;\n }\n }\n /**\n * Update conversion status in the dump file\n */\n async updateDumpFile() {\n if (this.options?.outputPath && this.options.tilesetName) {\n try {\n const time = process.hrtime();\n await writeFile(join(this.options.outputPath, this.options.tilesetName), JSON.stringify({\n options: this.options,\n tilesConverted: this.tilesConverted,\n textureSetDefinitions: this.textureSetDefinitions,\n attributeMetadataInfo: this.attributeMetadataInfo,\n materialDefinitions: this.materialDefinitions\n }), `${this.options.tilesetName}${DUMP_FILE_SUFFIX}.${time[0]}.${time[1]}`);\n await renameFile(join(this.options.outputPath, this.options.tilesetName, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}.${time[0]}.${time[1]}`), join(this.options.outputPath, this.options.tilesetName, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`));\n }\n catch (error) {\n // prettier-ignore\n console.log('Can\\'t update dump file', error); // eslint-disable-line no-console\n }\n }\n }\n /**\n * Delete a dump file\n */\n async deleteDumpFile() {\n if (this.options?.outputPath &&\n this.options.tilesetName &&\n (await isFileExists(join(this.options.outputPath, this.options.tilesetName, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`)))) {\n await removeFile(join(this.options.outputPath, this.options.tilesetName, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`));\n }\n }\n /**\n * Get record from the tilesConverted Map\n * @param fileName - source filename\n * @returns existing object from the tilesConverted Map\n */\n getRecord(fileName) {\n return this.tilesConverted[fileName];\n }\n /**\n * Set a record for the dump file\n * @param fileName - key - source filename\n * @param object - value\n */\n setRecord(fileName, object) {\n this.tilesConverted[fileName] = object;\n }\n /**\n * Add a node into the dump file for the source file record\n * @param fileName - source filename\n * @param nodeId - nodeId of the node\n */\n async addNode(filename, nodeId, dumpMetadata) {\n const { nodes } = this.getRecord(filename) || { nodes: [] };\n nodes.push({ nodeId, done: false, dumpMetadata });\n if (nodes.length === 1) {\n this.setRecord(filename, { nodes });\n }\n await this.updateDumpFile();\n }\n /**\n * Clear dump record got the source filename\n * @param fileName - source filename\n */\n clearDumpRecord(filename) {\n this.setRecord(filename, { nodes: [] });\n }\n /**\n * Add textures definitions into the dump file\n * @param textureDefinitions - textures definitions array\n */\n addTexturesDefinitions(textureDefinitions) {\n this.textureSetDefinitions = textureDefinitions;\n }\n /**\n * Update done status object for the writing resources\n * @param fileName - key - source filename\n * @param nodeId - nodeId for the source filename\n * @param resourceType - resource type to update status\n * @param value - value\n */\n updateDoneStatus(filename, nodeId, resourceType, value) {\n const nodeDump = this.tilesConverted[filename]?.nodes.find((element) => element.nodeId === nodeId);\n if (nodeDump) {\n if (!nodeDump.progress) {\n nodeDump.progress = {};\n }\n nodeDump.progress[resourceType] = value;\n if (!value) {\n nodeDump.done = false;\n }\n }\n }\n /**\n * Update dump file according to writing results\n * @param changedRecords - array of parameters ids for the written resources\n * @param writeResults - array of writing resource files results\n */\n async updateConvertedTilesDump(changedRecords, writeResults) {\n for (let i = 0; i < changedRecords.length; i++) {\n if (changedRecords[i] && 'value' in writeResults[i]) {\n const { sourceId, resourceType, outputId } = changedRecords[i];\n this.updateNodes(sourceId, outputId, resourceType);\n }\n }\n await this.updateDumpFile();\n }\n /**\n * Update done status for a node\n * @param sourceId - source resource Id\n * @param outputId - output node/tile Id\n * @param resourceType - type of resource\n * @returns void\n */\n updateNodes(sourceId, outputId, resourceType) {\n if (!sourceId || !resourceType || !outputId) {\n return;\n }\n for (const node of this.tilesConverted[sourceId].nodes) {\n if (node.nodeId === outputId && node.progress) {\n node.progress[resourceType] = true;\n let done = false;\n for (const key in node.progress) {\n done = node.progress[key];\n if (!done)\n break;\n }\n node.done = done;\n if (node.done) {\n delete node.progress;\n }\n break;\n }\n }\n }\n /**\n * Update 3d-tiles-converter dump file\n * @param filename - source filename\n * @param nodeId - nodeId\n * @param done - conversion status\n */\n async updateConvertedNodesDumpFile(filename, nodeId, done) {\n const nodeDump = this.tilesConverted[filename]?.nodes.find((element) => element.nodeId === nodeId);\n if (nodeDump) {\n nodeDump.done = done;\n await this.updateDumpFile();\n }\n }\n /**\n * Check is source file conversion complete\n * @param filename - source filename\n * @returns true if source file conversion complete\n */\n isFileConversionComplete(filename) {\n let result = true;\n for (const node of this.tilesConverted[filename]?.nodes || []) {\n if (!node.done) {\n result = false;\n break;\n }\n }\n return result && this.tilesConverted[filename]?.nodes?.length > 0;\n }\n /**\n * Set materialDefinitions into a dump\n * @param materialDefinitions - Array materialDefinitions\n */\n setMaterialsDefinitions(materialDefinitions) {\n this.materialDefinitions = materialDefinitions;\n }\n}\n", "export const dumpJsonSchema = {\n type: 'object',\n properties: {\n options: {\n type: 'object',\n properties: {\n inputUrl: { type: 'string' },\n outputPath: { type: 'string' },\n tilesetName: { type: 'string' },\n maxDepth: { type: 'number' },\n slpk: { type: 'boolean' },\n egmFilePath: { type: 'string' },\n token: { type: 'string' },\n draco: { type: 'boolean' },\n mergeMaterials: { type: 'boolean' },\n generateTextures: { type: 'boolean' },\n generateBoundingVolumes: { type: 'boolean' },\n metadataClass: { type: 'string' },\n analyze: { type: 'boolean' }\n },\n required: ['inputUrl', 'outputPath', 'tilesetName']\n },\n tilesConverted: {\n type: 'object',\n patternProperties: {\n '.*': {\n type: 'object',\n properties: {\n nodes: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n nodeId: { type: ['number', 'string'] },\n done: { type: 'boolean' },\n progress: { type: 'object', patternProperties: { '.*': { type: 'boolean' } } },\n dumpMetadata: {\n type: 'object',\n properties: {\n boundingVolumes: {\n type: ['object', 'null'],\n properties: {\n mbs: {\n type: 'array',\n minItems: 4,\n maxItems: 4,\n items: { type: 'number' }\n },\n obb: {\n type: 'object',\n properties: {\n center: {\n type: 'array',\n minItems: 3,\n maxItems: 3,\n items: { type: 'number' }\n },\n halfSize: {\n type: 'array',\n minItems: 3,\n maxItems: 3,\n items: { type: 'number' }\n },\n quaternion: {\n type: 'array',\n minItems: 4,\n maxItems: 4,\n items: { type: 'number' }\n }\n },\n required: ['center', 'halfSize', 'quaternion']\n }\n },\n required: ['mbs', 'obb']\n },\n attributesCount: { type: 'number' },\n featureCount: { type: 'number' },\n geometry: { type: 'boolean' },\n hasUvRegions: { type: 'boolean' },\n materialId: { type: 'number' },\n texelCountHint: { type: 'number' },\n vertexCount: { type: 'number' }\n },\n required: [\n 'boundingVolumes',\n 'featureCount',\n 'geometry',\n 'hasUvRegions',\n 'materialId',\n 'vertexCount'\n ]\n }\n },\n required: ['nodeId', 'done']\n }\n }\n },\n required: ['nodes']\n }\n }\n },\n textureSetDefinitions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n formats: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n format: { enum: ['jpg', 'png', 'ktx-etc2', 'dds', 'ktx2'] }\n },\n required: ['name', 'format']\n }\n },\n atlas: { type: 'boolean' }\n },\n required: ['formats']\n }\n },\n attributeMetadataInfo: {\n type: 'object',\n properties: {\n attributeStorageInfo: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n key: { type: 'string' },\n name: { type: 'string' },\n header: {\n type: 'array',\n items: {\n type: 'object',\n properties: { property: { type: 'string' }, valueType: { type: 'string' } },\n required: ['property', 'valueType']\n }\n },\n ordering: { type: 'array', items: { type: 'string' } },\n attributeValues: { $ref: '#/$defs/AttributeValue' },\n attributeByteCounts: { $ref: '#/$defs/AttributeValue' },\n objectIds: { $ref: '#/$defs/AttributeValue' }\n },\n required: ['key', 'name', 'header']\n }\n },\n fields: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n type: { $ref: '#/$defs/ESRIField' },\n alias: { type: 'string' },\n domain: { $ref: '#/$defs/Domain' }\n },\n required: ['name', 'type']\n }\n },\n popupInfo: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n expressionInfos: { type: 'array', items: {} },\n fieldInfos: { type: 'array', items: { $ref: '#/$defs/FieldInfo' } },\n mediaInfos: { type: 'array', items: {} },\n popupElements: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n text: { type: 'string' },\n type: { type: 'string' },\n fieldInfos: { type: 'array', items: { $ref: '#/$defs/FieldInfo' } }\n }\n }\n }\n }\n }\n },\n required: ['attributeStorageInfo', 'fields']\n },\n materialDefinitions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n pbrMetallicRoughness: {\n type: 'object',\n properties: {\n baseColorFactor: {\n type: 'array',\n minItems: 4,\n maxItems: 4,\n items: { type: 'number' }\n },\n baseColorTexture: { $ref: '#/$defs/I3SMaterialTexture' },\n metallicFactor: { type: 'number' },\n roughnessFactor: { type: 'number' },\n metallicRoughnessTexture: { $ref: '#/$defs/I3SMaterialTexture' }\n },\n required: ['metallicFactor', 'roughnessFactor']\n },\n normalTexture: { $ref: '#/$defs/I3SMaterialTexture' },\n occlusionTexture: { $ref: '#/$defs/I3SMaterialTexture' },\n emissiveTexture: { $ref: '#/$defs/I3SMaterialTexture' },\n emissiveFactor: { type: 'array', minItems: 3, maxItems: 3, items: { type: 'number' } },\n alphaMode: { enum: ['opaque', 'mask', 'blend'] },\n alphaCutoff: { type: 'number' },\n doubleSided: { type: 'boolean' },\n cullFace: { enum: ['none', 'front', 'back'] }\n },\n required: ['pbrMetallicRoughness', 'alphaMode']\n }\n }\n },\n required: ['options', 'tilesConverted'],\n $defs: {\n AttributeValue: {\n type: 'object',\n properties: {\n valueType: { type: 'string' },\n encoding: { type: 'string' },\n valuesPerElement: { type: 'number' }\n },\n required: ['valueType']\n },\n ESRIField: {\n enum: [\n 'esriFieldTypeDate',\n 'esriFieldTypeSingle',\n 'esriFieldTypeDouble',\n 'esriFieldTypeGUID',\n 'esriFieldTypeGlobalID',\n 'esriFieldTypeInteger',\n 'esriFieldTypeOID',\n 'esriFieldTypeSmallInteger',\n 'esriFieldTypeString'\n ]\n },\n Domain: {\n type: 'object',\n properties: {\n type: { type: 'string' },\n name: { type: 'string' },\n description: { type: 'string' },\n fieldType: { type: 'string' },\n range: { type: 'array', items: { type: 'number' } },\n codedValues: {\n type: 'array',\n items: {\n type: 'object',\n properties: { name: { type: 'string' }, code: { type: ['string', 'number'] } },\n required: ['name', 'code']\n }\n },\n mergePolicy: { type: 'string' },\n splitPolicy: { type: 'string' }\n },\n required: ['type', 'name']\n },\n FieldInfo: {\n type: 'object',\n properties: {\n fieldName: { type: 'string' },\n visible: { type: 'boolean' },\n isEditable: { type: 'boolean' },\n label: { type: 'string' }\n },\n required: ['fieldName', 'visible', 'isEditable', 'label']\n },\n I3SMaterialTexture: {\n type: 'object',\n properties: {\n textureSetDefinitionId: { type: 'number' },\n texCoord: { type: 'number' },\n factor: { type: 'number' }\n },\n required: ['textureSetDefinitionId']\n }\n }\n};\n", "import { join } from 'path';\nimport process from 'process';\nimport transform from 'json-map-transform';\nimport { load, isBrowser } from '@loaders.gl/core';\nimport { I3SLoader, I3SAttributeLoader, COORDINATE_SYSTEM } from '@loaders.gl/i3s';\nimport { PGMLoader } from \"../pgm-loader.js\";\nimport { i3sObbTo3dTilesObb } from \"./helpers/i3s-obb-to-3d-tiles-obb.js\";\nimport { convertScreenThresholdToGeometricError } from \"../lib/utils/lod-conversion-utils.js\";\nimport { writeFile, removeDir } from \"../lib/utils/file-utils.js\";\nimport { calculateFilesSize, timeConverter } from \"../lib/utils/statistic-utills.js\";\nimport { TILESET as tilesetTemplate } from \"./json-templates/tileset.js\";\nimport { createObbFromMbs } from \"../i3s-converter/helpers/coordinate-converter.js\";\nimport { WorkerFarm } from '@loaders.gl/worker-utils';\nimport { BROWSER_ERROR_MESSAGE } from \"../constants.js\";\nimport B3dmConverter from \"./helpers/b3dm-converter.js\";\nimport { getNodeCount, loadFromArchive, loadI3SContent, openSLPK } from \"./helpers/load-i3s.js\";\nimport { ConversionDump } from \"../lib/utils/conversion-dump.js\";\nimport { Progress } from \"../i3s-converter/helpers/progress.js\";\nconst I3S = 'I3S';\n/**\n * Converter from i3s to 3d-tiles\n */\nexport default class Tiles3DConverter {\n options;\n tilesetPath;\n vertexCounter;\n conversionStartTime;\n geoidHeightModel;\n sourceTileset;\n attributeStorageInfo;\n workerSource = {};\n slpkFilesystem = null;\n loaderOptions = {\n _nodeWorkers: true,\n reuseWorkers: true,\n // TODO: converter freezes in the end because of i3s-content-worker\n worker: false,\n i3s: { coordinateSystem: COORDINATE_SYSTEM.LNGLAT_OFFSETS, decodeTextures: false },\n // We need to load local fs workers because nodejs can't load workers from the Internet\n 'i3s-content': {\n workerUrl: './modules/i3s/dist/i3s-content-worker-node.js'\n }\n };\n conversionDump;\n progress;\n constructor() {\n this.options = {};\n this.tilesetPath = '';\n this.vertexCounter = 0;\n this.conversionStartTime = [0, 0];\n this.geoidHeightModel = null;\n this.sourceTileset = null;\n this.attributeStorageInfo = null;\n this.workerSource = {};\n this.conversionDump = new ConversionDump();\n this.progress = new Progress();\n }\n /**\n * Convert i3s format data to 3dTiles\n * @param options\n * @param options.inputUrl the url to read the tileset from\n * @param options.outputPath the output filename\n * @param options.tilesetName the output name of the tileset\n * @param options.egmFilePath location of *.pgm file to convert heights from ellipsoidal to gravity-related format\n * @param options.maxDepth The max tree depth of conversion\n */\n // eslint-disable-next-line complexity, max-statements\n async convert(options) {\n if (isBrowser) {\n console.log(BROWSER_ERROR_MESSAGE); // eslint-disable-line no-console\n return BROWSER_ERROR_MESSAGE;\n }\n const { inputUrl, outputPath, tilesetName, maxDepth, egmFilePath, inquirer, analyze } = options;\n this.conversionStartTime = process.hrtime();\n this.options = { maxDepth, inquirer };\n console.log('Loading egm file...'); // eslint-disable-line\n this.geoidHeightModel = await load(egmFilePath, PGMLoader);\n console.log('Loading egm file completed!'); // eslint-disable-line\n this.slpkFilesystem = await openSLPK(inputUrl);\n let preprocessResult = true;\n if (analyze || this.slpkFilesystem) {\n preprocessResult = await this.preprocessConversion();\n if (!preprocessResult || analyze) {\n return undefined;\n }\n }\n this.progress.startMonitoring();\n this.sourceTileset = await loadFromArchive(inputUrl, I3SLoader, {\n ...this.loaderOptions,\n // @ts-expect-error `isTileset` can be boolean of 'auto' but TS expects a string\n i3s: { ...this.loaderOptions.i3s, isTileset: true }\n }, this.slpkFilesystem);\n if (!this.sourceTileset) {\n return undefined;\n }\n const rootNode = this.sourceTileset?.root;\n if (!rootNode.obb) {\n rootNode.obb = createObbFromMbs(rootNode.mbs);\n }\n this.tilesetPath = join(`${outputPath}`, `${tilesetName}`);\n this.attributeStorageInfo = this.sourceTileset.attributeStorageInfo;\n await this.conversionDump.createDump(options);\n if (this.conversionDump.restored && this.options.inquirer) {\n const result = await this.options.inquirer.prompt([\n {\n name: 'resumeConversion',\n type: 'confirm',\n message: 'Dump file of the previous conversion exists, do you want to resume that conversion?'\n }\n ]);\n if (!result.resumeConversion) {\n this.conversionDump.reset();\n }\n }\n // Removing the tilesetPath needed to exclude erroneous files after conversion\n if (!this.conversionDump.restored) {\n try {\n await removeDir(this.tilesetPath);\n }\n catch (e) {\n // do nothing\n }\n }\n const rootTile = {\n boundingVolume: {\n box: i3sObbTo3dTilesObb(rootNode.obb, this.geoidHeightModel)\n },\n geometricError: convertScreenThresholdToGeometricError(rootNode),\n children: [],\n refine: 'REPLACE'\n };\n await this._addChildren(rootNode, rootTile, 1);\n const tileset = transform({ root: rootTile }, tilesetTemplate());\n await writeFile(this.tilesetPath, JSON.stringify(tileset), 'tileset.json');\n await this.conversionDump.deleteDumpFile();\n this.progress.stopMonitoring();\n await this._finishConversion({ slpk: false, outputPath, tilesetName });\n if (this.slpkFilesystem) {\n this.slpkFilesystem.destroy();\n }\n // Clean up worker pools\n const workerFarm = WorkerFarm.getWorkerFarm({});\n workerFarm.destroy();\n return undefined;\n }\n /**\n * Preprocess stage of the tile converter. Calculate number of nodes\n * @returns true - the conversion is possible, false - the tileset's content is not supported\n */\n async preprocessConversion() {\n // eslint-disable-next-line no-console\n console.log('Analyze source layer');\n const nodesCount = await getNodeCount(this.slpkFilesystem);\n this.progress.stepsTotal = nodesCount;\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n // eslint-disable-next-line no-console\n console.log('Preprocess results:');\n if (this.slpkFilesystem) {\n // eslint-disable-next-line no-console\n console.log(`Node count: ${nodesCount}`);\n if (nodesCount === 0) {\n // eslint-disable-next-line no-console\n console.log('Node count is 0. The conversion will be interrupted.');\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n return false;\n }\n }\n else {\n // eslint-disable-next-line no-console\n console.log('Node count cannot be calculated for the remote dataset');\n }\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n return true;\n }\n /**\n * Convert particular I3S Node\n * @param parentSourceNode the parent node tile object (@loaders.gl/tiles/Tile3D)\n * @param parentNode object in resulting tileset\n * @param level a current level of a tree depth\n * @param childNodeInfo child node to convert\n */\n // eslint-disable-next-line complexity, max-statements\n async convertChildNode(parentSourceNode, parentNode, level, childNodeInfo) {\n let nextParentNode = parentNode;\n const sourceChild = await this._loadChildNode(parentSourceNode, childNodeInfo);\n if (sourceChild.contentUrl) {\n if (this.conversionDump.restored &&\n this.conversionDump.isFileConversionComplete(`${sourceChild.id}.b3dm`) &&\n (sourceChild.obb || sourceChild.mbs)) {\n const { child } = this._createChildAndBoundingVolume(sourceChild);\n parentNode.children.push(child);\n await this._addChildren(sourceChild, child, level + 1);\n return;\n }\n const content = await loadI3SContent(this.sourceTileset, sourceChild, this.loaderOptions, this.slpkFilesystem);\n if (!content) {\n await this._addChildren(sourceChild, parentNode, level + 1);\n return;\n }\n this.vertexCounter += content?.vertexCount || 0;\n let featureAttributes = null;\n if (this.attributeStorageInfo) {\n featureAttributes = await this._loadChildAttributes(sourceChild, this.attributeStorageInfo);\n }\n const { child, boundingVolume } = this._createChildAndBoundingVolume(sourceChild);\n const i3sAttributesData = {\n tileContent: content,\n box: boundingVolume.box || [],\n textureFormat: sourceChild.textureFormat\n };\n const b3dmConverter = new B3dmConverter();\n const b3dm = await b3dmConverter.convert(i3sAttributesData, featureAttributes);\n await this.conversionDump.addNode(`${sourceChild.id}.b3dm`, sourceChild.id);\n await writeFile(this.tilesetPath, new Uint8Array(b3dm), `${sourceChild.id}.b3dm`);\n await this.conversionDump.updateConvertedNodesDumpFile(`${sourceChild.id}.b3dm`, sourceChild.id, true);\n parentNode.children.push(child);\n nextParentNode = child;\n }\n this.progress.stepsDone += 1;\n let timeRemainingString = 'Calculating time left...';\n const timeRemaining = this.progress.getTimeRemainingString();\n if (timeRemaining) {\n timeRemainingString = `${timeRemaining} left`;\n }\n const percentString = this.progress.getPercentString();\n const progressString = percentString ? ` ${percentString}%, ${timeRemainingString}` : '';\n console.log(`[converted${progressString}]: ${childNodeInfo.id}`); // eslint-disable-line\n await this._addChildren(sourceChild, nextParentNode, level + 1);\n }\n /**\n * The recursive function of traversal of a nodes tree\n * @param parentSourceNode the parent node tile object (@loaders.gl/tiles/Tile3D)\n * @param parentNode object in resulting tileset\n * @param level a current level of a tree depth\n */\n async _addChildren(parentSourceNode, parentNode, level) {\n if (this.options.maxDepth && level > this.options.maxDepth) {\n return;\n }\n for (const childNodeInfo of parentSourceNode.children || []) {\n await this.convertChildNode(parentSourceNode, parentNode, level, childNodeInfo);\n }\n }\n /**\n * Load a child node having information from the node header\n * @param parentNode a parent node tile object (@loaders.gl/tiles/Tile3D)\n * @param childNodeInfo child information from 3DNodeIndexDocument\n * (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/nodeReference.cmn.md)\n */\n async _loadChildNode(parentNode, childNodeInfo) {\n let header;\n if (this.sourceTileset?.nodePagesTile) {\n console.log(`Node conversion: ${childNodeInfo.id}`); // eslint-disable-line no-console,no-undef\n header = await this.sourceTileset.nodePagesTile.formTileFromNodePages(parseInt(childNodeInfo.id));\n }\n else {\n const nodeUrl = this._relativeUrlToFullUrl(parentNode.url, childNodeInfo.href);\n // load metadata\n const options = {\n i3s: {\n ...this.loaderOptions,\n // @ts-expect-error\n isTileHeader: true,\n loadContent: false\n }\n };\n console.log(`Node conversion: ${nodeUrl}`); // eslint-disable-line no-console,no-undef\n header = await loadFromArchive(nodeUrl, I3SLoader, options, this.slpkFilesystem);\n }\n return header;\n }\n /**\n * Create child and child's boundingVolume for the converted node\n * @param sourceChild\n * @returns child and child's boundingVolume\n */\n _createChildAndBoundingVolume(sourceChild) {\n if (!sourceChild.obb) {\n sourceChild.obb = createObbFromMbs(sourceChild.mbs);\n }\n const boundingVolume = {\n box: i3sObbTo3dTilesObb(sourceChild.obb, this.geoidHeightModel)\n };\n const child = {\n boundingVolume,\n geometricError: convertScreenThresholdToGeometricError(sourceChild),\n children: [],\n content: {\n uri: `${sourceChild.id}.b3dm`,\n boundingVolume\n }\n };\n return { boundingVolume, child };\n }\n /**\n * Make an url of a resource from its relative url having the base url\n * @param baseUrl the base url. A resulting url will be related from this url\n * @param relativeUrl a realtive url of a resource\n */\n _relativeUrlToFullUrl(baseUrl = '', relativeUrl) {\n let resultArray = baseUrl.split('/');\n const relativeUrlArray = relativeUrl.split('/');\n for (const folder of relativeUrlArray) {\n switch (folder) {\n case '.':\n continue; // eslint-disable-line no-continue\n case '..':\n resultArray = resultArray.slice(0, -1);\n break;\n default:\n resultArray.push(folder);\n }\n }\n return resultArray.join('/');\n }\n /**\n * Do loading all attributes related to particular node.\n * @param sourceChild\n * @param attributeStorageInfo\n * @returns Promise of attributes object.\n */\n async _loadChildAttributes(sourceChild, attributeStorageInfo) {\n const promises = [];\n const { attributeUrls = [] } = sourceChild;\n for (let index = 0; index < attributeUrls.length; index++) {\n const inputUrl = attributeUrls[index];\n const attribute = attributeStorageInfo[index];\n const options = {\n attributeName: attribute.name,\n attributeType: this._getAttributeType(attribute)\n };\n promises.push(loadFromArchive(inputUrl, I3SAttributeLoader, options, this.slpkFilesystem));\n }\n const attributesList = await Promise.all(promises);\n this._replaceNestedArrays(attributesList);\n return Object.assign({}, ...attributesList);\n }\n /**\n * Returns attribute type for loading attributes\n * @param attribute\n * Workaround for I3S v1.6. There is no attribute.attributeValues.valueType field in attribute.\n * There is an 'Oid32' type if attribute has objectIds property.\n * Doc: https://github.com/Esri/i3s-spec/blob/master/docs/1.6/attributeStorageInfo.cmn.md\n */\n _getAttributeType(attribute) {\n if (attribute.attributeValues) {\n return attribute.attributeValues.valueType;\n }\n else if (attribute.objectIds) {\n return 'Oid32';\n }\n return '';\n }\n /**\n * Make simple arrays from attribute typed arrays.\n * @param attributesList\n */\n _replaceNestedArrays(attributesList) {\n for (let index = 0; index < attributesList.length; index++) {\n const attributeObject = attributesList[index];\n for (const key in attributeObject) {\n attributeObject[key] = Array.from(attributeObject[key]);\n }\n }\n }\n /**\n * Print statistics in the end of conversion\n * @param params - output files data\n */\n async _finishConversion(params) {\n const filesSize = await calculateFilesSize(params);\n const diff = process.hrtime(this.conversionStartTime);\n const conversionTime = timeConverter(diff);\n console.log(`------------------------------------------------`); // eslint-disable-line\n console.log(`Finish conversion of ${I3S}`); // eslint-disable-line\n console.log(`Total conversion time: ${conversionTime}`); // eslint-disable-line\n console.log(`Vertex count: `, this.vertexCounter); // eslint-disable-line\n console.log(`File(s) size: `, filesSize, ' bytes'); // eslint-disable-line\n console.log(`------------------------------------------------`); // eslint-disable-line\n }\n}\n", "import { Vector3 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\nimport { OrientedBoundingBox } from '@math.gl/culling';\n/**\n * Convert quaternion-based OBB to half-axes-based OBB\n * @param i3SObb quaternion based OBB\n * @param geoidHeightModel the Earth Gravity Model instance\n * @returns number[12] 3DTiles OBB https://github.com/CesiumGS/3d-tiles/tree/master/specification#box\n */\nexport function i3sObbTo3dTilesObb(i3SObb, geoidHeightModel) {\n const tiles3DCenter = [\n i3SObb.center[0],\n i3SObb.center[1],\n i3SObb.center[2] + geoidHeightModel.getHeight(i3SObb.center[1], i3SObb.center[0])\n ];\n const cartesianCenter = Ellipsoid.WGS84.cartographicToCartesian(tiles3DCenter, new Vector3());\n const tiles3DObb = new OrientedBoundingBox().fromCenterHalfSizeQuaternion(cartesianCenter, i3SObb.halfSize, i3SObb.quaternion);\n return [...tiles3DObb.center, ...tiles3DObb.halfAxes.toArray()];\n}\n", "import transform from 'json-map-transform';\nconst ASSET = () => ({\n version: {\n path: 'version',\n default: '1.0'\n }\n});\nconst TILE = () => ({\n boundingVolume: {\n path: 'boundingVolume'\n },\n geometricError: {\n path: 'geometricError'\n },\n refine: {\n path: 'refine'\n },\n content: {\n path: 'content'\n },\n children: {\n path: 'children',\n transform: (val) => val.map((tile) => transform(tile, TILE()))\n }\n});\nexport const TILESET = () => ({\n asset: {\n path: 'asset',\n transform: (val) => transform(val, ASSET())\n },\n geometricError: {\n path: 'root',\n transform: (val) => val.geometricError\n },\n root: {\n path: 'root',\n transform: (val) => transform(val, TILE())\n }\n});\n", "import { encodeSync } from '@loaders.gl/core';\nimport { GLTFScenegraph, GLTFWriter } from '@loaders.gl/gltf';\nimport { Tile3DWriter } from '@loaders.gl/3d-tiles';\nimport { Matrix4, Vector3 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\nimport { convertTextureAtlas } from \"./texture-atlas.js\";\nimport { generateSyntheticIndices } from \"../../lib/utils/geometry-utils.js\";\nconst Z_UP_TO_Y_UP_MATRIX = new Matrix4([1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1]);\nconst scratchVector = new Vector3();\nconst KHR_MATERIALS_UNLIT = 'KHR_materials_unlit';\nconst METALLIC_FACTOR_DEFAULT = 1.0;\nconst ROUGHNESS_FACTOR_DEFAULT = 1.0;\n/**\n * Converts content of an I3S node to *.b3dm's file content\n */\nexport default class B3dmConverter {\n // @ts-expect-error\n rtcCenter;\n i3sTile;\n /**\n * The starter of content conversion\n * @param i3sTile - Tile3D instance for I3S node\n * @returns - encoded content\n */\n async convert(i3sAttributesData, featureAttributes = null) {\n const gltf = await this.buildGLTF(i3sAttributesData, featureAttributes);\n const b3dm = encodeSync({\n gltfEncoded: new Uint8Array(gltf),\n type: 'b3dm',\n featuresLength: this._getFeaturesLength(featureAttributes),\n batchTable: featureAttributes\n }, Tile3DWriter);\n return b3dm;\n }\n /**\n * Build and encode gltf\n * @param i3sTile - Tile3D instance for I3S node\n * @returns - encoded glb content\n */\n // eslint-disable-next-line max-statements\n async buildGLTF(i3sAttributesData, featureAttributes) {\n const { tileContent, textureFormat, box } = i3sAttributesData;\n const { material, attributes, indices: originalIndices, modelMatrix } = tileContent;\n const gltfBuilder = new GLTFScenegraph();\n const textureIndex = await this._addI3sTextureToGLTF(tileContent, textureFormat, gltfBuilder);\n // Add KHR_MATERIALS_UNLIT extension in the following cases:\n // - metallicFactor or roughnessFactor are set to default values\n // - metallicFactor or roughnessFactor are not set\n const pbrMetallicRoughness = material?.pbrMetallicRoughness;\n if (pbrMetallicRoughness &&\n (pbrMetallicRoughness.metallicFactor === undefined ||\n pbrMetallicRoughness.metallicFactor === METALLIC_FACTOR_DEFAULT) &&\n (pbrMetallicRoughness.roughnessFactor === undefined ||\n pbrMetallicRoughness.roughnessFactor === ROUGHNESS_FACTOR_DEFAULT)) {\n gltfBuilder.addObjectExtension(material, KHR_MATERIALS_UNLIT, {});\n gltfBuilder.addExtension(KHR_MATERIALS_UNLIT);\n }\n const pbrMaterialInfo = this._convertI3sMaterialToGLTFMaterial(material, textureIndex);\n const materialIndex = gltfBuilder.addMaterial(pbrMaterialInfo);\n const positions = attributes.positions;\n const positionsValue = positions.value;\n if (attributes.uvRegions && attributes.texCoords) {\n attributes.texCoords.value = convertTextureAtlas(attributes.texCoords.value, attributes.uvRegions.value);\n }\n const cartesianOrigin = new Vector3(box);\n const cartographicOrigin = Ellipsoid.WGS84.cartesianToCartographic(cartesianOrigin, new Vector3());\n attributes.positions.value = this._normalizePositions(positionsValue, cartesianOrigin, cartographicOrigin, modelMatrix);\n this._createBatchIds(tileContent, featureAttributes);\n if (attributes.normals && !this._checkNormals(attributes.normals.value)) {\n delete attributes.normals;\n }\n const indices = originalIndices || generateSyntheticIndices(positionsValue.length / positions.size);\n const meshIndex = gltfBuilder.addMesh({\n attributes,\n indices,\n material: materialIndex,\n mode: 4\n });\n const transformMatrix = this._generateTransformMatrix(cartesianOrigin);\n const nodeIndex = gltfBuilder.addNode({ meshIndex, matrix: transformMatrix });\n const sceneIndex = gltfBuilder.addScene({ nodeIndices: [nodeIndex] });\n gltfBuilder.setDefaultScene(sceneIndex);\n gltfBuilder.createBinaryChunk();\n const gltfBuffer = encodeSync(gltfBuilder.gltf, GLTFWriter);\n return gltfBuffer;\n }\n /**\n * Update gltfBuilder with texture from I3S tile\n * @param {object} i3sTile - Tile3D object\n * @param {GLTFScenegraph} gltfBuilder - gltfScenegraph instance to construct GLTF\n * @returns {Promise<number | null>} - GLTF texture index\n */\n async _addI3sTextureToGLTF(tileContent, textureFormat, gltfBuilder) {\n const { texture, material, attributes } = tileContent;\n let textureIndex = null;\n let selectedTexture = texture;\n if (!texture && material) {\n selectedTexture =\n material.pbrMetallicRoughness &&\n material.pbrMetallicRoughness.baseColorTexture &&\n material.pbrMetallicRoughness.baseColorTexture.texture.source.image;\n }\n if (selectedTexture) {\n const mimeType = this._deduceMimeTypeFromFormat(textureFormat);\n const imageIndex = gltfBuilder.addImage(selectedTexture, mimeType);\n textureIndex = gltfBuilder.addTexture({ imageIndex });\n delete attributes.colors;\n }\n return textureIndex;\n }\n /**\n * Generate a positions array which is correct for 3DTiles/GLTF format\n * @param {Float64Array} positionsValue - the input geometry positions array\n * @param {number[]} cartesianOrigin - the tile center in the cartesian coordinate system\n * @param {number[]} cartographicOrigin - the tile center in the cartographic coordinate system\n * @param {number[]} modelMatrix - the model matrix of geometry\n * @returns {Float32Array} - the output geometry positions array\n */\n _normalizePositions(positionsValue, cartesianOrigin, cartographicOrigin, modelMatrix) {\n const newPositionsValue = new Float32Array(positionsValue.length);\n for (let index = 0; index < positionsValue.length; index += 3) {\n const vertex = positionsValue.subarray(index, index + 3);\n const cartesianOriginVector = new Vector3(cartesianOrigin);\n let vertexVector = new Vector3(Array.from(vertex))\n .transform(modelMatrix)\n .add(cartographicOrigin);\n Ellipsoid.WGS84.cartographicToCartesian(vertexVector, scratchVector);\n vertexVector = scratchVector.subtract(cartesianOriginVector);\n newPositionsValue.set(vertexVector, index);\n }\n return newPositionsValue;\n }\n /**\n * Generate the transformation matrix for GLTF node:\n * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-node\n * 1. Create the translate transformation from cartesianOrigin (the positions array stores offsets from this cartesianOrigin)\n * 2. Create the rotation transformation to rotate model from z-up coordinates (I3S specific) to y-up coordinates (GLTF specific)\n * @param {number[]} cartesianOrigin - the tile center in the cartesian coordinate system\n * @returns {Matrix4} - an array of 16 numbers (4x4 matrix)\n */\n _generateTransformMatrix(cartesianOrigin) {\n const translateOriginMatrix = new Matrix4().translate(cartesianOrigin);\n const result = translateOriginMatrix.multiplyLeft(Z_UP_TO_Y_UP_MATRIX);\n return result;\n }\n /**\n * Create _BATCHID attribute\n * @param {Object} i3sContent - the source object\n * @returns {void}\n */\n _createBatchIds(i3sContent, featureAttributes) {\n const { featureIds } = i3sContent;\n const { OBJECTID: objectIds } = featureAttributes || {};\n if (!featureIds || !objectIds) {\n return;\n }\n for (let i = 0; i < featureIds.length; i++) {\n const featureId = featureIds[i];\n const batchId = objectIds.indexOf(featureId);\n featureIds[i] = batchId;\n }\n i3sContent.attributes._BATCHID = {\n size: 1,\n byteOffset: 0,\n value: featureIds\n };\n }\n /**\n * Deduce mime type by format from `textureSetDefinition.formats[0].format`\n * https://github.com/Esri/i3s-spec/blob/master/docs/1.7/textureSetDefinitionFormat.cmn.md\n * @param {string} format - format name\n * @returns {string} mime type.\n */\n _deduceMimeTypeFromFormat(format) {\n switch (format) {\n case 'jpg':\n return 'image/jpeg';\n case 'png':\n return 'image/png';\n case 'ktx2':\n return 'image/ktx2';\n default:\n console.warn(`Unexpected texture format in I3S: ${format}`); // eslint-disable-line no-console, no-undef\n return 'image/jpeg';\n }\n }\n /**\n * Convert i3s material to GLTF compatible material\n * @param {object} material - i3s material definition\n * @param {number | null} textureIndex - texture index in GLTF\n * @returns {object} GLTF material\n */\n _convertI3sMaterialToGLTFMaterial(material, textureIndex) {\n const isTextureIndexExists = textureIndex !== null;\n if (!material) {\n material = {\n alphaMode: 'OPAQUE',\n doubleSided: false,\n pbrMetallicRoughness: {\n metallicFactor: 0,\n roughnessFactor: 1\n }\n };\n if (isTextureIndexExists) {\n material.pbrMetallicRoughness.baseColorTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n else {\n material.pbrMetallicRoughness.baseColorFactor = [1, 1, 1, 1];\n }\n return material;\n }\n if (textureIndex !== null) {\n material = this._setGLTFTexture(material, textureIndex);\n }\n return material;\n }\n /**\n * Set texture properties in material with GLTF textureIndex\n * @param {object} materialDefinition - i3s material definition\n * @param {number} textureIndex - texture index in GLTF\n * @returns {void}\n */\n _setGLTFTexture(materialDefinition, textureIndex) {\n const material = {\n ...materialDefinition,\n pbrMetallicRoughness: { ...materialDefinition.pbrMetallicRoughness }\n };\n // I3SLoader now support loading only one texture. This elseif sequence will assign this texture to one of\n // properties defined in materialDefinition\n if (materialDefinition.pbrMetallicRoughness &&\n materialDefinition.pbrMetallicRoughness.baseColorTexture) {\n material.pbrMetallicRoughness.baseColorTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n else if (materialDefinition.emissiveTexture) {\n material.emissiveTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n else if (materialDefinition.pbrMetallicRoughness &&\n materialDefinition.pbrMetallicRoughness.metallicRoughnessTexture) {\n material.pbrMetallicRoughness.metallicRoughnessTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n else if (materialDefinition.normalTexture) {\n material.normalTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n else if (materialDefinition.occlusionTexture) {\n material.occlusionTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n return material;\n }\n /*\n * Returns Features length based on attribute array in attribute object.\n * @param {Object} attributes\n * @returns {Number} Features length .\n */\n _getFeaturesLength(attributes) {\n if (!attributes) {\n return 0;\n }\n const firstKey = Object.keys(attributes)[0];\n return firstKey ? attributes[firstKey].length : 0;\n }\n /* Checks that normals buffer is correct\n * @param {TypedArray} normals\n * @returns {boolean} true - normals are correct; false - normals are incorrect\n */\n _checkNormals(normals) {\n // If all normals === 0, the resulting tileset is all in black colors on Cesium\n return normals.find((value) => value);\n }\n}\n", "/**\n * Apply uvRegions to texture coordinates.\n * Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/geometryUVRegion.cmn.md\n * Shader formula vec2 uv = fract(texCoords) * (uvRegions.zw - uvRegions.xy) + uvRegions.xy;\n * @param texCoords\n * @param uvRegions\n */\nexport function convertTextureAtlas(texCoords, uvRegions) {\n const convertedTexCoords = new Float32Array(texCoords.length);\n const normalisedRegions = normalizeRegions(uvRegions);\n for (let index = 0; index < texCoords.length; index += 2) {\n const uv = texCoords.subarray(index, index + 2);\n const regions = normalisedRegions.slice(index * 2, index * 2 + 4);\n // fract(texCoords)\n const fractatedUV = fract([uv[0], uv[1]]);\n // (uvRegions.zw - uvRegions.xy)\n const subtracted = [regions[2] - regions[0], regions[3] - regions[1]];\n // fract(texCoords) * (uvRegions.zw - uvRegions.xy)\n const multiplicationResult = [fractatedUV[0] * subtracted[0], fractatedUV[1] * subtracted[1]];\n // fract(texCoords) * (uvRegions.zw - uvRegions.xy) + uvRegions.xy;\n const convertedUV = [\n multiplicationResult[0] + regions[0],\n multiplicationResult[1] + regions[1]\n ];\n convertedTexCoords[index] = convertedUV[0];\n convertedTexCoords[index + 1] = convertedUV[1];\n }\n return convertedTexCoords;\n}\n/**\n * Do fractation of UV array.\n * @param uv\n */\nfunction fract(uv) {\n return [uv[0] - Math.floor(uv[0]), uv[1] - Math.floor(uv[1])];\n}\n/**\n * Normalize uvRegions by dividing by the maximum Uint16 value\n * @param regions\n */\nfunction normalizeRegions(regions) {\n // The code is for Uint16Array because it is the spec requirement\n // https://github.com/Esri/i3s-spec/blob/master/docs/1.8/geometryUVRegion.cmn.md\n const MAX_UINT_16_VALUE = 65535;\n const normalizedRegions = [];\n for (let index = 0; index < regions.length; index++) {\n normalizedRegions[index] = regions[index] / MAX_UINT_16_VALUE;\n }\n return normalizedRegions;\n}\n", "import { load } from '@loaders.gl/core';\nimport { I3SLoader, parseSLPKArchive } from '@loaders.gl/i3s';\nimport { FileHandleFile } from '@loaders.gl/loader-utils';\nimport { ZipFileSystem, makeZipCDHeaderIterator } from '@loaders.gl/zip';\n/**\n * Load I3S node content\n * @param sourceTileset - source layer JSON\n * @param sourceTile - source I3S node metadata\n * @param tilesetLoadOptions - load options for Tiles3DLoader\n * @param slpkFilesystem - loaded instance of ZipFileSystem for local convertion from SLPK file\n * @returns - 3DTiles tile content or null\n */\nexport const loadI3SContent = async (sourceTileset, sourceTile, tilesetLoadOptions, slpkFilesystem) => {\n if (!sourceTileset || !sourceTile.contentUrl) {\n return null;\n }\n const loadOptions = {\n ...tilesetLoadOptions,\n i3s: {\n ...tilesetLoadOptions.i3s,\n // @ts-expect-error\n isTileset: false,\n // @ts-expect-error\n isTileHeader: false,\n _tileOptions: {\n attributeUrls: sourceTile.attributeUrls || [],\n textureUrl: sourceTile.textureUrl,\n textureFormat: sourceTile.textureFormat,\n textureLoaderOptions: sourceTile.textureLoaderOptions,\n materialDefinition: sourceTile.materialDefinition,\n isDracoGeometry: sourceTile.isDracoGeometry,\n mbs: sourceTile.mbs\n },\n _tilesetOptions: {\n store: sourceTileset.store,\n // @ts-expect-error\n attributeStorageInfo: sourceTileset.attributeStorageInfo,\n // @ts-expect-error\n fields: sourceTileset.fields\n }\n }\n };\n const tileContent = await loadFromArchive(sourceTile.contentUrl, I3SLoader, loadOptions, slpkFilesystem);\n return tileContent;\n};\n/**\n * Load local SLPK file to ZipFileSystem instance\n * @param url - path to SLPK file\n * @returns instance of ZipFileSystem or null if url is not an SLPK file\n */\nexport async function openSLPK(url) {\n const slpkUrlParts = url.split('.slpk');\n if (slpkUrlParts.length === 2) {\n const slpkFileName = `${slpkUrlParts[0]}.slpk`;\n const fileProvider = new FileHandleFile(slpkFileName);\n const archive = await parseSLPKArchive(fileProvider, undefined, slpkFileName);\n const fileSystem = new ZipFileSystem(archive);\n return fileSystem;\n }\n return null;\n}\n/**\n * Load a resource with load options and .3tz format support\n * @param url - resource URL\n * @param loader - loader to parse data (Tiles3DLoader / CesiumIonLoader)\n * @param loadOptions - i3s loader options\n * @returns i3s resource\n */\nexport async function loadFromArchive(url, loader, loadOptions, fileSystem) {\n if (fileSystem !== null) {\n const content = await load(url, loader, {\n ...loadOptions,\n fetch: fileSystem.fetch.bind(fileSystem)\n });\n return content;\n }\n return await load(url, loader, loadOptions);\n}\n/**\n * Get nodes count inside SLPK\n * @param fileSystem - file system of SLPK\n * @returns number of nodes\n */\nexport async function getNodeCount(fileSystem) {\n if (!fileSystem?.fileProvider) {\n return 0;\n }\n let count = 0;\n const filesIterator = makeZipCDHeaderIterator(fileSystem.fileProvider);\n for await (const file of filesIterator) {\n const filename = file.fileName;\n if (filename.indexOf('3dNodeIndexDocument.json.gz') >= 0) {\n count++;\n }\n }\n return count;\n}\n"],
|
|
4
|
+
"sourcesContent": ["export { default as I3SConverter } from \"./i3s-converter/i3s-converter.js\";\nexport { default as Tiles3DConverter } from \"./3d-tiles-converter/3d-tiles-converter.js\";\n", "/**\n * glTF primitive modes (mesh topology types)\n * @see https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode\n */\nexport var GLTFPrimitiveModeString;\n(function (GLTFPrimitiveModeString) {\n GLTFPrimitiveModeString[\"POINTS\"] = \"POINTS\";\n GLTFPrimitiveModeString[\"LINES\"] = \"LINES\";\n GLTFPrimitiveModeString[\"LINE_LOOP\"] = \"LINE_LOOP\";\n GLTFPrimitiveModeString[\"LINE_STRIP\"] = \"LINE_STRIP\";\n GLTFPrimitiveModeString[\"TRIANGLES\"] = \"TRIANGLES\";\n GLTFPrimitiveModeString[\"TRIANGLE_STRIP\"] = \"TRIANGLE_STRIP\";\n GLTFPrimitiveModeString[\"TRIANGLE_FAN\"] = \"TRIANGLE_FAN\";\n})(GLTFPrimitiveModeString || (GLTFPrimitiveModeString = {}));\n/**\n * I3S' types difine the following:\n * type Attribute = 'OBJECTID' | 'string' | 'double' | 'Int32' | string;\n * The AttributeType contains the string values of the Attribute type.\n */\nexport const AttributeType = {\n /** Type of attribute that is linked with feature ids */\n OBJECT_ID_TYPE: 'OBJECTID',\n /** String data type name for feature attributes */\n STRING_TYPE: 'string',\n /** Double data type name for feature attributes */\n DOUBLE_TYPE: 'double',\n /** Integer data type name for feature attributes */\n SHORT_INT_TYPE: 'Int32'\n};\nexport var ResourceType;\n(function (ResourceType) {\n ResourceType[\"ATTRIBUTES\"] = \"ATTRIBUTES\";\n ResourceType[\"DRACO_GEOMETRY\"] = \"DRACO_GEOMETRY\";\n ResourceType[\"GEOMETRY\"] = \"GEOMETRY\";\n ResourceType[\"SHARED\"] = \"SHARED\";\n ResourceType[\"TEXTURE\"] = \"TEXTURE\";\n})(ResourceType || (ResourceType = {}));\n", "import { AttributeType } from \"../types.js\";\nexport class AttributeMetadataInfo {\n _attributeStorageInfo;\n _fields;\n _popupInfo;\n constructor() {\n this._attributeStorageInfo = [];\n this._fields = [];\n }\n get attributeStorageInfo() {\n return this._attributeStorageInfo;\n }\n get fields() {\n return this._fields;\n }\n get popupInfo() {\n return this._popupInfo;\n }\n /**\n * Creates and stores Attribute Storage Info, Fields and PopupInfo objects based on attribute's types.\n * Appends objects that have not been stored yet.\n * @param attributeTypesMap - set of attribute's types\n * @example AttributeStorageInfo, Fields and PopupInfo already contain objects for the following attributes:\n * {\n * color: 'string',\n * name: 'string',\n * opt_uint8: 'Int32'\n * }\n * Then, we call the addMetadataInfo method with the following attributeTypesMap:\n * {\n * // The same attributes\n * color: 'string',\n * name: 'string',\n * opt_uint8: 'Int32',\n * // New attributes\n * opt_uint64: 'string',\n * opt_float32: 'double',\n * }\n * The method creates and stores objects for opt_uint64, opt_float32 attributes.\n */\n addMetadataInfo(attributeTypesMap) {\n if (!Object.keys(attributeTypesMap).length) {\n return;\n }\n const attributeTypes = {\n OBJECTID: AttributeType.OBJECT_ID_TYPE,\n ...attributeTypesMap\n };\n let isUpdated = false;\n let attributeIndex = this._attributeStorageInfo.length;\n for (const key in attributeTypes) {\n /*\n We will append a new attribute only in case it has not been added to the attribute storage info yet.\n */\n const elementFound = this._attributeStorageInfo.find((element) => element.name === key);\n if (!elementFound) {\n const attributeType = attributeTypes[key];\n const storageAttribute = this.createStorageAttribute(attributeIndex, key, attributeType);\n const fieldAttributeType = this.getFieldAttributeType(attributeType);\n const fieldAttribute = this.createFieldAttribute(key, fieldAttributeType);\n this._attributeStorageInfo.push(storageAttribute);\n this._fields.push(fieldAttribute);\n attributeIndex += 1;\n isUpdated = true;\n }\n }\n if (isUpdated) {\n /*\n The attributeStorageInfo is updated. So, popupInfo should be recreated.\n Use attributeStorageInfo as a source of attribute names to create the popupInfo.\n */\n const attributeNames = [];\n for (const info of this._attributeStorageInfo) {\n attributeNames.push(info.name);\n }\n this._popupInfo = this.createPopupInfo(attributeNames);\n }\n }\n /**\n * Set AttributeMetadataInfo from object\n * @param object - object with AttributeMetadataInfo props\n */\n fromObject(object) {\n this._attributeStorageInfo = object.attributeStorageInfo;\n this._fields = object.fields;\n this._popupInfo = object.popupInfo;\n }\n /**\n * Generates storage attribute for map segmentation.\n * @param attributeIndex - order index of attribute (f_0, f_1 ...).\n * @param key - attribute key from propertyTable.\n * @param attributeType - attribute type.\n * @return Updated storageAttribute.\n */\n createStorageAttribute(attributeIndex, key, attributeType) {\n const storageAttribute = {\n key: `f_${attributeIndex}`,\n name: key,\n ordering: ['attributeValues'],\n header: [{ property: 'count', valueType: 'UInt32' }],\n attributeValues: { valueType: 'Int32', valuesPerElement: 1 }\n };\n switch (attributeType) {\n case AttributeType.OBJECT_ID_TYPE:\n this.setupIdAttribute(storageAttribute);\n break;\n case AttributeType.STRING_TYPE:\n this.setupStringAttribute(storageAttribute);\n break;\n case AttributeType.DOUBLE_TYPE:\n this.setupDoubleAttribute(storageAttribute);\n break;\n case AttributeType.SHORT_INT_TYPE:\n break;\n default:\n this.setupStringAttribute(storageAttribute);\n }\n return storageAttribute;\n }\n /**\n * Finds and returns attribute type based on key form propertyTable.\n * @param attributeType\n */\n getFieldAttributeType(attributeType) {\n switch (attributeType) {\n case AttributeType.OBJECT_ID_TYPE:\n return 'esriFieldTypeOID';\n case AttributeType.STRING_TYPE:\n return 'esriFieldTypeString';\n case AttributeType.SHORT_INT_TYPE:\n return 'esriFieldTypeInteger';\n case AttributeType.DOUBLE_TYPE:\n return 'esriFieldTypeDouble';\n default:\n return 'esriFieldTypeString';\n }\n }\n /**\n * Sets up Id attribute for map segmentation.\n * @param storageAttribute - attribute for map segmentation .\n */\n setupIdAttribute(storageAttribute) {\n storageAttribute.attributeValues = {\n valueType: 'Oid32',\n valuesPerElement: 1\n };\n }\n /**\n * Sets up storage attribute as string.\n * @param storageAttribute - attribute for map segmentation.\n */\n setupStringAttribute(storageAttribute) {\n // @ts-expect-error\n storageAttribute.ordering.unshift('attributeByteCounts');\n storageAttribute.header.push({ property: 'attributeValuesByteCount', valueType: 'UInt32' });\n storageAttribute.attributeValues = {\n valueType: 'String',\n encoding: 'UTF-8',\n valuesPerElement: 1\n };\n storageAttribute.attributeByteCounts = {\n valueType: 'UInt32',\n valuesPerElement: 1\n };\n }\n /**\n * Sets up double attribute for map segmentation.\n * @param storageAttribute - attribute for map segmentation .\n */\n setupDoubleAttribute(storageAttribute) {\n storageAttribute.attributeValues = {\n valueType: 'Float64',\n valuesPerElement: 1\n };\n }\n /**\n * Sets up field attribute for map segmentation.\n * @param key - attribute for map segmentation.\n * @param fieldAttributeType - esri attribute type ('esriFieldTypeString' or 'esriFieldTypeOID').\n */\n createFieldAttribute(key, fieldAttributeType) {\n return {\n name: key,\n type: fieldAttributeType,\n alias: key\n };\n }\n /**\n * Generates popup info to show metadata on the map.\n * @param propertyNames - array of property names including OBJECTID.\n * @return data for correct rendering of popup.\n */\n createPopupInfo(propertyNames) {\n const title = '{OBJECTID}';\n const mediaInfos = [];\n const fieldInfos = [];\n const popupElements = [];\n const expressionInfos = [];\n for (const propertyName of propertyNames) {\n fieldInfos.push({\n fieldName: propertyName,\n visible: true,\n isEditable: false,\n label: propertyName\n });\n }\n popupElements.push({\n fieldInfos,\n type: 'fields'\n });\n return {\n title,\n mediaInfos,\n popupElements,\n fieldInfos,\n expressionInfos\n };\n }\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { AttributeMetadataInfo } from \"./helpers/attribute-metadata-info.js\";\nimport { load, encode, isBrowser } from '@loaders.gl/core';\nimport { CesiumIonLoader, Tiles3DLoader } from '@loaders.gl/3d-tiles';\nimport { join } from 'path';\nimport { v4 as uuidv4 } from 'uuid';\nimport process from 'process';\nimport transform from 'json-map-transform';\nimport md5 from 'md5';\nimport NodePages from \"./helpers/node-pages.js\";\nimport { writeFile, removeDir, writeFileForSlpk, removeFile } from \"../lib/utils/file-utils.js\";\nimport { compressFileWithGzip } from \"../lib/utils/compress-util.js\";\nimport { calculateFilesSize, timeConverter } from \"../lib/utils/statistic-utills.js\";\nimport convertB3dmToI3sGeometry, { getPropertyTable } from \"./helpers/geometry-converter.js\";\nimport { createBoundingVolumes, convertBoundingVolumeToI3SFullExtent } from \"./helpers/coordinate-converter.js\";\nimport { createSceneServerPath } from \"./helpers/create-scene-server-path.js\";\nimport { convertGeometricErrorToScreenThreshold } from \"../lib/utils/lod-conversion-utils.js\";\nimport { PGMLoader } from \"../pgm-loader.js\";\nimport { LAYERS as layersTemplate } from \"./json-templates/layers.js\";\nimport { GEOMETRY_DEFINITION as geometryDefinitionTemlate } from \"./json-templates/geometry-definitions.js\";\nimport { SHARED_RESOURCES as sharedResourcesTemplate } from \"./json-templates/shared-resources.js\";\nimport { validateNodeBoundingVolumes } from \"./helpers/node-debug.js\";\nimport { KTX2BasisWriterWorker } from '@loaders.gl/textures';\nimport { ImageWriter } from '@loaders.gl/images';\nimport { GLTFPrimitiveModeString, ResourceType } from \"./types.js\";\nimport { WorkerFarm } from '@loaders.gl/worker-utils';\nimport WriteQueue from \"../lib/utils/write-queue.js\";\nimport { BROWSER_ERROR_MESSAGE } from \"../constants.js\";\nimport { getAttributeTypesMapFromPropertyTable, getAttributeTypesMapFromSchema } from \"./helpers/feature-attributes.js\";\nimport { NodeIndexDocument } from \"./helpers/node-index-document.js\";\nimport { isNestedTileset, loadNestedTileset, loadTile3DContent, loadFromArchive } from \"./helpers/load-3d-tiles.js\";\nimport { Matrix4 } from '@math.gl/core';\nimport { TILE_REFINEMENT, createBoundingVolume } from '@loaders.gl/tiles';\nimport { traverseDatasetWith } from \"./helpers/tileset-traversal.js\";\nimport { analyzeTileContent, mergePreprocessData } from \"./helpers/preprocess-3d-tiles.js\";\nimport { Progress } from \"./helpers/progress.js\";\nimport { composeHashFile, createZip } from '@loaders.gl/zip';\nimport { ConversionDump } from \"../lib/utils/conversion-dump.js\";\nconst ION_DEFAULT_TOKEN = process.env?.IonToken;\nconst HARDCODED_NODES_PER_PAGE = 64;\nconst _3D_TILES = '3DTILES';\nconst _3D_OBJECT_LAYER_TYPE = '3DObject';\nconst REFRESH_TOKEN_TIMEOUT = 1800; // 30 minutes in seconds\nconst CESIUM_DATASET_PREFIX = 'https://';\n// const FS_FILE_TOO_LARGE = 'ERR_FS_FILE_TOO_LARGE';\nconst PROGRESS_PHASE1_COUNT = 'phase1-count';\n/**\n * Converter from 3d-tiles tileset to i3s layer\n */\nexport default class I3SConverter {\n attributeMetadataInfo;\n nodePages;\n options;\n layers0Path;\n materialMap;\n materialDefinitions;\n geometryMap;\n geometryConfigs;\n vertexCounter;\n layers0;\n featuresHashArray;\n refinementCounter;\n validate;\n boundingVolumeWarnings = [];\n conversionStartTime = [0, 0];\n refreshTokenTime = [0, 0];\n sourceTileset = null;\n loadOptions = {\n _nodeWorkers: true,\n reuseWorkers: true,\n useLocalLibraries: true,\n basis: {\n format: 'rgba32',\n // We need to load local fs workers because nodejs can't load workers from the Internet\n workerUrl: './modules/textures/dist/basis-worker-node.js'\n },\n // We need to load local fs workers because nodejs can't load workers from the Internet\n draco: { workerUrl: './modules/draco/dist/draco-worker-node.js' },\n fetch: {},\n modules: {}\n };\n geoidHeightModel = null;\n Loader = Tiles3DLoader;\n generateTextures;\n generateBoundingVolumes;\n layersHasTexture;\n workerSource = {};\n writeQueue = new WriteQueue(new ConversionDump());\n compressList = null;\n preprocessData = {\n meshTopologyTypes: new Set(),\n metadataClasses: new Set()\n };\n progresses = {};\n conversionDump;\n constructor() {\n this.attributeMetadataInfo = new AttributeMetadataInfo();\n this.nodePages = new NodePages(writeFile, HARDCODED_NODES_PER_PAGE, this);\n this.options = {};\n this.layers0Path = '';\n this.materialMap = new Map();\n this.materialDefinitions = [];\n this.geometryMap = new Map();\n this.geometryConfigs = [];\n this.vertexCounter = 0;\n this.layers0 = null;\n this.featuresHashArray = [];\n this.refinementCounter = {\n tilesCount: 0,\n tilesWithAddRefineCount: 0\n };\n this.validate = false;\n this.generateTextures = false;\n this.generateBoundingVolumes = false;\n this.layersHasTexture = false;\n this.compressList = null;\n this.conversionDump = new ConversionDump();\n }\n /**\n * Convert a 3d tileset\n * @param options\n * @param options.inputUrl the url to read the tileset from\n * @param options.outputPath the output filename\n * @param options.tilesetName the output name of the tileset\n * @param options.maxDepth The max tree depth of conversion\n * @param options.slpk Generate slpk (Scene Layer Packages) output file\n * @param options.sevenZipExe Location of 7z.exe archiver to create slpk on Windows\n * @param options.egmFilePath location of *.pgm file to convert heights from ellipsoidal to gravity-related format\n * @param options.token Token for Cesium ION tilesets authentication\n * @param options.draco Generate I3S 1.7 draco compressed geometries\n * @param options.validate -enable validation\n * @param options.generateTextures - generate alternative type of textures (to have non-compressed jpeg/png and compressed ktx2)\n * @param options.generateBoundingVolumes - generate bounding volumes from vertices coordinates instead of source tiles bounding volumes\n * @param options.instantNodeWriting - Keep created 3DNodeIndexDocument files on disk instead of memory. This option reduce memory usage but decelerates conversion speed\n */\n // eslint-disable-next-line max-statements, complexity\n async convert(options) {\n if (isBrowser) {\n console.log(BROWSER_ERROR_MESSAGE); // eslint-disable-line no-console\n return BROWSER_ERROR_MESSAGE;\n }\n this.conversionStartTime = process.hrtime();\n const { tilesetName, slpk, egmFilePath, inputUrl, validate, outputPath, draco = true, sevenZipExe, maxDepth, token, generateTextures, generateBoundingVolumes, instantNodeWriting = false, mergeMaterials = true, inquirer, metadataClass, analyze = false } = options;\n this.options = {\n outputPath,\n tilesetName,\n maxDepth,\n slpk,\n sevenZipExe,\n egmFilePath,\n draco,\n token,\n inputUrl,\n instantNodeWriting,\n mergeMaterials,\n inquirer,\n metadataClass\n };\n this.progresses[PROGRESS_PHASE1_COUNT] = new Progress();\n this.compressList = (this.options.instantNodeWriting && []) || null;\n this.validate = Boolean(validate);\n this.Loader = inputUrl.indexOf(CESIUM_DATASET_PREFIX) !== -1 ? CesiumIonLoader : Tiles3DLoader;\n this.generateTextures = Boolean(generateTextures);\n this.generateBoundingVolumes = Boolean(generateBoundingVolumes);\n this.writeQueue = new WriteQueue(this.conversionDump);\n this.writeQueue.startListening();\n console.log('Loading egm file...'); // eslint-disable-line\n this.geoidHeightModel = await load(egmFilePath, PGMLoader);\n console.log('Loading egm file completed!'); // eslint-disable-line\n if (slpk) {\n this.nodePages.useWriteFunction(writeFileForSlpk);\n }\n try {\n const preloadOptions = await this._fetchPreloadOptions();\n let tilesetUrl = inputUrl;\n if (preloadOptions.url) {\n tilesetUrl = preloadOptions.url;\n }\n if (preloadOptions.headers) {\n this.loadOptions.fetch = { headers: preloadOptions.headers };\n }\n this.sourceTileset = await loadFromArchive(tilesetUrl, this.Loader, this.loadOptions);\n const preprocessResult = this.Loader === Tiles3DLoader || analyze ? await this.preprocessConversion() : true;\n if (preprocessResult && !analyze) {\n const selectMetadataClassResult = await this.selectMetadataClass();\n if (selectMetadataClassResult) {\n await this._createAndSaveTileset(outputPath, tilesetName);\n await this._finishConversion({ slpk: Boolean(slpk), outputPath, tilesetName });\n }\n }\n }\n catch (error) {\n throw error;\n }\n finally {\n await this.writeQueue.finalize();\n // Clean up worker pools\n const workerFarm = WorkerFarm.getWorkerFarm({});\n workerFarm.destroy();\n }\n return 'success';\n }\n /**\n * Preprocess stage of the tile converter. Traverse all the tiles tree and\n * check a tile content to be sure that the data is supported\n * @returns true - the conversion is possible, false - the tileset's content is not supported\n */\n async preprocessConversion() {\n // eslint-disable-next-line no-console\n console.log('Analyze source tileset');\n const sourceRootTile = this.sourceTileset.root;\n await traverseDatasetWith({\n tile: sourceRootTile,\n traversalProps: null,\n processTile: this.analyzeTile.bind(this),\n postprocessTile: undefined,\n maxDepth: this.options.maxDepth\n });\n const { meshTopologyTypes, metadataClasses } = this.preprocessData;\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n // eslint-disable-next-line no-console\n console.log('Preprocess results:');\n // eslint-disable-next-line no-console\n console.log(`Tile count: ${this.progresses[PROGRESS_PHASE1_COUNT].stepsTotal}`);\n // eslint-disable-next-line no-console\n console.log(`glTF mesh topology types: ${Array.from(meshTopologyTypes).join(', ')}`);\n if (metadataClasses.size) {\n // eslint-disable-next-line no-console\n console.log(`Feature metadata classes have been found: ${Array.from(metadataClasses).join(', ')}`);\n }\n else {\n // eslint-disable-next-line no-console\n console.log('Feature metadata classes have not been found');\n }\n if (!meshTopologyTypes.has(GLTFPrimitiveModeString.TRIANGLES) &&\n !meshTopologyTypes.has(GLTFPrimitiveModeString.TRIANGLE_STRIP)) {\n // eslint-disable-next-line no-console\n console.log('The tileset is of unsupported mesh topology types. The conversion will be interrupted.');\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n return false;\n }\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n return true;\n }\n /**\n * Analyze a tile content. The callback for preprocess stage.\n * @param sourceTile - 3DTiles tile JSON metadata\n * @param traversalProps - mandatory argument but it is not used for the preprocess stage\n * @returns - nothing\n */\n async analyzeTile(sourceTile, traversalProps) {\n const isTileset = isNestedTileset(sourceTile);\n if (isTileset) {\n await loadNestedTileset(this.sourceTileset, sourceTile, this.loadOptions);\n return null;\n }\n if (sourceTile.id) {\n this.progresses[PROGRESS_PHASE1_COUNT].stepsTotal += 1;\n console.log(`[analyze]: ${sourceTile.id}`); // eslint-disable-line\n }\n let tileContent = null;\n try {\n tileContent = await loadTile3DContent(this.sourceTileset, sourceTile, {\n ...this.loadOptions,\n '3d-tiles': { ...this.loadOptions['3d-tiles'], loadGLTF: false }\n });\n }\n catch (error) {\n // eslint-disable-next-line no-console\n console.log(`[warning]: Failed to load ${sourceTile.contentUrl}. An I3S tile with empty content will be added to the output tileset`);\n }\n const tilePreprocessData = await analyzeTileContent(tileContent);\n mergePreprocessData(this.preprocessData, tilePreprocessData);\n return null;\n }\n /**\n * Select metadata class associated with the set of feature attributes\n * @returns true if the metadata class has been successfully selected\n */\n async selectMetadataClass() {\n const { metadataClasses } = this.preprocessData;\n if (metadataClasses.size > 1) {\n if (this.options.metadataClass?.length) {\n // eslint-disable-next-line no-console\n console.log(`${this.options.metadataClass} has been selected`);\n }\n else if (this.options.inquirer) {\n const result = await this.options.inquirer.prompt([\n {\n name: 'metadataClass',\n type: 'list',\n message: 'Select feature metadata data class to convert...',\n choices: Array.from(metadataClasses)\n }\n ]);\n this.options.metadataClass = result.metadataClass;\n // eslint-disable-next-line no-console\n console.log(`${result.metadataClass} has been selected`);\n }\n else {\n // eslint-disable-next-line no-console\n console.log(`A feature metadata class has not been selected. Start the converter with option \"--metadata-class\". For example, \"npx tile-converter ... --metadata-class ${Array.from(metadataClasses)[0]}\"`);\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n return false;\n }\n }\n return true;\n }\n /**\n * Convert and save the layer and embedded tiles\n * @param outputPath - path to save output data\n * @param tilesetName - new tileset path\n */\n // eslint-disable-next-line max-statements, complexity\n async _createAndSaveTileset(outputPath, tilesetName) {\n const tilesetPath = join(`${outputPath}`, `${tilesetName}`);\n await this.conversionDump.createDump(this.options);\n if (this.conversionDump.restored && this.options.inquirer) {\n const result = await this.options.inquirer.prompt([\n {\n name: 'resumeConversion',\n type: 'confirm',\n message: 'Dump file of the previous conversion exists, do you want to resume that conversion?'\n }\n ]);\n if (!result.resumeConversion) {\n this.conversionDump.reset();\n }\n }\n this.layers0Path = join(tilesetPath, 'SceneServer', 'layers', '0');\n // Removing the tilesetPath needed to exclude erroneous files after conversion\n const removePath = this.conversionDump.restored\n ? join(this.layers0Path, 'nodepages')\n : tilesetPath;\n try {\n await removeDir(removePath);\n }\n catch (e) {\n // do nothing\n }\n if (this.conversionDump.restored && this.conversionDump.attributeMetadataInfo) {\n this.attributeMetadataInfo.fromObject(this.conversionDump.attributeMetadataInfo);\n }\n this.materialDefinitions = [];\n this.materialMap = new Map();\n if (this.conversionDump.restored && this.conversionDump.materialDefinitions) {\n for (let i = 0; i < this.conversionDump.materialDefinitions.length; i++) {\n const hash = md5(JSON.stringify(this.conversionDump.materialDefinitions[i]));\n this.materialMap.set(hash, i);\n }\n this.materialDefinitions = this.conversionDump.materialDefinitions;\n }\n const sourceRootTile = this.sourceTileset.root;\n const sourceBoundingVolume = createBoundingVolume(sourceRootTile.boundingVolume, new Matrix4(sourceRootTile.transform), null);\n this._formLayers0(tilesetName, sourceBoundingVolume, this.sourceTileset?.root?.boundingVolume?.region);\n const boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);\n await this.nodePages.push({\n index: 0,\n lodThreshold: 0,\n obb: boundingVolumes.obb,\n children: []\n });\n this.progresses[PROGRESS_PHASE1_COUNT].startMonitoring();\n const rootNode = await NodeIndexDocument.createRootNode(boundingVolumes, this);\n await traverseDatasetWith({\n tile: sourceRootTile,\n traversalProps: {\n transform: new Matrix4(sourceRootTile.transform),\n parentNodes: [rootNode]\n },\n processTile: this.convertTile.bind(this),\n postprocessTile: this.finalizeTile.bind(this),\n maxDepth: this.options.maxDepth\n });\n this.progresses[PROGRESS_PHASE1_COUNT].stopMonitoring();\n console.log(`[finalizing conversion]`); // eslint-disable-line\n this.layers0.attributeStorageInfo = this.attributeMetadataInfo.attributeStorageInfo;\n this.layers0.fields = this.attributeMetadataInfo.fields;\n this.layers0.popupInfo = this.attributeMetadataInfo.popupInfo;\n if (this.attributeMetadataInfo.attributeStorageInfo.length) {\n this.layers0.layerType = _3D_OBJECT_LAYER_TYPE;\n }\n if (this.conversionDump.restored && this.conversionDump.textureSetDefinitions) {\n this.layers0.textureSetDefinitions = this.conversionDump.textureSetDefinitions;\n }\n this.layers0.materialDefinitions = this.materialDefinitions;\n // @ts-ignore\n this.layers0.geometryDefinitions = transform(this.geometryConfigs.map((config) => ({\n geometryConfig: { ...config, draco: this.options.draco }\n })), geometryDefinitionTemlate());\n if (this.layersHasTexture === false) {\n this.layers0.store.defaultGeometrySchema.ordering =\n this.layers0.store.defaultGeometrySchema.ordering.filter((attribute) => attribute !== 'uv0');\n }\n await this._writeLayers0();\n createSceneServerPath(tilesetName, this.layers0, tilesetPath);\n for (const filePath of this.compressList || []) {\n await compressFileWithGzip(filePath);\n await removeFile(filePath);\n }\n await this.nodePages.save();\n await this.writeQueue.finalize();\n await this._createSlpk(tilesetPath);\n }\n /**\n * Form object of 3DSceneLayer https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DSceneLayer.cmn.md\n * @param tilesetName - Name of layer\n * @param sourceBoundingVolume - initialized bounding volume of the source root tile\n * @param boundingVolumeRegion - region bounding volume of the source root tile\n */\n _formLayers0(tilesetName, sourceBoundingVolume, boundingVolumeRegion) {\n if (!this.sourceTileset?.root) {\n return;\n }\n const fullExtent = convertBoundingVolumeToI3SFullExtent(sourceBoundingVolume);\n if (boundingVolumeRegion) {\n fullExtent.zmin = boundingVolumeRegion[4];\n fullExtent.zmax = boundingVolumeRegion[5];\n }\n const extent = [fullExtent.xmin, fullExtent.ymin, fullExtent.xmax, fullExtent.ymax];\n const layers0data = {\n version: `{${uuidv4().toUpperCase()}}`,\n id: 0,\n name: tilesetName,\n href: './layers/0',\n store: {\n id: `{${uuidv4().toUpperCase()}}`,\n extent\n },\n nodePages: {\n nodesPerPage: HARDCODED_NODES_PER_PAGE\n },\n compressGeometry: this.options.draco,\n fullExtent\n };\n this.layers0 = transform(layers0data, layersTemplate());\n }\n /**\n * Write 3DSceneLayer https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DSceneLayer.cmn.md in file\n */\n async _writeLayers0() {\n if (this.options.slpk) {\n await this.writeQueue.enqueue({\n archiveKey: '3dSceneLayer.json.gz',\n writePromise: () => writeFileForSlpk(this.layers0Path, JSON.stringify(this.layers0), '3dSceneLayer.json')\n });\n }\n else {\n await this.writeQueue.enqueue({\n writePromise: () => writeFile(this.layers0Path, JSON.stringify(this.layers0))\n });\n }\n }\n /**\n * Pack files into *.slpk archive\n * @param tilesetPath - Path to save file\n */\n async _createSlpk(tilesetPath) {\n await this.conversionDump.deleteDumpFile();\n if (this.options.slpk) {\n const slpkTilesetPath = join(tilesetPath, 'SceneServer', 'layers', '0');\n const slpkFileName = `${tilesetPath}.slpk`;\n await createZip(slpkTilesetPath, slpkFileName, async (fileList) => ({\n path: '@specialIndexFileHASH128@',\n file: await composeHashFile(fileList)\n }));\n try {\n await removeDir(tilesetPath);\n }\n catch (e) {\n // do nothing\n }\n }\n }\n /**\n * Convert the specific 3DTiles tile to I3S nodes.\n * This is callback function for the traversal generic function\n * @param sourceTile - current 3DTiles tile JSON metadata\n * @param traversalProps - traversal properties calculated recursively\n * @returns - traversal properties for the child tiles\n */\n // eslint-disable-next-line max-statements\n async convertTile(sourceTile, traversalProps) {\n const isTileset = isNestedTileset(sourceTile);\n if (isTileset || sourceTile.type === 'empty') {\n if (isTileset) {\n if (sourceTile.id) {\n console.log(`[load]: ${sourceTile.id}`); // eslint-disable-line\n }\n await loadNestedTileset(this.sourceTileset, sourceTile, this.loadOptions);\n }\n return traversalProps;\n }\n if (sourceTile.id) {\n console.log(`[convert]: ${sourceTile.id}`); // eslint-disable-line\n }\n const { parentNodes, transform } = traversalProps;\n let transformationMatrix = transform.clone();\n if (sourceTile.transform) {\n transformationMatrix = transformationMatrix.multiplyRight(sourceTile.transform);\n }\n const parentNode = parentNodes[0];\n const restoreResult = await this._restoreNode(parentNode, sourceTile, transformationMatrix);\n let childNodes;\n if (restoreResult === null) {\n childNodes = await this._createNode(parentNode, sourceTile, transformationMatrix);\n }\n else {\n childNodes = restoreResult;\n }\n await parentNode.addChildren(childNodes);\n const newTraversalProps = {\n transform: transformationMatrix,\n parentNodes: childNodes\n };\n if (sourceTile.id) {\n this.progresses[PROGRESS_PHASE1_COUNT].stepsDone += 1;\n let timeRemainingString = 'Calculating time left...';\n const timeRemainingStringBasedOnCount = this.progresses[PROGRESS_PHASE1_COUNT].getTimeRemainingString();\n if (timeRemainingStringBasedOnCount) {\n timeRemainingString = `${timeRemainingStringBasedOnCount} left`;\n }\n const percentString = this.progresses[PROGRESS_PHASE1_COUNT].getPercentString();\n const progressString = percentString ? ` ${percentString}%, ${timeRemainingString}` : '';\n console.log(`[converted${progressString}]: ${sourceTile.id}`); // eslint-disable-line\n }\n return newTraversalProps;\n }\n /**\n * Do final action with nodes after the current node and all child nodes been converted.\n * @param conversionResults - array of conversion results of the current node\n * @param currentTraversalProps - traversal properties of the current node\n */\n async finalizeTile(conversionResults, currentTraversalProps) {\n for (const result of conversionResults) {\n for (const node of result.parentNodes) {\n await node.addNeighbors();\n }\n }\n for (const node of currentTraversalProps.parentNodes) {\n await node.save();\n }\n }\n /**\n * Generate NodeIndexDocument\n * @param boundingVolumes - Bounding volumes\n * @param resources - converted or dumped node resources data\n * @param parentNode - 3DNodeIndexDocument of parent node\n * @param sourceTile - source 3DTile data\n * @param isDumped - indicator if the node is dumped\n * @return NodeIndexDocument, nodeInPage and node data\n */\n async _generateNodeIndexDocument(boundingVolumes, resources, parentNode, sourceTile, isDumped) {\n this.layersHasTexture =\n this.layersHasTexture ||\n Boolean(('texture' in resources && resources.texture) ||\n ('texelCountHint' in resources && resources.texelCountHint));\n if (this.generateBoundingVolumes && resources.boundingVolumes) {\n boundingVolumes = resources.boundingVolumes;\n }\n const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);\n const maxScreenThresholdSQ = lodSelection.find((val) => val.metricType === 'maxScreenThresholdSQ') || { maxError: 0 };\n if (isDumped) {\n const draftObb = {\n center: [],\n halfSize: [],\n quaternion: []\n };\n await this.nodePages.push({ index: 0, obb: draftObb }, parentNode.inPageId);\n }\n const nodeInPage = await this._updateNodeInNodePages(maxScreenThresholdSQ, boundingVolumes, sourceTile, parentNode.inPageId, resources);\n const nodeData = await NodeIndexDocument.createNodeIndexDocument(parentNode, boundingVolumes, lodSelection, nodeInPage, resources);\n const node = await new NodeIndexDocument(nodeInPage.index, this).addData(nodeData);\n return { node, nodeInPage, nodeData };\n }\n /**\n * Restore 3DNodeIndexDocument from a comversion dump file\n * @param parentNode - 3DNodeIndexDocument of parent node\n * @param sourceTile - source 3DTile data\n * @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n */\n async _restoreNode(parentNode, sourceTile, transformationMatrix) {\n this._checkAddRefinementTypeForTile(sourceTile);\n await this._updateTilesetOptions();\n if (this.conversionDump.restored &&\n sourceTile.id &&\n this.conversionDump.isFileConversionComplete(sourceTile.id)) {\n const sourceBoundingVolume = createBoundingVolume(sourceTile.boundingVolume, transformationMatrix, null);\n const boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);\n const nodes = [];\n for (const convertedNode of this.conversionDump.tilesConverted[sourceTile.id].nodes) {\n const { node } = await this._generateNodeIndexDocument(boundingVolumes, {\n ...convertedNode.dumpMetadata,\n nodeId: convertedNode.nodeId\n }, parentNode, sourceTile, true);\n nodes.push(node);\n }\n return nodes;\n }\n else if (this.conversionDump.restored && sourceTile.id) {\n // clear existing record in a dump\n this.conversionDump.clearDumpRecord(sourceTile.id);\n }\n return null;\n }\n /**\n * Convert tile to one or more I3S nodes\n * @param parentNode - 3DNodeIndexDocument of parent node\n * @param sourceTile - source 3DTile data\n * @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n * @param level - tree level\n */\n // eslint-disable-next-line max-statements\n async _createNode(parentNode, sourceTile, transformationMatrix) {\n this._checkAddRefinementTypeForTile(sourceTile);\n await this._updateTilesetOptions();\n let tileContent = null;\n try {\n tileContent = await loadTile3DContent(this.sourceTileset, sourceTile, this.loadOptions);\n }\n catch (error) {\n // eslint-disable-next-line no-console\n console.log(`[warning]: Failed to load ${sourceTile.contentUrl}`);\n }\n const sourceBoundingVolume = createBoundingVolume(sourceTile.boundingVolume, transformationMatrix, null);\n const boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);\n const propertyTable = getPropertyTable(tileContent, this.options.metadataClass);\n this.createAttributeStorageInfo(tileContent, propertyTable);\n this.conversionDump.attributeMetadataInfo = {\n attributeStorageInfo: this.attributeMetadataInfo.attributeStorageInfo,\n fields: this.attributeMetadataInfo.fields,\n popupInfo: this.attributeMetadataInfo.popupInfo\n };\n const resourcesData = await this._convertResources({\n sourceTile,\n transformationMatrix,\n boundingVolume: sourceBoundingVolume,\n tileContent,\n parentId: parentNode.inPageId,\n propertyTable\n });\n const nodes = [];\n const nodeIds = [];\n const nodesInPage = [];\n const emptyResources = {\n geometry: null,\n compressedGeometry: null,\n texture: null,\n hasUvRegions: false,\n sharedResources: null,\n meshMaterial: null,\n vertexCount: null,\n attributes: null,\n featureCount: null,\n boundingVolumes: null\n };\n for (const resources of resourcesData || [emptyResources]) {\n const { node, nodeInPage, nodeData } = await this._generateNodeIndexDocument(boundingVolumes, resources, parentNode, sourceTile, false);\n nodes.push(node);\n if (nodeInPage.mesh) {\n // update a record in a dump file\n if (sourceTile.id) {\n const dumpMetadata = {\n boundingVolumes: resources.boundingVolumes,\n attributesCount: resources.attributes?.length,\n featureCount: resources.featureCount,\n geometry: Boolean(resources.geometry),\n hasUvRegions: resources.hasUvRegions,\n materialId: nodeInPage.mesh.material.definition,\n texelCountHint: nodeInPage.mesh.material.texelCountHint,\n vertexCount: resources.vertexCount\n };\n this.conversionDump.setMaterialsDefinitions(this.materialDefinitions);\n await this.conversionDump.addNode(sourceTile.id, nodeInPage.index, dumpMetadata);\n }\n // write resources\n await this._writeResources(resources, node.id, sourceTile);\n }\n if (this.validate) {\n this.boundingVolumeWarnings = validateNodeBoundingVolumes(nodeData);\n if (this.boundingVolumeWarnings && this.boundingVolumeWarnings.length) {\n console.warn('Bounding Volume Warnings: ', ...this.boundingVolumeWarnings); //eslint-disable-line\n }\n }\n nodeIds.push(nodeInPage.index);\n nodesInPage.push(nodeInPage);\n }\n return nodes;\n }\n /**\n * Convert tile to one or more I3S nodes\n * @param sourceTile - source tile (3DTile)\n * @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n * @param boundingVolume - initialized bounding volume of the source tile\n * @param tileContent - content of the source tile\n * @param parentId - id of parent node in node pages\n * @param propertyTable - batch table from b3dm / feature properties from EXT_FEATURE_METADATA, EXT_MESH_FEATURES or EXT_STRUCTURAL_METADATA\n * @returns - converted node resources\n */\n async _convertResources({ sourceTile, transformationMatrix, boundingVolume, tileContent, parentId, propertyTable }) {\n if (!this.isContentSupported(sourceTile) || !tileContent) {\n return null;\n }\n const draftObb = {\n center: [],\n halfSize: [],\n quaternion: []\n };\n const resourcesData = await convertB3dmToI3sGeometry({\n tileContent,\n tileTransform: transformationMatrix,\n tileBoundingVolume: boundingVolume,\n addNodeToNodePage: async () => (await this.nodePages.push({ index: 0, obb: draftObb }, parentId)).index,\n propertyTable,\n featuresHashArray: this.featuresHashArray,\n attributeStorageInfo: this.attributeMetadataInfo.attributeStorageInfo,\n draco: this.options.draco,\n generateBoundingVolumes: this.generateBoundingVolumes,\n shouldMergeMaterials: this.options.mergeMaterials,\n geoidHeightModel: this.geoidHeightModel,\n libraries: this.loadOptions.modules,\n metadataClass: this.options.metadataClass\n });\n return resourcesData;\n }\n /**\n * Update node object (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/node.cmn.md)\n * in node pages (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/nodePage.cmn.md)\n * @param maxScreenThresholdSQ - Level of Details (LOD) metric\n * @param boundingVolumes - Bounding volumes\n * @param sourceTile - source tile (3DTile)\n * @param parentId - id of parent node in node pages\n * @param resources - the node resources data\n * @param resources.meshMaterial - PBR-like material object\n * @param resources.texture - texture image\n * @param resources.vertexCount - number of vertices in geometry\n * @param resources.featureCount - number of features\n * @param resources.geometry - Uint8Array with geometry attributes\n * @return the node object in node pages\n */\n // eslint-disable-next-line max-statements, complexity\n async _updateNodeInNodePages(maxScreenThresholdSQ, boundingVolumes, sourceTile, parentId, resources) {\n const { vertexCount, featureCount, geometry, hasUvRegions } = resources;\n const nodeInPage = {\n index: 0,\n lodThreshold: maxScreenThresholdSQ.maxError,\n obb: boundingVolumes.obb,\n children: []\n };\n if (geometry && this.isContentSupported(sourceTile)) {\n nodeInPage.mesh = {\n geometry: {\n definition: this.findOrCreateGeometryDefinition(Boolean(('texture' in resources && resources.texture) ||\n ('texelCountHint' in resources && resources.texelCountHint)), hasUvRegions),\n resource: 0\n },\n attribute: {\n resource: 0\n },\n material: {\n definition: 0\n }\n };\n }\n const nodeId = 'nodeId' in resources ? resources.nodeId : undefined;\n let node;\n if (!nodeId) {\n node = await this.nodePages.push(nodeInPage, parentId);\n }\n else {\n node = await this.nodePages.getNodeById(nodeId);\n }\n if (!nodeInPage.mesh) {\n // eslint-disable-next-line no-console\n console.log(`[warning]: node ${node.index} is created with empty content`);\n }\n NodePages.updateAll(node, nodeInPage);\n if ('meshMaterial' in resources && resources.meshMaterial) {\n NodePages.updateMaterialByNodeId(node, this._findOrCreateMaterial(resources.meshMaterial));\n }\n else if ('materialId' in resources && resources.materialId !== null) {\n NodePages.updateMaterialByNodeId(node, resources.materialId);\n }\n if ('texture' in resources && resources.texture) {\n const texelCountHint = resources.texture.image.height * resources.texture.image.width;\n NodePages.updateTexelCountHintByNodeId(node, texelCountHint);\n }\n else if ('texelCountHint' in resources && resources.texelCountHint) {\n NodePages.updateTexelCountHintByNodeId(node, resources.texelCountHint);\n }\n if (vertexCount) {\n this.vertexCounter += vertexCount;\n NodePages.updateVertexCountByNodeId(node, vertexCount);\n }\n NodePages.updateNodeAttributeByNodeId(node);\n if (featureCount) {\n NodePages.updateFeatureCountByNodeId(node, featureCount);\n }\n this.nodePages.saveNode(node);\n return node;\n }\n /**\n * Write node resources in files\n * @param resources - source tile (3DTile)\n * @param resources.geometry - Uint8Array with geometry attributes\n * @param resources.compressedGeometry - Uint8Array with compressed (draco) geometry\n * @param resources.texture - texture image\n * @param resources.sharedResources - shared resource data object\n * @param resources.attributes - feature attributes\n * @param nodePath - node path\n * @param sourceTile - source tile (3DTile)\n * @return {Promise<void>}\n */\n async _writeResources(resources, nodePath, sourceTile) {\n const { geometry: geometryBuffer, compressedGeometry, texture, sharedResources, attributes } = resources;\n const childPath = join(this.layers0Path, 'nodes', nodePath);\n const slpkChildPath = join('nodes', nodePath);\n await this._writeGeometries({\n geometryBuffer,\n compressedGeometry,\n childPath,\n slpkChildPath,\n sourceId: sourceTile.id || '',\n nodeId: parseInt(nodePath)\n });\n await this._writeShared({\n sharedResources,\n childPath,\n slpkChildPath,\n nodePath,\n sourceId: sourceTile.id || '',\n nodeId: parseInt(nodePath)\n });\n await this._writeTexture(texture, childPath, slpkChildPath, sourceTile.id || '', parseInt(nodePath));\n await this._writeAttributes(attributes, childPath, slpkChildPath, sourceTile.id || '', parseInt(nodePath));\n }\n /**\n * Write non-compressed and compressed geometries in files\n * @param geometryBuffer - Uint8Array with geometry attributes\n * @param compressedGeometry - Uint8Array with compressed (draco) geometry\n * @param childPath - a child path to write resources\n * @param slpkChildPath - resource path inside *slpk file\n * @param sourceId - source filename\n * @param nodeId - nodeId of a converted node for the writing\n */\n async _writeGeometries({ geometryBuffer, compressedGeometry, childPath, slpkChildPath, sourceId, nodeId }) {\n if (!geometryBuffer) {\n return;\n }\n this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.GEOMETRY, false);\n if (this.options.slpk) {\n const slpkGeometryPath = join(childPath, 'geometries');\n await this.writeQueue.enqueue({\n archiveKey: `${slpkChildPath}/geometries/0.bin.gz`,\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.GEOMETRY,\n writePromise: () => writeFileForSlpk(slpkGeometryPath, geometryBuffer, '0.bin')\n });\n }\n else {\n const geometryPath = join(childPath, 'geometries/0/');\n await this.writeQueue.enqueue({\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.GEOMETRY,\n writePromise: () => writeFile(geometryPath, geometryBuffer, 'index.bin')\n });\n }\n if (this.options.draco && compressedGeometry) {\n this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.DRACO_GEOMETRY, false);\n if (this.options.slpk) {\n const slpkCompressedGeometryPath = join(childPath, 'geometries');\n await this.writeQueue.enqueue({\n archiveKey: `${slpkChildPath}/geometries/1.bin.gz`,\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.DRACO_GEOMETRY,\n writePromise: () => writeFileForSlpk(slpkCompressedGeometryPath, compressedGeometry, '1.bin')\n });\n }\n else {\n const compressedGeometryPath = join(childPath, 'geometries/1/');\n await this.writeQueue.enqueue({\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.DRACO_GEOMETRY,\n writePromise: () => writeFile(compressedGeometryPath, compressedGeometry, 'index.bin')\n });\n }\n }\n }\n /**\n * Write shared resources in a file\n * @param sharedResources - shared resource data object\n * @param childPath - a child path to write resources\n * @param slpkChildPath - resource path inside *slpk file\n * @param nodePath - a node path\n * @param sourceId - source filename\n * @param nodeId - nodeId of a converted node for the writing\n */\n async _writeShared({ sharedResources, childPath, slpkChildPath, nodePath, sourceId, nodeId }) {\n if (!sharedResources) {\n return;\n }\n sharedResources.nodePath = nodePath;\n const sharedData = transform(sharedResources, sharedResourcesTemplate());\n const sharedDataStr = JSON.stringify(sharedData);\n this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.SHARED, false);\n if (this.options.slpk) {\n const slpkSharedPath = join(childPath, 'shared');\n await this.writeQueue.enqueue({\n archiveKey: `${slpkChildPath}/shared/sharedResource.json.gz`,\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.SHARED,\n writePromise: () => writeFileForSlpk(slpkSharedPath, sharedDataStr, 'sharedResource.json')\n });\n }\n else {\n const sharedPath = join(childPath, 'shared/');\n await this.writeQueue.enqueue({\n sourceId,\n outputId: nodeId,\n resourceType: ResourceType.SHARED,\n writePromise: () => writeFile(sharedPath, sharedDataStr)\n });\n }\n }\n /**\n * Generates textures based on texture mime type and fill in textureSetDefinitions data.\n * @param texture - the texture image\n * @param childPath - a child path to write resources\n * @param slpkChildPath - the resource path inside *slpk file\n * @param sourceId - source filename\n * @param nodeId - nodeId of a converted node for the writing\n */\n // eslint-disable-next-line max-statements\n async _writeTexture(texture, childPath, slpkChildPath, sourceId, nodeId) {\n if (texture) {\n const format = this._getFormatByMimeType(texture?.mimeType);\n const formats = [];\n const textureData = texture.bufferView.data;\n switch (format) {\n case 'jpg':\n case 'png': {\n formats.push({ name: '0', format });\n this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/${format}`, false);\n await this.writeTextureFile({\n textureData,\n name: '0',\n format,\n childPath,\n slpkChildPath,\n sourceId,\n nodeId\n });\n if (this.generateTextures) {\n formats.push({ name: '1', format: 'ktx2' });\n // For Node.js texture.image.data is type of Buffer\n const copyArrayBuffer = texture.image.data.subarray();\n const arrayToEncode = new Uint8Array(copyArrayBuffer);\n const ktx2TextureData = encode({ ...texture.image, data: arrayToEncode }, \n // @ts-expect-error - Worker encoder typing is still WIP\n KTX2BasisWriterWorker, {\n ...KTX2BasisWriterWorker.options,\n ['ktx2-basis-writer']: {\n // We need to load local fs workers because nodejs can't load workers from the Internet\n workerUrl: './modules/textures/dist/ktx2-basis-writer-worker-node.js'\n },\n reuseWorkers: true,\n _nodeWorkers: true,\n useLocalLibraries: true\n });\n this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/ktx2`, false);\n await this.writeTextureFile({\n textureData: ktx2TextureData,\n name: '1',\n format: 'ktx2',\n childPath,\n slpkChildPath,\n sourceId,\n nodeId\n });\n }\n break;\n }\n case 'ktx2': {\n formats.push({ name: '1', format });\n this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/${format}`, false);\n await this.writeTextureFile({\n textureData,\n name: '1',\n format,\n childPath,\n slpkChildPath,\n sourceId,\n nodeId\n });\n if (this.generateTextures) {\n formats.push({ name: '0', format: 'jpg' });\n const decodedFromKTX2TextureData = encode(texture.image.data[0], ImageWriter);\n this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/jpg`, false);\n await this.writeTextureFile({\n textureData: decodedFromKTX2TextureData,\n name: '0',\n format: 'jpg',\n childPath,\n slpkChildPath,\n sourceId,\n nodeId\n });\n }\n break;\n }\n default:\n }\n if (!this.layers0.textureSetDefinitions.length) {\n this.layers0.textureSetDefinitions.push({ formats });\n this.layers0.textureSetDefinitions.push({ formats, atlas: true });\n if (this.layers0.textureSetDefinitions) {\n this.conversionDump.addTexturesDefinitions(this.layers0.textureSetDefinitions);\n }\n }\n }\n }\n /**\n * Write the texture image in a file\n * @param textureData\n * @param name\n * @param format\n * @param childPath\n * @param slpkChildPath\n * @param sourceId\n * @param nodeId\n */\n async writeTextureFile({ textureData, name, format, childPath, slpkChildPath, sourceId, nodeId }) {\n if (this.options.slpk) {\n const slpkTexturePath = join(childPath, 'textures');\n const compress = false;\n await this.writeQueue.enqueue({\n archiveKey: `${slpkChildPath}/textures/${name}.${format}`,\n sourceId,\n outputId: nodeId,\n resourceType: `${ResourceType.TEXTURE}/${format}`,\n writePromise: () => writeFileForSlpk(slpkTexturePath, textureData, `${name}.${format}`, compress)\n });\n }\n else {\n const texturePath = join(childPath, `textures/${name}/`);\n await this.writeQueue.enqueue({\n sourceId,\n outputId: nodeId,\n resourceType: `${ResourceType.TEXTURE}/${format}`,\n writePromise: () => writeFile(texturePath, textureData, `index.${format}`)\n });\n }\n }\n /**\n * Write feature attributes in files\n * @param attributes - feature attributes\n * @param childPath - a child path to write resources\n * @param slpkChildPath - the resource path inside *slpk file\n * @param sourceId - source filename\n * @param nodeId - nodeId of a converted node for the writing\n */\n async _writeAttributes(attributes = [], childPath, slpkChildPath, sourceId, nodeId) {\n if (attributes?.length && this.attributeMetadataInfo.attributeStorageInfo.length) {\n const minimumLength = attributes.length < this.attributeMetadataInfo.attributeStorageInfo.length\n ? attributes.length\n : this.attributeMetadataInfo.attributeStorageInfo.length;\n for (let index = 0; index < minimumLength; index++) {\n const folderName = this.attributeMetadataInfo.attributeStorageInfo[index].key;\n const fileBuffer = new Uint8Array(attributes[index]);\n this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.ATTRIBUTES}/${folderName}`, false);\n if (this.options.slpk) {\n const slpkAttributesPath = join(childPath, 'attributes', folderName);\n await this.writeQueue.enqueue({\n archiveKey: `${slpkChildPath}/attributes/${folderName}.bin.gz`,\n sourceId,\n outputId: nodeId,\n resourceType: `${ResourceType.ATTRIBUTES}/${folderName}`,\n writePromise: () => writeFileForSlpk(slpkAttributesPath, fileBuffer, '0.bin')\n });\n }\n else {\n const attributesPath = join(childPath, `attributes/${folderName}/0`);\n await this.writeQueue.enqueue({\n sourceId,\n outputId: nodeId,\n resourceType: `${ResourceType.ATTRIBUTES}/${folderName}`,\n writePromise: () => writeFile(attributesPath, fileBuffer, 'index.bin')\n });\n }\n }\n }\n }\n /**\n * Return file format by its MIME type\n * @param mimeType - feature attributes\n */\n _getFormatByMimeType(mimeType) {\n switch (mimeType) {\n case 'image/jpeg':\n return 'jpg';\n case 'image/png':\n return 'png';\n case 'image/ktx2':\n return 'ktx2';\n default:\n return 'jpg';\n }\n }\n /**\n * Find or create material in materialDefinitions array\n * @param material - end-to-end index of the node\n * @return material id\n */\n _findOrCreateMaterial(material) {\n const hash = md5(JSON.stringify(material));\n if (this.materialMap.has(hash)) {\n return this.materialMap.get(hash) || 0;\n }\n const newMaterialId = this.materialDefinitions.push(material) - 1;\n this.materialMap.set(hash, newMaterialId);\n return newMaterialId;\n }\n /**\n * Get unique geometry configuration index\n * In the end of conversion configurations will be transformed to geometryDefinitions array\n * @param hasTexture\n * @param hasUvRegions\n * @returns\n */\n findOrCreateGeometryDefinition(hasTexture, hasUvRegions) {\n const geometryConfig = { hasTexture, hasUvRegions };\n const hash = md5(JSON.stringify(geometryConfig));\n if (this.geometryMap.has(hash)) {\n return this.geometryMap.get(hash) || 0;\n }\n const newGeometryId = this.geometryConfigs.push(geometryConfig) - 1;\n this.geometryMap.set(hash, newGeometryId);\n return newGeometryId;\n }\n /**\n * Creates attribute storage info based on either extension schema or property table.\n * @param tileContent - content of the source tile\n * @param propertyTable - feature properties from EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA\n */\n createAttributeStorageInfo(tileContent, propertyTable) {\n /*\n In case the tileset doesn't have either EXT_structural_metadata or EXT_feature_metadata\n that can be a source of attribute information so metadataClass is not specified\n we will collect attribute information for node attributes from the property table\n taken from each tile.\n */\n let attributeTypesMap = null;\n if (this.options.metadataClass) {\n if (!this.attributeMetadataInfo.attributeStorageInfo.length && tileContent?.gltf) {\n attributeTypesMap = getAttributeTypesMapFromSchema(tileContent.gltf, this.options.metadataClass);\n }\n }\n else if (propertyTable) {\n attributeTypesMap = getAttributeTypesMapFromPropertyTable(propertyTable);\n }\n if (attributeTypesMap) {\n // Add new storage attributes, fields and create popupInfo\n this.attributeMetadataInfo.addMetadataInfo(attributeTypesMap);\n }\n }\n /**\n * Print statistics in the end of conversion\n * @param params - output files data\n */\n async _finishConversion(params) {\n const { tilesCount, tilesWithAddRefineCount } = this.refinementCounter;\n const addRefinementPercentage = tilesWithAddRefineCount\n ? (tilesWithAddRefineCount / tilesCount) * 100\n : 0;\n const filesSize = await calculateFilesSize(params);\n const diff = process.hrtime(this.conversionStartTime);\n const conversionTime = timeConverter(diff);\n console.log('------------------------------------------------'); // eslint-disable-line no-undef, no-console\n console.log(`Finishing conversion of ${_3D_TILES}`); // eslint-disable-line no-undef, no-console\n console.log(`Total conversion time: ${conversionTime}`); // eslint-disable-line no-undef, no-console\n console.log('Vertex count: ', this.vertexCounter); // eslint-disable-line no-undef, no-console\n console.log('File(s) size: ', filesSize, ' bytes'); // eslint-disable-line no-undef, no-console\n console.log('Percentage of tiles with \"ADD\" refinement type:', addRefinementPercentage, '%'); // eslint-disable-line no-undef, no-console\n console.log('------------------------------------------------'); // eslint-disable-line no-undef, no-console\n }\n /**\n * Fetch preload options for ION tileset\n */\n async _fetchPreloadOptions() {\n if (!this.Loader.preload) {\n return {};\n }\n const options = {\n 'cesium-ion': { accessToken: this.options.token || ION_DEFAULT_TOKEN }\n };\n const preloadOptions = await this.Loader.preload(this.options.inputUrl, options);\n this.refreshTokenTime = process.hrtime();\n return { ...options, ...preloadOptions };\n }\n /**\n * Update options of source tileset\n */\n async _updateTilesetOptions() {\n const diff = process.hrtime(this.refreshTokenTime);\n if (diff[0] < REFRESH_TOKEN_TIMEOUT) {\n return;\n }\n this.refreshTokenTime = process.hrtime();\n const preloadOptions = await this._fetchPreloadOptions();\n if (preloadOptions.headers) {\n this.loadOptions.fetch = {\n ...this.loadOptions.fetch,\n headers: preloadOptions.headers\n };\n console.log('Authorization Bearer token has been updated'); // eslint-disable-line no-undef, no-console\n }\n }\n /** Do calculations of all tiles and tiles with \"ADD\" type of refinement.\n * @param tile\n */\n _checkAddRefinementTypeForTile(tile) {\n const ADD_TILE_REFINEMENT = TILE_REFINEMENT.ADD;\n if (tile.refine === ADD_TILE_REFINEMENT) {\n this.refinementCounter.tilesWithAddRefineCount += 1;\n console.warn('This tile uses \"ADD\" type of refinement'); // eslint-disable-line\n }\n this.refinementCounter.tilesCount += 1;\n }\n /**\n * Check if the tile's content format is supported by the converter\n * @param sourceTile\n * @returns\n */\n isContentSupported(sourceTile) {\n return ['b3dm', 'glTF', 'scenegraph'].includes(sourceTile.type || '');\n }\n}\n", "import { join } from 'path';\nimport transform from 'json-map-transform';\nimport { METADATA as metadataTemplate } from \"../json-templates/metadata.js\";\nimport { isFileExists, openJson } from \"../../lib/utils/file-utils.js\";\n/**\n * class NodePages - wrapper of nodePages array\n *\n * @example\n * import {writeFile} from './helpers/write-file';\n *\n * // create an instance of the class\n * const nodePages = new NodePages(writeFile, HARDCODED_NODES_PER_PAGE);\n * ...\n * // push root node\n * const parent = await nodePages.push({\n lodThreshold: HARDCODED_MAX_SCREEN_THRESHOLD_SQ,\n obb: coordinates.obb,\n children: []\n });\n * ...\n * // push node with parent relation\n * const nodeInPage = {\n lodThreshold: HARDCODED_MAX_SCREEN_THRESHOLD_SQ,\n obb: coordinates.obb,\n children: [],\n mesh: {\n geometry: {\n definition: 0\n }\n }\n };\n * const node = await this.nodePages.push(nodeInPage, parent.index);\n * ...\n * // save all the nodePages in the end of pushing all the nodes\n * await this.nodePages.save(layers0path);\n */\nexport default class NodePages {\n nodesPerPage;\n nodesCounter;\n writeFile;\n converter;\n nodePages;\n length = 0;\n /**\n * @constructs\n * Create a nodePages instance.\n * @param writeFileFunc - function to save one nodePage into a file\n * @param nodesPerPage - length limit for one nodePage. An additional nodePage is created when this limit is met\n */\n constructor(writeFileFunc, nodesPerPage, converter) {\n this.nodesPerPage = nodesPerPage;\n this.nodesCounter = 0;\n // @ts-expect-error\n this.nodePages = [{}];\n this.nodePages[0].nodes = [];\n this.writeFile = writeFileFunc;\n this.converter = converter;\n this.length = 0;\n }\n /**\n * Setup function to save node pages\n * @param func - function which should be used to save node pages\n */\n useWriteFunction(func) {\n this.writeFile = func;\n }\n /**\n * Get file path and file name of the node page with the particular id\n * @param nodePageId - node page id\n * @returns file path and file name\n */\n getNodePageFileName(nodePageId) {\n let filePath;\n let fileName;\n if (this.converter.options.slpk) {\n filePath = join(this.converter.layers0Path, 'nodepages');\n fileName = `${nodePageId.toString()}.json`;\n }\n else {\n filePath = join(this.converter.layers0Path, 'nodepages', nodePageId.toString());\n fileName = 'index.json';\n }\n return { filePath, fileName };\n }\n /**\n * Load node page from a file on the disk\n * @param nodePageId - node page id\n * @returns - node page data\n */\n async loadNodePage(nodePageId) {\n const { filePath, fileName } = this.getNodePageFileName(nodePageId);\n const fullName = join(filePath, fileName);\n if (await isFileExists(fullName)) {\n console.log(`load ${fullName}.`); // eslint-disable-line\n return (await openJson(filePath, fileName));\n }\n return { nodes: [] };\n }\n /**\n * Get nodepage id by node id\n * @param id node id\n * @returns node page id\n */\n getPageIndexByNodeId(id) {\n return Math.floor(id / this.nodesPerPage);\n }\n /**\n * Get node page data by node id\n * @param id node id\n * @returns node page data\n */\n async getPageByNodeId(id) {\n const pageIndex = this.getPageIndexByNodeId(id);\n if (this.converter.options.instantNodeWriting) {\n return await this.loadNodePage(pageIndex);\n }\n return this.nodePages[pageIndex];\n }\n /**\n * Get the node by its end-to-end index\n * @param id - end-to-end index of the node\n * @return the node object\n */\n async getNodeById(id, nodePage) {\n const nodeIndex = id % this.nodesPerPage;\n nodePage = nodePage || (await this.getPageByNodeId(id));\n return nodePage.nodes[nodeIndex];\n }\n /**\n * Add a child id into the parent node.children array\n * @param parentId - end-to-end parent node index\n * @param childId - end-to-end child node index\n */\n async addChildRelation(parentId, childId) {\n if (parentId === null || parentId === undefined) {\n return;\n }\n const parentNode = await this.getNodeById(parentId);\n parentNode.children?.push(childId);\n await this.saveNode(parentNode);\n }\n /**\n * Put new node in nodePages array\n * @param node - node object\n * @param parentId - index of parent node\n * @return\n */\n async push(node, parentId) {\n node.index = this.nodesCounter++;\n if (!this.converter.options.instantNodeWriting) {\n let currentNodePage = this.nodePages[this.nodePages.length - 1];\n if (currentNodePage.nodes.length === this.nodesPerPage) {\n currentNodePage = { nodes: [] };\n this.nodePages.push(currentNodePage);\n }\n currentNodePage.nodes.push(node);\n }\n await this.addChildRelation(parentId, node.index);\n NodePages.updateResourceInMesh(node);\n await this.saveNode(node);\n return node;\n }\n /**\n * Save node to the file on the disk\n * @param node - node data\n */\n async saveNode(node) {\n if (!this.converter.options.instantNodeWriting) {\n return;\n }\n const nodePageIndex = this.getPageIndexByNodeId(node.index);\n const nodePage = await this.getPageByNodeId(node.index);\n const { filePath, fileName } = this.getNodePageFileName(nodePageIndex);\n const nodeToUpdate = await this.getNodeById(node.index, nodePage);\n if (nodeToUpdate) {\n NodePages.updateAll(nodeToUpdate, node);\n }\n else {\n nodePage.nodes.push(node);\n }\n const nodePageStr = JSON.stringify(nodePage);\n if (this.converter.options.slpk) {\n await this.converter.writeQueue.enqueue({\n archiveKey: `nodePages/${nodePageIndex.toString()}.json.gz`,\n writePromise: () => this.writeFile(filePath, nodePageStr, fileName, true, this.converter.compressList)\n }, true);\n }\n else {\n await this.converter.writeQueue.enqueue({\n writePromise: () => this.writeFile(filePath, nodePageStr)\n }, true);\n }\n }\n /**\n * Save metadata file (for slpk only)\n */\n async saveMetadata() {\n const metadata = transform({ nodeCount: this.nodesCounter }, metadataTemplate());\n const compress = false;\n await this.converter.writeQueue.enqueue({\n archiveKey: 'metadata.json',\n writePromise: () => this.writeFile(this.converter.layers0Path, JSON.stringify(metadata), 'metadata.json', compress)\n });\n }\n /**\n * Save all the node pages\n * Run this method when all nodes is pushed in nodePages\n */\n async save() {\n if (this.converter.options.instantNodeWriting) {\n await this.saveMetadata();\n return;\n }\n if (this.converter.options.slpk) {\n for (const [index, nodePage] of this.nodePages.entries()) {\n const nodePageStr = JSON.stringify(nodePage);\n const slpkPath = join(this.converter.layers0Path, 'nodepages');\n await this.converter.writeQueue.enqueue({\n archiveKey: `nodePages/${index.toString()}.json.gz`,\n writePromise: () => this.writeFile(slpkPath, nodePageStr, `${index.toString()}.json`)\n });\n }\n await this.saveMetadata();\n }\n else {\n for (const [index, nodePage] of this.nodePages.entries()) {\n const nodePageStr = JSON.stringify(nodePage);\n const nodePagePath = join(this.converter.layers0Path, 'nodepages', index.toString());\n await this.converter.writeQueue.enqueue({\n writePromise: () => this.writeFile(nodePagePath, nodePageStr)\n });\n }\n }\n }\n /**\n * Update resource index in node.mesh object\n * @param node - node object\n */\n static updateResourceInMesh(node) {\n if (node.mesh && isFinite(node.index)) {\n node.mesh.geometry.resource = node.index;\n }\n }\n /**\n * Update all fields in the node excluding id\n * @param node - node object\n * @param data - NodeInPage data to replace original data\n */\n static updateAll(node, data) {\n Object.assign(node, data, { index: node.index });\n NodePages.updateResourceInMesh(node);\n return node;\n }\n /**\n * Update material in node.mesh object by node id\n * @param id - end-to-end index of the node\n * @param materialId - id from scene layer materialDefinitions\n */\n static updateMaterialByNodeId(node, materialId) {\n if (!node.mesh) {\n return;\n }\n node.mesh.material = {\n definition: materialId,\n resource: node.index\n };\n }\n /**\n * Update vertexCount in node.mesh.geometry object by node id\n * @param id - end-to-end index of the node\n * @param vertexCount - vertex count for particular node\n */\n static updateVertexCountByNodeId(node, vertexCount) {\n if (!node.mesh) {\n return;\n }\n node.mesh.geometry.vertexCount = vertexCount;\n }\n /**\n * Update resource in node.mesh.attribute object by node id\n * @param node - node object\n */\n static updateNodeAttributeByNodeId(node) {\n if (!node.mesh || !node.index) {\n return;\n }\n node.mesh.attribute.resource = node.index;\n }\n /**\n * Update featureCount in node.mesh.geometry object by node id\n * @param node - node object\n * @param featureCount - features count of the node\n */\n static updateFeatureCountByNodeId(node, featureCount) {\n if (!node.mesh) {\n return;\n }\n node.mesh.geometry.featureCount = featureCount;\n }\n /**\n * Update texelCountHint in node.mesh.material object by node id\n * @param node - node object\n * @param texelCountHint - texelCountHint of particular node\n */\n static updateTexelCountHintByNodeId(node, texelCountHint) {\n if (!node.mesh || !node.mesh.material) {\n return;\n }\n node.mesh.material.texelCountHint = texelCountHint;\n }\n}\n", "export const METADATA = () => ({\n folderPattern: {\n path: 'folderPattern',\n default: 'BASIC'\n },\n archiveCompressionType: {\n path: 'archiveCompressionType',\n default: 'STORE'\n },\n resourceCompressionType: {\n path: 'resourceCompressionType',\n default: 'GZIP'\n },\n I3SVersion: {\n path: 'I3SVersion',\n default: '1.8'\n },\n nodeCount: {\n path: 'nodeCount'\n }\n});\n", "import { load } from '@loaders.gl/core';\nimport { JSONLoader } from '@loaders.gl/loader-utils';\nimport { promises as fs } from 'fs';\nimport { isAbsolute, join } from 'path';\nimport { compressFileWithGzip } from \"./compress-util.js\";\n/**\n * Write a file with data and name fileName to path\n *\n * @param path - output path\n * @param data - file content\n * @param fileName - name of output file (default: index.json)\n */\nexport async function writeFile(path, data, fileName = 'index.json') {\n let toWriteData;\n if (data instanceof Promise) {\n toWriteData = new Uint8Array(await data);\n }\n else if (data instanceof ArrayBuffer) {\n toWriteData = new Uint8Array(data);\n }\n else {\n toWriteData = data;\n }\n await fs.mkdir(path, { recursive: true });\n const pathFile = join(path, fileName);\n try {\n await fs.writeFile(pathFile, toWriteData);\n }\n catch (err) {\n throw err;\n }\n console.log(`${pathFile} saved.`); // eslint-disable-line no-console\n return pathFile;\n}\n/**\n * Write a file with data and name fileName to path - specific one for further packaging into slpk\n *\n * @param path - output path\n * @param data - file content\n * @param fileName - name of output file (default: index.json)\n * @param compress - if need to compress file with gzip (default: true)\n * @param compressList - if set - the file should be added to this list and compressed in the end of conversion\n */\nexport async function writeFileForSlpk(path, data, fileName = 'index.json', compress = true, compressList) {\n const pathFile = await writeFile(path, data, fileName);\n if (compress) {\n if (compressList) {\n if (!compressList.includes(pathFile)) {\n compressList.push(pathFile);\n return `${pathFile}.gz`;\n }\n return null;\n }\n const pathGzFile = await compressFileWithGzip(pathFile);\n // After compression, we don't need an uncompressed file\n await removeFile(pathFile);\n return pathGzFile;\n }\n return pathFile;\n}\n/**\n * Open json file\n * @param path - path to the file\n * @param fileName - file name\n * @returns object\n */\nexport async function openJson(path, fileName) {\n return new Promise((resolve, reject) => {\n let count = 0;\n console.log(`load ${path}/${fileName}.`); // eslint-disable-line no-console\n const intervalId = setInterval(() => {\n const pathFile = join(path, fileName);\n load(pathFile, JSONLoader)\n .then((result) => {\n clearInterval(intervalId);\n resolve(result);\n })\n .catch(() => {\n count++;\n if (count > 100) {\n clearInterval(intervalId);\n reject(new Error(`Cannon load ${path}/${fileName}.`));\n }\n });\n }, 200);\n });\n}\n/**\n * Check if the file exists\n * @param fileName - full name of file\n * @returns true if file exists, otherwise - false\n */\nexport async function isFileExists(fileName) {\n try {\n await fs.stat(fileName);\n return true;\n }\n catch {\n return false;\n }\n}\n/**\n * Remove dir with path\n *\n * @param path\n */\nexport function removeDir(path) {\n // (node:35607) [DEP0147] DeprecationWarning: In future versions of Node.js, fs.rmdir(path, { recursive: true }) will be removed. Use fs.rm(path, { recursive: true }) instead\n // @ts-ignore\n return fs.rm(path, { recursive: true });\n}\n/**\n * Remove file with path\n *\n * @param path\n */\nexport function removeFile(path) {\n return fs.unlink(path);\n}\n/**\n * Generates absolute file path\n * @param filePath\n */\nexport function getAbsoluteFilePath(filePath) {\n return isAbsolute(filePath) ? filePath : join(process.cwd(), filePath);\n}\n/**\n * Rename file with old path by new path\n * @param oldPath\n * @param newPath\n */\nexport async function renameFile(oldPath, newPath) {\n try {\n await fs.rename(oldPath, newPath);\n }\n catch (err) {\n // prettier-ignore\n console.log('Can\\'t rename file', err); // eslint-disable-line no-console\n }\n}\n", "import { createGzip } from 'zlib';\nimport { createReadStream, createWriteStream } from 'fs';\n/**\n * Compress file to gzip file\n *\n * @param pathFile - the path to the file\n * @return the path to the gzip file\n */\nexport function compressFileWithGzip(pathFile) {\n const compressedPathFile = `${pathFile}.gz`;\n const gzip = createGzip();\n const input = createReadStream(pathFile);\n const output = createWriteStream(compressedPathFile);\n return new Promise((resolve, reject) => {\n input.on('end', () => {\n console.log(`${compressedPathFile} compressed and saved.`); // eslint-disable-line no-undef,no-console\n resolve(compressedPathFile);\n });\n input.on('error', (error) => {\n console.log(`${compressedPathFile}: compression error!`); // eslint-disable-line no-undef,no-console\n reject(error);\n });\n input.pipe(gzip).pipe(output);\n });\n}\n", "import { join } from 'path';\nimport { promises as fs } from 'fs';\nimport { getAbsoluteFilePath } from \"./file-utils.js\";\n/**\n * Converts time value to string.\n * @param time - high-resolution real time in a [seconds, nanoseconds] tuple Array, or a value on milliseconds.\n * @returns string representation of the time\n */\nexport function timeConverter(time) {\n if (typeof time === 'number') {\n // time - real time in milli-seconds\n const milliSecondsInSecond = 1e3;\n const timeInSeconds = Math.floor(time / milliSecondsInSecond);\n const milliseconds = time - timeInSeconds * milliSecondsInSecond;\n return timeConverterFromSecondsAndMilliseconds(timeInSeconds, milliseconds);\n }\n // time - high-resolution real time in a [seconds, nanoseconds] tuple Array\n const nanoSecondsInMillisecond = 1e6;\n const timeInSeconds = time[0];\n const milliseconds = time[1] / nanoSecondsInMillisecond;\n return timeConverterFromSecondsAndMilliseconds(timeInSeconds, milliseconds);\n}\nfunction timeConverterFromSecondsAndMilliseconds(timeInSeconds, milliseconds) {\n const hours = Math.floor(timeInSeconds / 3600);\n timeInSeconds = timeInSeconds - hours * 3600;\n const minutes = Math.floor(timeInSeconds / 60);\n timeInSeconds = timeInSeconds - minutes * 60;\n const seconds = Math.floor(timeInSeconds);\n let result = '';\n if (hours) {\n result += `${hours}h `;\n }\n if (minutes) {\n result += `${minutes}m `;\n }\n if (seconds) {\n result += `${seconds}s`;\n }\n if (!result) {\n result += `${Math.floor(milliseconds)}ms`;\n }\n return result;\n}\nexport async function calculateFilesSize(params) {\n const { slpk, outputPath, tilesetName } = params;\n const fullOutputPath = getAbsoluteFilePath(outputPath);\n try {\n if (slpk) {\n const slpkPath = join(fullOutputPath, `${tilesetName}.slpk`);\n const stat = await fs.stat(slpkPath);\n return stat.size;\n }\n const directoryPath = join(fullOutputPath, tilesetName);\n const totalSize = await getTotalFilesSize(directoryPath);\n return totalSize;\n }\n catch (error) {\n console.log('Calculate file sizes error: ', error); // eslint-disable-line\n return null;\n }\n}\nasync function getTotalFilesSize(dirPath) {\n let totalFileSize = 0;\n const files = await fs.readdir(dirPath);\n for (const file of files) {\n const fileStat = await fs.stat(join(dirPath, file));\n if (fileStat.isDirectory()) {\n totalFileSize += await getTotalFilesSize(join(dirPath, file));\n }\n else {\n totalFileSize += fileStat.size;\n }\n }\n return totalFileSize;\n}\n", "import { Vector3, Matrix4, Vector4 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\nimport { DracoWriterWorker } from '@loaders.gl/draco';\nimport { assert, encode } from '@loaders.gl/core';\nimport { concatenateArrayBuffers, concatenateTypedArrays } from '@loaders.gl/loader-utils';\nimport md5 from 'md5';\nimport { v4 as uuidv4 } from 'uuid';\nimport { generateAttributes } from \"./geometry-attributes.js\";\nimport { createBoundingVolumesFromGeometry } from \"./coordinate-converter.js\";\nimport { prepareDataForAttributesConversion } from \"./gltf-attributes.js\";\nimport { getTextureByMetadataClass, handleBatchIdsExtensions } from \"./batch-ids-extensions.js\";\nimport { checkPropertiesLength, flattenPropertyTableByFeatureIds } from \"./feature-attributes.js\";\nimport { GL } from '@loaders.gl/math';\nimport { generateSyntheticIndices } from \"../../lib/utils/geometry-utils.js\";\nimport { EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA } from '@loaders.gl/gltf';\n// Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md\nconst DEFAULT_ROUGHNESS_FACTOR = 1;\nconst DEFAULT_METALLIC_FACTOR = 1;\nconst VALUES_PER_VERTEX = 3;\nconst VALUES_PER_TEX_COORD = 2;\nconst VALUES_PER_COLOR_ELEMENT = 4;\nconst STRING_TYPE = 'string';\nconst SHORT_INT_TYPE = 'Int32';\nconst DOUBLE_TYPE = 'Float64';\nconst OBJECT_ID_TYPE = 'Oid32';\n/*\n * 'CUSTOM_ATTRIBUTE_2' - Attribute name which includes batch info and used by New York map.\n * _BATCHID - Default attribute name which includes batch info.\n * BATCHID - Legacy attribute name which includes batch info.\n */\nconst BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES = ['CUSTOM_ATTRIBUTE_2', '_BATCHID', 'BATCHID'];\nlet scratchVector = new Vector3();\n/**\n * Convert binary data from b3dm file to i3s resources\n *\n * @param tileContent - 3d tile content\n * @param tileTransform - transformation matrix of the tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n * @param tileBoundingVolume - initialized bounding volume of the source tile\n * @param addNodeToNodePage - function to add new node to node pages\n * @param propertyTable - batch table (corresponding to feature attributes data)\n * @param featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes\n * @param attributeStorageInfo - attributes metadata from 3DSceneLayer json\n * @param draco - is converter should create draco compressed geometry\n * @param generateBoundingVolumes - is converter should create accurate bounding voulmes from geometry attributes\n * @param shouldMergeMaterials - Try to merge similar materials to be able to merge meshes into one node\n * @param geoidHeightModel - model to convert elevation from elipsoidal to geoid\n * @param libraries - dynamicaly loaded 3rd-party libraries\n * @param metadataClass `- user selected feature metadata class name`\n * @returns Array of node resources to create one or more i3s nodes\n */\nexport default async function convertB3dmToI3sGeometry({ tileContent, tileTransform, tileBoundingVolume, addNodeToNodePage, propertyTable, featuresHashArray, attributeStorageInfo, draco, generateBoundingVolumes, shouldMergeMaterials, geoidHeightModel, libraries, metadataClass }) {\n const useCartesianPositions = generateBoundingVolumes;\n const materialAndTextureList = await convertMaterials(tileContent.gltf?.materials, shouldMergeMaterials);\n const dataForAttributesConversion = prepareDataForAttributesConversion(tileContent, tileTransform, tileBoundingVolume);\n const featureTexture = getTextureByMetadataClass(tileContent, metadataClass);\n const convertedAttributesMap = await convertAttributes(dataForAttributesConversion, materialAndTextureList, useCartesianPositions, featureTexture);\n /** Usage of worker here brings more overhead than advantage */\n // const convertedAttributesMap: Map<string, ConvertedAttributes> =\n // await transformI3SAttributesOnWorker(dataForAttributesConversion, {\n // reuseWorkers: true,\n // _nodeWorkers: true,\n // useCartesianPositions,\n // source: workerSource.I3SAttributes\n // });\n if (generateBoundingVolumes) {\n _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeightModel);\n }\n const result = [];\n for (const materialAndTexture of materialAndTextureList) {\n const originarMaterialId = materialAndTexture.mergedMaterials[0].originalMaterialId;\n if (!convertedAttributesMap.has(originarMaterialId)) {\n continue; // eslint-disable-line no-continue\n }\n const convertedAttributes = convertedAttributesMap.get(originarMaterialId);\n if (!convertedAttributes) {\n continue; // eslint-disable-line no-continue\n }\n const { material, texture } = materialAndTexture;\n const nodeId = await addNodeToNodePage();\n result.push(await _makeNodeResources({\n convertedAttributes,\n material,\n texture,\n tileContent,\n nodeId,\n featuresHashArray,\n propertyTable,\n attributeStorageInfo,\n draco,\n libraries\n }));\n }\n if (!result.length) {\n return null;\n }\n return result;\n}\n/**\n * Create bounding volumes based on positions\n * @param convertedAttributesMap - geometry attributes map\n * @param geoidHeightModel - geoid height model to convert elevation from elipsoidal to geoid\n */\nfunction _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeightModel) {\n for (const attributes of convertedAttributesMap.values()) {\n const boundingVolumes = createBoundingVolumesFromGeometry(attributes.positions, geoidHeightModel);\n attributes.boundingVolumes = boundingVolumes;\n const cartographicOrigin = boundingVolumes.obb.center;\n for (let index = 0; index < attributes.positions.length; index += VALUES_PER_VERTEX) {\n const vertex = attributes.positions.subarray(index, index + VALUES_PER_VERTEX);\n Ellipsoid.WGS84.cartesianToCartographic(Array.from(vertex), scratchVector);\n scratchVector[2] =\n scratchVector[2] - geoidHeightModel.getHeight(scratchVector[1], scratchVector[0]);\n scratchVector = scratchVector.subtract(cartographicOrigin);\n attributes.positions.set(scratchVector, index);\n }\n }\n}\n/**\n *\n * @param params\n * @param params.convertedAttributes - Converted geometry attributes\n * @param params.material - I3S PBR-like material definition\n * @param params.texture - texture content\n * @param params.tileContent - 3DTiles decoded content\n * @param params.nodeId - new node ID\n * @param params.featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes\n * @param params.propertyTable - batch table (corresponding to feature attributes data)\n * @param params.attributeStorageInfo - attributes metadata from 3DSceneLayer json\n * @param params.draco - is converter should create draco compressed geometry\n * @param libraries - dynamicaly loaded 3rd-party libraries\n * @returns Array of I3S node resources\n */\nasync function _makeNodeResources({ convertedAttributes, material, texture, tileContent, nodeId, featuresHashArray, propertyTable, attributeStorageInfo, draco, libraries }) {\n const boundingVolumes = convertedAttributes.boundingVolumes;\n const vertexCount = convertedAttributes.positions.length / VALUES_PER_VERTEX;\n const { faceRange, featureIds, positions, normals, colors, uvRegions, texCoords, featureCount } = generateAttributes(convertedAttributes);\n let featureIdsMap = {};\n if (propertyTable) {\n /**\n * 3DTiles has featureIndices unique only for one tile.\n * In I3S featureIds are unique layer-wide. We create featureIds from all feature properties.\n * If 3DTiles features has equal set of properties they are considered as same feature in I3S.\n */\n featureIdsMap = makeFeatureIdsUnique(featureIds, convertedAttributes.featureIndices, featuresHashArray, propertyTable);\n }\n const header = new Uint32Array(2);\n const typedFeatureIds = generateBigUint64Array(featureIds);\n header.set([vertexCount, featureCount], 0);\n const fileBuffer = new Uint8Array(concatenateArrayBuffers(header.buffer, positions.buffer, normals.buffer, texture ? texCoords.buffer : new ArrayBuffer(0), colors.buffer, uvRegions, typedFeatureIds.buffer, faceRange.buffer));\n // prettier-ignore\n const compressedGeometry = draco\n ? generateCompressedGeometry(vertexCount, convertedAttributes, {\n positions,\n normals,\n texCoords: texture ? texCoords : new Float32Array(0),\n colors,\n uvRegions,\n featureIds,\n faceRange\n }, libraries)\n : null;\n let attributes = [];\n if (attributeStorageInfo && propertyTable) {\n attributes = convertPropertyTableToAttributeBuffers(featureIds, featureIdsMap, propertyTable, attributeStorageInfo);\n }\n return {\n nodeId,\n geometry: fileBuffer,\n compressedGeometry,\n texture,\n hasUvRegions: Boolean(uvRegions.length),\n sharedResources: getSharedResources(tileContent.gltf?.materials || [], nodeId),\n meshMaterial: material,\n vertexCount,\n attributes,\n featureCount,\n boundingVolumes\n };\n}\n/**\n * Convert attributes from the gltf nodes tree to i3s plain geometry\n * @param attributesData - geometry attributes from gltf\n * @param materialAndTextureList - array of data about materials and textures of the content\n * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.\n * Cartesian coordinates will be required for creating bounding voulmest from geometry positions\n * @param featureTexture - feature texture key\n * @returns map of converted geometry attributes\n */\nexport async function convertAttributes(attributesData, materialAndTextureList, useCartesianPositions, featureTexture) {\n const { nodes, images, cartographicOrigin, cartesianModelMatrix } = attributesData;\n const attributesMap = new Map();\n for (const materialAndTexture of materialAndTextureList) {\n const attributes = {\n positions: new Float32Array(0),\n normals: new Float32Array(0),\n texCoords: new Float32Array(0),\n colors: new Uint8Array(0),\n uvRegions: new Uint16Array(0),\n featureIndicesGroups: [],\n featureIndices: [],\n boundingVolumes: null,\n mergedMaterials: materialAndTexture.mergedMaterials\n };\n for (const mergedMaterial of materialAndTexture.mergedMaterials) {\n attributesMap.set(mergedMaterial.originalMaterialId, attributes);\n }\n }\n convertNodes({\n nodes,\n images,\n cartographicOrigin,\n cartesianModelMatrix,\n attributesMap,\n useCartesianPositions,\n featureTexture\n });\n for (const attrKey of attributesMap.keys()) {\n const attributes = attributesMap.get(attrKey);\n if (!attributes) {\n continue; // eslint-disable-line no-continue\n }\n if (attributes.positions.length === 0) {\n attributesMap.delete(attrKey);\n continue; // eslint-disable-line no-continue\n }\n if (attributes.featureIndicesGroups) {\n attributes.featureIndices = attributes.featureIndicesGroups.reduce((acc, value) => acc.concat(value));\n delete attributes.featureIndicesGroups;\n }\n }\n return attributesMap;\n}\n/**\n * glTF has hierarchical structure of nodes. This function converts nodes starting from those which are in gltf scene object.\n * The goal is applying tranformation matrix for all children. Functions \"convertNodes\" and \"convertNode\" work together recursively.\n * @param nodes - gltf nodes array\n * @param images - gltf images array\n * @param cartographicOrigin - cartographic origin of bounding volume\n * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic\n * @param attributesMap - for recursive concatenation of attributes\n * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.\n * Cartesian coordinates will be required for creating bounding voulmest from geometry positions\n * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @param featureTexture - feature texture key\n * @returns {void}\n */\nfunction convertNodes({ nodes, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]), featureTexture }) {\n if (nodes) {\n for (const node of nodes) {\n convertNode({\n node,\n images,\n cartographicOrigin,\n cartesianModelMatrix,\n attributesMap,\n useCartesianPositions,\n matrix,\n featureTexture\n });\n }\n }\n}\n/**\n * Generate transformation matrix for node\n * Aapply all gltf transformations to initial transformation matrix.\n * @param node\n * @param matrix\n */\nfunction getCompositeTransformationMatrix(node, matrix) {\n let transformationMatrix = matrix;\n const { matrix: nodeMatrix, rotation, scale, translation } = node;\n if (nodeMatrix) {\n transformationMatrix = matrix.multiplyRight(nodeMatrix);\n }\n if (translation) {\n transformationMatrix = transformationMatrix.translate(translation);\n }\n if (rotation) {\n transformationMatrix = transformationMatrix.rotateXYZ(rotation);\n }\n if (scale) {\n transformationMatrix = transformationMatrix.scale(scale);\n }\n return transformationMatrix;\n}\n/**\n * Convert all primitives of node and all children nodes\n * @param node - gltf node\n * @param images - gltf images array\n * @param cartographicOrigin - cartographic origin of bounding volume\n * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic\n * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of\n * attributes\n * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.\n * Cartesian coordinates will be required for creating bounding voulmest from geometry positions\n * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @param featureTexture - feature texture key\n */\nfunction convertNode({ node, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]), featureTexture }) {\n const transformationMatrix = getCompositeTransformationMatrix(node, matrix);\n const mesh = node.mesh;\n if (mesh) {\n convertMesh({\n mesh,\n images,\n cartographicOrigin,\n cartesianModelMatrix,\n attributesMap,\n useCartesianPositions,\n matrix: transformationMatrix,\n featureTexture\n });\n }\n convertNodes({\n nodes: node.children || [],\n images,\n cartographicOrigin,\n cartesianModelMatrix,\n attributesMap,\n useCartesianPositions,\n matrix: transformationMatrix,\n featureTexture\n });\n}\n/**\n * Convert all primitives of the mesh\n * @param mesh - gltf mesh data\n * @param images - gltf images array\n * @param cartographicOrigin - cartographic origin of bounding volume\n * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic\n * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of\n * attributes\n * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.\n * Cartesian coordinates will be required for creating bounding voulmest from geometry positions\n * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of\n * attributes\n * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @param featureTexture - feature texture key\n */\nfunction convertMesh({ mesh, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions = false, matrix, featureTexture }) {\n for (const primitive of mesh.primitives) {\n let outputAttributes = null;\n let materialUvRegion;\n if (primitive.material) {\n outputAttributes = attributesMap.get(primitive.material.id);\n materialUvRegion = outputAttributes?.mergedMaterials.find(({ originalMaterialId }) => originalMaterialId === primitive.material?.id)?.uvRegion;\n }\n else if (attributesMap.has('default')) {\n outputAttributes = attributesMap.get('default');\n }\n assert(outputAttributes !== null, 'Primitive - material mapping failed');\n // Per the spec https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode\n // GL.TRIANGLES is default. So in case `mode` is `undefined`, it is 'TRIANGLES'\n assert(primitive.mode === undefined ||\n primitive.mode === GL.TRIANGLES ||\n primitive.mode === GL.TRIANGLE_STRIP, `Primitive - unsupported mode ${primitive.mode}`);\n const attributes = primitive.attributes;\n if (!outputAttributes) {\n continue; // eslint-disable-line no-continue\n }\n const indices = normalizeIndices(primitive);\n outputAttributes.positions = concatenateTypedArrays(outputAttributes.positions, transformVertexArray({\n vertices: attributes.POSITION.value,\n cartographicOrigin,\n cartesianModelMatrix,\n nodeMatrix: matrix,\n indices,\n attributeSpecificTransformation: transformVertexPositions,\n useCartesianPositions\n }));\n outputAttributes.normals = concatenateTypedArrays(outputAttributes.normals, transformVertexArray({\n vertices: attributes.NORMAL && attributes.NORMAL.value,\n cartographicOrigin,\n cartesianModelMatrix,\n nodeMatrix: matrix,\n indices,\n attributeSpecificTransformation: transformVertexNormals,\n useCartesianPositions: false\n }));\n outputAttributes.texCoords = concatenateTypedArrays(outputAttributes.texCoords, flattenTexCoords(attributes.TEXCOORD_0 && attributes.TEXCOORD_0.value, indices));\n outputAttributes.colors = concatenateTypedArrays(outputAttributes.colors, flattenColors(attributes.COLOR_0, indices));\n if (materialUvRegion) {\n outputAttributes.uvRegions = concatenateTypedArrays(outputAttributes.uvRegions, createUvRegion(materialUvRegion, indices));\n }\n outputAttributes.featureIndicesGroups = outputAttributes.featureIndicesGroups || [];\n outputAttributes.featureIndicesGroups.push(flattenBatchIds(getBatchIds(attributes, primitive, images, featureTexture), indices));\n }\n}\n/**\n * Converts TRIANGLE-STRIPS to independent TRIANGLES\n * @param primitive - the primitive to get the indices from\n * @returns indices of vertices of the independent triangles\n */\nfunction normalizeIndices(primitive) {\n let indices = primitive.indices?.value;\n if (!indices) {\n const positions = primitive.attributes.POSITION.value;\n return generateSyntheticIndices(positions.length / VALUES_PER_VERTEX);\n }\n if (indices && primitive.mode === GL.TRIANGLE_STRIP) {\n /*\n TRIANGLE_STRIP geometry contains n+2 vertices for n triangles;\n TRIANGLE geometry contains n*3 vertices for n triangles.\n The conversion from TRIANGLE_STRIP to TRIANGLE implies duplicating adjacent vertices.\n */\n const TypedArrayConstructor = indices.constructor;\n const newIndices = new TypedArrayConstructor((indices.length - 2) * 3);\n // Copy the first triangle indices with no modification like [i0, i1, i2, ...] -> [i0, i1, i2, ...]\n let triangleIndex = 0;\n let currentTriangle = indices.slice(0, 3);\n newIndices.set(currentTriangle, 0);\n // The rest triangle indices are being taken from strips using the following logic:\n // [i1, i2, i3, i4, i5, i6, ...] -> [i3, i2, i1, i2, i3, i4, i5, i4, i3, i4, i5, i6, ...]\n for (let i = 1; i + 2 < indices.length; i++) {\n triangleIndex += 3;\n currentTriangle = indices.slice(i, i + 3);\n if (i % 2 === 0) {\n newIndices.set(currentTriangle, triangleIndex);\n }\n else {\n // The following \"reverce\" is necessary to calculate normals correctly\n newIndices.set(currentTriangle.reverse(), triangleIndex);\n }\n }\n indices = newIndices;\n }\n return indices;\n}\n/**\n * Convert vertices attributes (POSITIONS or NORMALS) to i3s compatible format\n * @param args\n * @param args.vertices - gltf primitive POSITION or NORMAL attribute\n * @param args.cartographicOrigin - cartographic origin coordinates\n * @param args.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format\n * @param args.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @param args.indices - gltf primitive indices\n * @param args.attributeSpecificTransformation - function to do attribute - specific transformations\n * @param args.useCartesianPositions - use coordinates as it is.\n * @returns\n */\nfunction transformVertexArray(args) {\n const { vertices, indices, attributeSpecificTransformation } = args;\n const newVertices = new Float32Array(indices.length * VALUES_PER_VERTEX);\n if (!vertices) {\n return newVertices;\n }\n for (let i = 0; i < indices.length; i++) {\n const coordIndex = indices[i] * VALUES_PER_VERTEX;\n const vertex = vertices.subarray(coordIndex, coordIndex + VALUES_PER_VERTEX);\n let vertexVector = new Vector3(Array.from(vertex));\n vertexVector = attributeSpecificTransformation(vertexVector, args);\n newVertices[i * VALUES_PER_VERTEX] = vertexVector.x;\n newVertices[i * VALUES_PER_VERTEX + 1] = vertexVector.y;\n newVertices[i * VALUES_PER_VERTEX + 2] = vertexVector.z;\n }\n return newVertices;\n}\n/**\n * Trasform positions vector with the attribute specific transformations\n * @param vertexVector - source positions vector to transform\n * @param calleeArgs\n * @param calleeArgs.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format\n * @param calleeArgs.cartographicOrigin - cartographic origin coordinates\n * @param calleeArgs.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @param calleeArgs.useCartesianPositions - use coordinates as it is.\n * @returns transformed positions vector\n */\nfunction transformVertexPositions(vertexVector, calleeArgs) {\n const { cartesianModelMatrix, cartographicOrigin, nodeMatrix, useCartesianPositions } = calleeArgs;\n if (nodeMatrix) {\n vertexVector = vertexVector.transform(nodeMatrix);\n }\n vertexVector = vertexVector.transform(cartesianModelMatrix);\n if (useCartesianPositions) {\n return vertexVector;\n }\n Ellipsoid.WGS84.cartesianToCartographic([vertexVector[0], vertexVector[1], vertexVector[2]], vertexVector);\n vertexVector = vertexVector.subtract(cartographicOrigin);\n return vertexVector;\n}\n/**\n * Trasform normals vector with the attribute specific transformations\n * @param vertexVector - source normals vector to transform\n * @param calleeArgs\n * @param calleeArgs.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format\n * @param calleeArgs.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices\n * @returns transformed normals vector\n */\nfunction transformVertexNormals(vertexVector, calleeArgs) {\n const { cartesianModelMatrix, nodeMatrix } = calleeArgs;\n if (nodeMatrix) {\n vertexVector = vertexVector.transformAsVector(nodeMatrix);\n }\n vertexVector = vertexVector.transformAsVector(cartesianModelMatrix);\n return vertexVector;\n}\n/**\n * Convert uv0 (texture coordinates) from coords based on indices to plain arrays, compatible with i3s\n * @param texCoords - gltf primitive TEXCOORD_0 attribute\n * @param indices - gltf primitive indices\n * @returns flattened texture coordinates\n */\nfunction flattenTexCoords(texCoords, indices) {\n const newTexCoords = new Float32Array(indices.length * VALUES_PER_TEX_COORD);\n if (!texCoords) {\n // We need dummy UV0s because it is required in 1.6\n // https://github.com/Esri/i3s-spec/blob/master/docs/1.6/vertexAttribute.cmn.md\n newTexCoords.fill(1);\n return newTexCoords;\n }\n for (let i = 0; i < indices.length; i++) {\n const coordIndex = indices[i] * VALUES_PER_TEX_COORD;\n const texCoord = texCoords.subarray(coordIndex, coordIndex + VALUES_PER_TEX_COORD);\n newTexCoords[i * VALUES_PER_TEX_COORD] = texCoord[0];\n newTexCoords[i * VALUES_PER_TEX_COORD + 1] = texCoord[1];\n }\n return newTexCoords;\n}\n/**\n * Convert color from COLOR_0 based on indices to plain arrays, compatible with i3s\n * @param colorsAttribute - gltf primitive COLOR_0 attribute\n * @param indices - gltf primitive indices\n * @returns flattened colors attribute\n */\nfunction flattenColors(colorsAttribute, indices) {\n const components = colorsAttribute?.components || VALUES_PER_COLOR_ELEMENT;\n const newColors = new Uint8Array(indices.length * components);\n if (!colorsAttribute) {\n // Vertex color multiplies by material color so it must be normalized 1 by default\n newColors.fill(255);\n return newColors;\n }\n const colors = colorsAttribute.value;\n for (let i = 0; i < indices.length; i++) {\n const colorIndex = indices[i] * components;\n const color = colors.subarray(colorIndex, colorIndex + components);\n const colorUint8 = new Uint8Array(components);\n for (let j = 0; j < color.length; j++) {\n colorUint8[j] = color[j] * 255;\n }\n newColors.set(colorUint8, i * components);\n }\n return newColors;\n}\n/**\n * Create per-vertex uv-region array\n * @param materialUvRegion - uv-region fragment for a single vertex\n * @param indices - geometry indices data\n * @returns - uv-region array\n */\nfunction createUvRegion(materialUvRegion, indices) {\n const result = new Uint16Array(indices.length * 4);\n for (let i = 0; i < result.length; i += 4) {\n result.set(materialUvRegion, i);\n }\n return result;\n}\n/**\n * Flatten batchedIds list based on indices to right ordered array, compatible with i3s\n * @param batchedIds - gltf primitive\n * @param indices - gltf primitive indices\n * @returns flattened batch ids\n */\nfunction flattenBatchIds(batchedIds, indices) {\n if (!batchedIds.length || !indices.length) {\n return [];\n }\n const newBatchIds = [];\n for (let i = 0; i < indices.length; i++) {\n const coordIndex = indices[i];\n newBatchIds.push(batchedIds[coordIndex]);\n }\n return newBatchIds;\n}\n/**\n * Get batchIds for featureIds creation\n * @param attributes - gltf accessors\n * @param primitive - gltf primitive data\n * @param images - gltf texture images\n * @param featureTexture - feature texture key\n * @return batch IDs\n */\nfunction getBatchIds(attributes, primitive, images, featureTexture) {\n const batchIds = handleBatchIdsExtensions(attributes, primitive, images, featureTexture);\n if (batchIds.length) {\n return batchIds;\n }\n for (let index = 0; index < BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES.length; index++) {\n const possibleBatchIdAttributeName = BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES[index];\n if (attributes[possibleBatchIdAttributeName] &&\n attributes[possibleBatchIdAttributeName].value) {\n return attributes[possibleBatchIdAttributeName].value;\n }\n }\n return [];\n}\n/**\n * Convert GLTF material to I3S material definitions and textures\n * @param sourceMaterials Source GLTF materials\n * @param shouldMergeMaterials - if true - the converter will try to merge similar materials\n * to be able to merge primitives having those materials\n * @returns Array of Couples I3SMaterialDefinition + texture content\n */\nasync function convertMaterials(sourceMaterials = [], shouldMergeMaterials) {\n let materials = [];\n for (const sourceMaterial of sourceMaterials) {\n materials.push(convertMaterial(sourceMaterial));\n }\n if (shouldMergeMaterials) {\n materials = await mergeAllMaterials(materials);\n }\n return materials;\n}\n/**\n * Merge materials when possible\n * @param materials materials array\n * @returns merged materials array\n */\n// eslint-disable-next-line max-statements, complexity\nasync function mergeAllMaterials(materials) {\n const result = [];\n while (materials.length > 0) {\n let newMaterial = materials.splice(0, 1)[0];\n const mergedIndices = [];\n for (let i = 0; i < materials.length; i++) {\n const material = materials[i];\n if ((newMaterial.texture && material.texture) ||\n (!newMaterial.texture && !material.texture)) {\n newMaterial = await mergeMaterials(newMaterial, material);\n mergedIndices.push(i);\n }\n }\n if (newMaterial.texture && mergedIndices.length) {\n const newWidth = newMaterial.mergedMaterials?.reduce((accum, { textureSize }) => accum + (textureSize?.width || 0), 0);\n const newHeight = newMaterial.mergedMaterials?.reduce((accum, { textureSize }) => Math.max(accum, textureSize?.height || 0), 0);\n let currentX = -1;\n for (const aTextureMetadata of newMaterial.mergedMaterials) {\n if (aTextureMetadata.textureSize) {\n const newX = currentX +\n 1 +\n (aTextureMetadata.textureSize.width / newWidth) *\n 2 ** (Uint16Array.BYTES_PER_ELEMENT * 8) -\n 1;\n aTextureMetadata.uvRegion = new Uint16Array([\n currentX + 1,\n 0,\n newX,\n (aTextureMetadata.textureSize.height / newHeight) *\n 2 ** (Uint16Array.BYTES_PER_ELEMENT * 8) -\n 1\n ]);\n currentX = newX;\n }\n }\n newMaterial.texture.image.width = newWidth;\n newMaterial.texture.image.height = newHeight;\n }\n for (const index of mergedIndices.reverse()) {\n materials.splice(index, 1);\n }\n result.push(newMaterial);\n }\n if (!result.length) {\n result.push({\n material: getDefaultMaterial(),\n mergedMaterials: [{ originalMaterialId: 'default' }]\n });\n }\n return result;\n}\n/**\n * Merge 2 materials including texture\n * @param material1\n * @param material2\n * @returns\n */\nasync function mergeMaterials(material1, material2) {\n if (material1.texture?.bufferView &&\n material2.texture?.bufferView &&\n material1.mergedMaterials &&\n material2.mergedMaterials) {\n const buffer1 = Buffer.from(material1.texture.bufferView.data);\n const buffer2 = Buffer.from(material2.texture.bufferView.data);\n try {\n // @ts-ignore\n const { joinImages } = await import('join-images');\n const sharpData = await joinImages([buffer1, buffer2], { direction: 'horizontal' });\n material1.texture.bufferView.data = await sharpData\n .toFormat(material1.texture.mimeType === 'image/png' ? 'png' : 'jpeg')\n .toBuffer();\n }\n catch (error) {\n // eslint-disable-next-line no-console\n console.log('Join images into a texture atlas has failed. Consider usage `--split-nodes` option. (See documentation https://loaders.gl/modules/tile-converter/docs/cli-reference/tile-converter)');\n throw error;\n }\n // @ts-ignore\n material1.material.pbrMetallicRoughness.baseColorTexture.textureSetDefinitionId = 1;\n }\n material1.mergedMaterials = material1.mergedMaterials.concat(material2.mergedMaterials);\n return material1;\n}\n/**\n * Convert texture and material from gltf 2.0 material object\n * @param sourceMaterial - material object\n * @returns I3S material definition and texture\n */\nfunction convertMaterial(sourceMaterial) {\n const material = {\n doubleSided: sourceMaterial.doubleSided,\n emissiveFactor: sourceMaterial.emissiveFactor?.map((c) => Math.round(c * 255)),\n // It is in upper case in GLTF: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#alpha-coverage\n // But it is in lower case in I3S: https://github.com/Esri/i3s-spec/blob/master/docs/1.7/materialDefinitions.cmn.md\n alphaMode: convertAlphaMode(sourceMaterial.alphaMode),\n pbrMetallicRoughness: {\n roughnessFactor: sourceMaterial?.pbrMetallicRoughness?.roughnessFactor || DEFAULT_ROUGHNESS_FACTOR,\n metallicFactor: sourceMaterial?.pbrMetallicRoughness?.metallicFactor || DEFAULT_METALLIC_FACTOR\n }\n };\n let texture;\n if (sourceMaterial?.pbrMetallicRoughness?.baseColorTexture) {\n texture = sourceMaterial.pbrMetallicRoughness.baseColorTexture.texture.source;\n material.pbrMetallicRoughness.baseColorTexture = {\n textureSetDefinitionId: 0\n };\n }\n else if (sourceMaterial.emissiveTexture) {\n texture = sourceMaterial.emissiveTexture.texture.source;\n // ArcGIS webscene doesn't show emissiveTexture but shows baseColorTexture\n material.pbrMetallicRoughness.baseColorTexture = {\n textureSetDefinitionId: 0\n };\n }\n sourceMaterial.id = Number.isFinite(sourceMaterial.id) ? sourceMaterial.id : uuidv4();\n const mergedMaterials = [{ originalMaterialId: sourceMaterial.id }];\n if (!texture) {\n // Should use default baseColorFactor if it is not present in source material\n // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-pbrmetallicroughness\n const baseColorFactor = sourceMaterial?.pbrMetallicRoughness?.baseColorFactor;\n material.pbrMetallicRoughness.baseColorFactor =\n (baseColorFactor && baseColorFactor.map((c) => Math.round(c * 255))) || undefined;\n }\n else {\n mergedMaterials[0].textureSize = { width: texture.image.width, height: texture.image.height };\n }\n return { material, texture, mergedMaterials };\n}\n/**\n * Converts from `alphaMode` material property from GLTF to I3S format\n * @param gltfAlphaMode glTF material `alphaMode` property\n * @returns I3SMaterialDefinition.alphaMode property\n */\nfunction convertAlphaMode(gltfAlphaMode) {\n switch (gltfAlphaMode) {\n case 'OPAQUE':\n return 'opaque';\n case 'MASK':\n return 'mask';\n case 'BLEND':\n return 'blend';\n default:\n return 'opaque';\n }\n}\n/**\n * Form default I3SMaterialDefinition\n * @returns I3S material definition\n */\nfunction getDefaultMaterial() {\n return {\n alphaMode: 'opaque',\n pbrMetallicRoughness: {\n metallicFactor: 1,\n roughnessFactor: 1\n }\n };\n}\n/**\n * Form \"sharedResources\" from gltf materials array\n * @param gltfMaterials - GLTF materials array\n * @param nodeId - I3S node ID\n * @returns {materialDefinitionInfos: Object[], textureDefinitionInfos: Object[]} -\n * 2 arrays in format of i3s sharedResources data https://github.com/Esri/i3s-spec/blob/master/docs/1.7/sharedResource.cmn.md\n */\nfunction getSharedResources(gltfMaterials, nodeId) {\n const i3sResources = {};\n if (!gltfMaterials || !gltfMaterials.length) {\n return i3sResources;\n }\n i3sResources.materialDefinitionInfos = [];\n for (const gltfMaterial of gltfMaterials) {\n const { materialDefinitionInfo, textureDefinitionInfo } = convertGLTFMaterialToI3sSharedResources(gltfMaterial, nodeId);\n i3sResources.materialDefinitionInfos.push(materialDefinitionInfo);\n if (textureDefinitionInfo) {\n i3sResources.textureDefinitionInfos = i3sResources.textureDefinitionInfos || [];\n i3sResources.textureDefinitionInfos.push(textureDefinitionInfo);\n }\n }\n return i3sResources;\n}\n/**\n * Convert gltf material into I3S sharedResources data\n * @param gltfMaterial - gltf material data\n * @param nodeId - I3S node ID\n * @returns - Couple {materialDefinitionInfo, textureDefinitionInfo} extracted from gltf material data\n */\nfunction convertGLTFMaterialToI3sSharedResources(gltfMaterial, nodeId) {\n const texture = gltfMaterial?.pbrMetallicRoughness?.baseColorTexture || gltfMaterial.emissiveTexture;\n let textureDefinitionInfo = null;\n if (texture) {\n textureDefinitionInfo = extractSharedResourcesTextureInfo(texture.texture, nodeId);\n }\n const { baseColorFactor, metallicFactor } = gltfMaterial?.pbrMetallicRoughness || {};\n let colorFactor = baseColorFactor;\n // If alpha channel is 0 try to get emissive factor from gltf material.\n if ((!baseColorFactor || baseColorFactor[3] === 0) && gltfMaterial.emissiveFactor) {\n colorFactor = gltfMaterial.emissiveFactor;\n colorFactor[3] = colorFactor[3] || 1;\n }\n return {\n materialDefinitionInfo: extractSharedResourcesMaterialInfo(colorFactor || [1, 1, 1, 1], metallicFactor),\n textureDefinitionInfo\n };\n}\n/**\n * Form \"materialDefinition\" which is part of \"sharedResouces\"\n * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materials\n * See formulas in appendix \"Appendix B: BRDF Implementation\":\n * const dielectricSpecular = rgb(0.04, 0.04, 0.04)\n * const black = rgb(0, 0, 0)\n * cdiff = lerp(baseColor.rgb * (1 - dielectricSpecular.r), black, metallic)\n * F0 = lerp(dieletricSpecular, baseColor.rgb, metallic)\n *\n * Assumption: F0 - specular in i3s (\"specular reflection\" <-> \"reflectance value at normal incidence\")\n * cdiff - diffuse in i3s (\"Diffuse color\" <-> \"'c' diffuse\" (c means color?))\n * @param baseColorFactor - RGBA color in 0..1 format\n * @param metallicFactor - \"metallicFactor\" attribute of gltf material object\n * @returns material definition info for I3S shared resource\n */\nfunction extractSharedResourcesMaterialInfo(baseColorFactor, metallicFactor = 1) {\n const matDielectricColorComponent = 0.04 / 255; // Color from rgb (255) to 0..1 resolution\n // All color resolutions are 0..1\n const black = new Vector4(0, 0, 0, 1);\n const unitVector = new Vector4(1, 1, 1, 1);\n const dielectricSpecular = new Vector4(matDielectricColorComponent, matDielectricColorComponent, matDielectricColorComponent, 0);\n const baseColorVector = new Vector4(baseColorFactor);\n // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material\n // Formulas for Cdiff & F0\n const firstOperand = unitVector.subtract(dielectricSpecular).multiply(baseColorVector);\n const diffuse = firstOperand.lerp(firstOperand, black, metallicFactor);\n dielectricSpecular[3] = 1;\n const specular = dielectricSpecular.lerp(dielectricSpecular, baseColorVector, metallicFactor);\n return {\n params: {\n // @ts-expect-error NumericArray\n diffuse: diffuse.toArray(),\n // @ts-expect-error NumericArray\n specular: specular.toArray(),\n renderMode: 'solid'\n }\n };\n}\n/**\n * Form \"textureDefinition\" which is part of \"sharedResouces\"\n * @param texture - texture image info\n * @param nodeId - I3S node ID\n * @returns texture definition infor for shared resource\n */\nfunction extractSharedResourcesTextureInfo(texture, nodeId) {\n return {\n encoding: texture?.source?.mimeType ? [texture.source.mimeType] : undefined,\n images: [\n {\n // 'i3s' has just size which is width of the image. Images are supposed to be square.\n // https://github.com/Esri/i3s-spec/blob/master/docs/1.7/image.cmn.md\n id: generateImageId(texture, nodeId),\n size: texture.source?.image.width,\n length: texture.source?.image.data.length ? [texture.source?.image.data.length] : undefined\n }\n ]\n };\n}\n/**\n * Formula for calculating imageId:\n * https://github.com/Esri/i3s-spec/blob/0a6366a9249b831db8436c322f8d27521e86cf07/format/Indexed%203d%20Scene%20Layer%20Format%20Specification.md#generating-image-ids\n * @param texture - texture image info\n * @param nodeId - I3S node ID\n * @returns calculate image ID according to the spec\n */\nfunction generateImageId(texture, nodeId) {\n const { width, height } = texture.source?.image || {};\n if (!width || !height) {\n return '';\n }\n const levelCountOfTexture = 1;\n const indexOfLevel = 0;\n const indexOfTextureInStore = nodeId + 1;\n const zerosCount = 32 - indexOfTextureInStore.toString(2).length;\n const rightHalf = '0'.repeat(zerosCount).concat(indexOfTextureInStore.toString(2));\n const shiftedLevelCountOfTexture = levelCountOfTexture << 28;\n const shiftedIndexOfLevel = indexOfLevel << 24;\n const shiftedWidth = (width - 1) << 12;\n const shiftedHeight = (height - 1) << 0;\n const leftHalf = shiftedLevelCountOfTexture + shiftedIndexOfLevel + shiftedWidth + shiftedHeight;\n const imageId = BigInt(`0b${leftHalf.toString(2)}${rightHalf}`);\n return imageId.toString();\n}\n/**\n * Make all feature ids unique through all nodes in layout.\n * @param featureIds\n * @param featureIndices\n * @param featuresHashArray\n * @param batchTable\n * @returns propertyTable indices to map featureIds\n */\nfunction makeFeatureIdsUnique(featureIds, featureIndices, featuresHashArray, batchTable) {\n const replaceMap = getFeaturesReplaceMap(featureIds, batchTable, featuresHashArray);\n replaceIndicesByUnique(featureIndices, replaceMap);\n replaceIndicesByUnique(featureIds, replaceMap);\n return replaceMap;\n}\n/**\n * Generate replace map to make featureIds unique.\n * @param featureIds\n * @param batchTable\n * @param featuresHashArray\n * @returns\n */\nfunction getFeaturesReplaceMap(featureIds, batchTable, featuresHashArray) {\n const featureMap = {};\n for (let index = 0; index < featureIds.length; index++) {\n const oldFeatureId = featureIds[index];\n const uniqueFeatureId = getOrCreateUniqueFeatureId(index, batchTable, featuresHashArray);\n featureMap[oldFeatureId.toString()] = uniqueFeatureId;\n }\n return featureMap;\n}\n/**\n * Generates string for unique batch id creation.\n * @param batchTable\n * @param index\n * @returns\n */\nfunction generateStringFromBatchTableByIndex(batchTable, index) {\n let str = '';\n for (const key in batchTable) {\n str += batchTable[key][index];\n }\n return str;\n}\n/**\n * Return already exited featureId or creates and returns new to support unique feature ids throw nodes.\n * @param index\n * @param batchTable\n * @param featuresHashArray\n * @returns\n */\nfunction getOrCreateUniqueFeatureId(index, batchTable, featuresHashArray) {\n const batchTableStr = generateStringFromBatchTableByIndex(batchTable, index);\n const hash = md5(batchTableStr);\n if (featuresHashArray.includes(hash)) {\n return featuresHashArray.indexOf(hash);\n }\n return featuresHashArray.push(hash) - 1;\n}\n/**\n * Do replacement of indices for making them unique through all nodes.\n * @param indicesArray\n * @param featureMap\n * @returns\n */\nfunction replaceIndicesByUnique(indicesArray, featureMap) {\n for (let index = 0; index < indicesArray.length; index++) {\n indicesArray[index] = featureMap[indicesArray[index]];\n }\n}\n/**\n * Convert property table data to attribute buffers.\n * @param featureIds\n * @param propertyTable - table with metadata for particular feature.\n * @param attributeStorageInfo\n * @returns - Array of file buffers.\n */\nfunction convertPropertyTableToAttributeBuffers(featureIds, featureIdsMap, propertyTable, attributeStorageInfo) {\n const attributeBuffers = [];\n const needFlattenPropertyTable = checkPropertiesLength(featureIds, propertyTable);\n const properties = needFlattenPropertyTable\n ? flattenPropertyTableByFeatureIds(featureIdsMap, propertyTable)\n : propertyTable;\n const propertyTableWithObjectIds = {\n OBJECTID: featureIds,\n ...properties\n };\n for (const propertyName in propertyTableWithObjectIds) {\n const type = getAttributeType(propertyName, attributeStorageInfo);\n if (type) {\n const value = propertyTableWithObjectIds[propertyName];\n const attributeBuffer = generateAttributeBuffer(type, value);\n attributeBuffers.push(attributeBuffer);\n }\n }\n return attributeBuffers;\n}\n/**\n * Generates attribute buffer based on attribute type\n * @param type\n * @param value\n */\nfunction generateAttributeBuffer(type, value) {\n let attributeBuffer;\n switch (type) {\n case OBJECT_ID_TYPE:\n case SHORT_INT_TYPE:\n attributeBuffer = generateShortIntegerAttributeBuffer(value);\n break;\n case DOUBLE_TYPE:\n attributeBuffer = generateDoubleAttributeBuffer(value);\n break;\n case STRING_TYPE:\n attributeBuffer = generateStringAttributeBuffer(value);\n break;\n default:\n attributeBuffer = generateStringAttributeBuffer(value);\n }\n return attributeBuffer;\n}\n/**\n * Return attribute type.\n * @param key\n * @param attributeStorageInfo\n * @returns attribute type.\n */\nfunction getAttributeType(key, attributeStorageInfo) {\n const attribute = attributeStorageInfo.find((attr) => attr.name === key);\n if (!attribute) {\n // eslint-disable-next-line no-console\n console.error(`attribute is null, key=${key}, attributeStorageInfo=${JSON.stringify(attributeStorageInfo, null, 2)}`);\n return '';\n }\n if (!attribute.attributeValues) {\n // eslint-disable-next-line no-console\n console.error(`attributeValues is null, attribute=${attribute}`);\n return '';\n }\n return attribute.attributeValues.valueType;\n}\n/**\n * Convert short integer to attribute arrayBuffer.\n * @param featureIds\n * @returns - Buffer with objectId data.\n */\nfunction generateShortIntegerAttributeBuffer(featureIds) {\n const count = new Uint32Array([featureIds.length]);\n const valuesArray = new Uint32Array(featureIds);\n return concatenateArrayBuffers(count.buffer, valuesArray.buffer);\n}\n/**\n * Convert double to attribute arrayBuffer.\n * @param featureIds\n * @returns - Buffer with objectId data.\n */\nfunction generateDoubleAttributeBuffer(featureIds) {\n const count = new Uint32Array([featureIds.length]);\n const padding = new Uint8Array(4);\n const valuesArray = new Float64Array(featureIds);\n return concatenateArrayBuffers(count.buffer, padding.buffer, valuesArray.buffer);\n}\n/**\n * Convert batch table attributes to array buffer with batch table data.\n * @param batchAttributes\n * @returns - Buffer with batch table data.\n */\nfunction generateStringAttributeBuffer(batchAttributes) {\n const stringCountArray = new Uint32Array([batchAttributes.length]);\n let totalNumberOfBytes = 0;\n const stringSizesArray = new Uint32Array(batchAttributes.length);\n const stringBufferArray = [];\n for (let index = 0; index < batchAttributes.length; index++) {\n const currentString = `${String(batchAttributes[index])}\\0`;\n const currentStringBuffer = Buffer.from(currentString);\n const currentStringSize = currentStringBuffer.length;\n totalNumberOfBytes += currentStringSize;\n stringSizesArray[index] = currentStringSize;\n stringBufferArray.push(currentStringBuffer);\n }\n const totalBytes = new Uint32Array([totalNumberOfBytes]);\n return concatenateArrayBuffers(stringCountArray.buffer, totalBytes.buffer, stringSizesArray.buffer, ...stringBufferArray);\n}\n/**\n * Convert featureIds to BigUint64Array.\n * @param featureIds\n * @returns - Array of feature ids in BigUint64 format.\n */\nfunction generateBigUint64Array(featureIds) {\n const typedFeatureIds = new BigUint64Array(featureIds.length);\n for (let index = 0; index < featureIds.length; index++) {\n typedFeatureIds[index] = BigInt(featureIds[index]);\n }\n return typedFeatureIds;\n}\n/**\n * Generates draco compressed geometry\n * @param vertexCount\n * @param convertedAttributes - get rid of this argument here\n * @param attributes - geometry attributes to compress\n * @param libraries - dynamicaly loaded 3rd-party libraries\n * @returns - Compressed geometry.\n */\nasync function generateCompressedGeometry(vertexCount, convertedAttributes, attributes, libraries) {\n const { positions, normals, texCoords, colors, uvRegions, featureIds, faceRange } = attributes;\n const indices = new Uint32Array(vertexCount);\n for (let index = 0; index < indices.length; index++) {\n indices.set([index], index);\n }\n const featureIndices = new Uint32Array(convertedAttributes.featureIndices.length ? convertedAttributes.featureIndices : vertexCount);\n const featureIndex = generateFeatureIndexAttribute(featureIndices, faceRange);\n const compressedAttributes = {\n positions,\n normals,\n colors,\n 'feature-index': featureIndex\n };\n if (texCoords.length) {\n compressedAttributes.texCoords = texCoords;\n }\n const attributesMetadata = {\n 'feature-index': {\n 'i3s-attribute-type': 'feature-index',\n 'i3s-feature-ids': new Int32Array(featureIds)\n }\n };\n if (uvRegions.length) {\n compressedAttributes['uv-region'] = uvRegions;\n attributesMetadata['uv-region'] = {\n 'i3s-attribute-type': 'uv-region'\n };\n }\n return encode({ attributes: compressedAttributes, indices }, \n // @ts-expect-error if encoded supports worker writer, we should update its type signature\n DracoWriterWorker, {\n ...DracoWriterWorker.options,\n reuseWorkers: true,\n _nodeWorkers: true,\n modules: libraries,\n useLocalLibraries: true,\n draco: {\n method: 'MESH_SEQUENTIAL_ENCODING',\n attributesMetadata\n },\n ['draco-writer']: {\n // We need to load local fs workers because nodejs can't load workers from the Internet\n workerUrl: './modules/draco/dist/draco-writer-worker-node.js'\n }\n });\n}\n/**\n * Generates ordered feature indices based on face range\n * @param featureIndex\n * @param faceRange\n * @returns\n */\nfunction generateFeatureIndexAttribute(featureIndex, faceRange) {\n const orderedFeatureIndices = new Uint32Array(featureIndex.length);\n let fillIndex = 0;\n let startIndex = 0;\n for (let index = 1; index < faceRange.length; index += 2) {\n const endIndex = (faceRange[index] + 1) * VALUES_PER_VERTEX;\n orderedFeatureIndices.fill(fillIndex, startIndex, endIndex);\n fillIndex++;\n startIndex = endIndex + 1;\n }\n return orderedFeatureIndices;\n}\n/**\n * Find property table in tile\n * For example it can be batchTable for b3dm files or property table in gLTF extension.\n * @param tileContent - 3DTiles tile content\n * @param metadataClass - user selected feature metadata class name\n * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA or EXT_STRUCTURAL_METADATA.\n */\nexport function getPropertyTable(tileContent, metadataClass) {\n if (!tileContent) {\n return null;\n }\n let propertyTable;\n const batchTableJson = tileContent.batchTableJson;\n if (batchTableJson) {\n return batchTableJson;\n }\n const { extensionName, extension } = getPropertyTableExtension(tileContent);\n switch (extensionName) {\n case EXT_STRUCTURAL_METADATA: {\n propertyTable = getPropertyTableFromExtStructuralMetadata(extension, metadataClass);\n return propertyTable;\n }\n case EXT_FEATURE_METADATA: {\n propertyTable = getPropertyTableFromExtFeatureMetadata(extension, metadataClass);\n return propertyTable;\n }\n default:\n return null;\n }\n}\n/**\n * Handles EXT_structural_metadata to get property table.\n * @param extension - Global level of EXT_STRUCTURAL_METADATA extension.\n * @param metadataClass - User selected feature metadata class name.\n * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.\n */\nfunction getPropertyTableFromExtStructuralMetadata(extension, metadataClass) {\n /**\n * Note, 3dTiles is able to have multiple featureId attributes and multiple feature tables.\n * In I3S we should decide which featureIds attribute will be passed to geometry data.\n * So, we take only the feature table / feature texture to generate attributes storage info object.\n * If the user has selected the metadataClass, the table with the corresponding class will be used,\n * or just the first one otherwise.\n */\n if (extension.propertyTables) {\n for (const propertyTable of extension.propertyTables) {\n if (propertyTable.class === metadataClass || !metadataClass) {\n return getPropertyData(propertyTable);\n }\n }\n }\n if (extension.propertyTextures) {\n for (const propertyTexture of extension.propertyTextures) {\n if (propertyTexture.class === metadataClass || !metadataClass) {\n return getPropertyData(propertyTexture);\n }\n }\n }\n return null;\n}\n/**\n * Handles EXT_feature_metadata to get property table.\n * @param extension - Global level of EXT_FEATURE_METADATA extension.\n * @param metadataClass - User selected feature metadata class name.\n * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.\n */\nfunction getPropertyTableFromExtFeatureMetadata(extension, metadataClass) {\n /**\n * Note, 3dTiles is able to have multiple featureId attributes and multiple feature tables.\n * In I3S we should decide which featureIds attribute will be passed to geometry data.\n * So, we take only the feature table / feature texture to generate attributes storage info object.\n * If the user has selected the metadataClass, the table with the corresponding class will be used,\n * or just the first one otherwise.\n */\n if (extension.featureTables) {\n for (const featureTableName in extension.featureTables) {\n const featureTable = extension.featureTables[featureTableName];\n if (featureTable.class === metadataClass || !metadataClass) {\n return getPropertyData(featureTable);\n }\n }\n }\n if (extension.featureTextures) {\n for (const featureTextureName in extension.featureTextures) {\n const featureTexture = extension.featureTextures[featureTextureName];\n if (featureTexture.class === metadataClass || !metadataClass) {\n return getPropertyData(featureTexture);\n }\n }\n }\n return null;\n}\n/**\n * Gets data from Property Table or Property Texture\n * @param featureObject - property table or texture from the extension\n * @returns Table containing property data\n */\nfunction getPropertyData(featureObject) {\n const propertyTableWithData = {};\n for (const propertyName in featureObject.properties) {\n propertyTableWithData[propertyName] = featureObject.properties[propertyName].data;\n }\n return propertyTableWithData;\n}\n/**\n * Check extensions which can be with property table inside.\n * @param tileContent - 3DTiles tile content\n */\nfunction getPropertyTableExtension(tileContent) {\n const extensionsWithPropertyTables = [EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA];\n const extensionsUsed = tileContent?.gltf?.extensionsUsed;\n if (!extensionsUsed) {\n return { extensionName: null, extension: null };\n }\n let extensionName = '';\n for (const extensionItem of tileContent?.gltf?.extensionsUsed || []) {\n if (extensionsWithPropertyTables.includes(extensionItem)) {\n extensionName = extensionItem;\n /*\n It returns the first extension containing the property table.\n We assume that there can be only one extension containing the property table:\n either EXT_FEATURE_METADATA, which is a depricated extension,\n or EXT_STRUCTURAL_METADATA.\n */\n break;\n }\n }\n if (!extensionName) {\n return { extensionName: null, extension: null };\n }\n const extension = tileContent?.gltf?.extensions?.[extensionName];\n return { extensionName, extension };\n}\n", "import { concatenateTypedArrays } from '@loaders.gl/loader-utils';\nconst VALUES_PER_VERTEX = 3;\nconst POSITIONS_AND_NORMALS_PER_TRIANGLE = 9;\n/**\n * Generate geometry attributes with faceRange and featureCount\n * @param attributes\n * @returns attirbutes with featureCount, featureIds and changed faceRange.\n */\nexport function generateAttributes(attributes) {\n const { positions, normals, texCoords, colors, uvRegions, featureIndices } = attributes;\n const triangleCount = positions.length / POSITIONS_AND_NORMALS_PER_TRIANGLE;\n if (!featureIndices.length) {\n return {\n faceRange: new Uint32Array([0, triangleCount - 1]),\n featureIds: [0],\n featureCount: 1,\n positions,\n normals,\n texCoords,\n colors,\n uvRegions\n };\n }\n const data = calculateFaceRangesAndFeaturesCount(featureIndices);\n const attributeObjects = makeAttributeObjects({ ...data, ...attributes });\n const unifiedAttributeObjectsByFeatureIds = unifyObjectsByFeatureId(attributeObjects);\n const groupedAttributes = groupAttributesAndRangesByFeatureId(unifiedAttributeObjectsByFeatureIds, data.featureCount);\n return groupedAttributes;\n}\n/**\n * Calculates face Ranges and feature count based on featureIndices.\n * @param featureIndices\n * @returns Object with featureCount, reordered attributes and changed faceRange.\n */\nfunction calculateFaceRangesAndFeaturesCount(featureIndices) {\n let rangeIndex = 1;\n let featureIndex = 1;\n let currentFeatureId = getFrequentValue(featureIndices.slice(0, VALUES_PER_VERTEX));\n const faceRangeList = [];\n const featureIds = [];\n const uniqueFeatureIds = [currentFeatureId];\n faceRangeList[0] = 0;\n featureIds[0] = currentFeatureId;\n for (let index = VALUES_PER_VERTEX; index < featureIndices.length; index += VALUES_PER_VERTEX) {\n const newFeatureId = getFrequentValue(featureIndices.slice(index, index + VALUES_PER_VERTEX));\n if (currentFeatureId !== newFeatureId) {\n faceRangeList[rangeIndex] = index / VALUES_PER_VERTEX - 1;\n faceRangeList[rangeIndex + 1] = index / VALUES_PER_VERTEX;\n featureIds[featureIndex] = newFeatureId;\n if (!uniqueFeatureIds.includes(newFeatureId)) {\n uniqueFeatureIds.push(newFeatureId);\n }\n rangeIndex += 2;\n featureIndex += 1;\n }\n currentFeatureId = newFeatureId;\n }\n faceRangeList[rangeIndex] = featureIndices.length / VALUES_PER_VERTEX - 1;\n const faceRange = new Uint32Array(faceRangeList);\n const featureCount = uniqueFeatureIds.length;\n return { faceRange, featureCount, featureIds };\n}\n/**\n * Find most frequent value to avoid situation where one vertex can be part of multiple features (objects).\n * @param values\n */\nfunction getFrequentValue(values) {\n const map = {};\n let mostFrequentValue = values[0];\n let maxCount = 1;\n for (const value of values) {\n // Save item and it's frequency count to the map.\n map[value] = (map[value] || 0) + 1;\n // Find max count of frequency.\n maxCount = maxCount > map[value] ? maxCount : map[value];\n // Find the most frequent value.\n mostFrequentValue = maxCount > map[value] ? mostFrequentValue : value;\n }\n return mostFrequentValue;\n}\n/**\n * Generate list of attribute object grouped by feature ids.\n * @param attributes\n * @returns sorted list of attribute objects.\n */\n// eslint-disable-next-line max-statements\nfunction makeAttributeObjects(attributes) {\n const { featureIds, positions, normals, colors, uvRegions, texCoords, faceRange = new Uint32Array(0) } = attributes;\n const groupedData = [];\n const positionsList = new Float32Array(positions);\n const normalsList = new Float32Array(normals);\n const colorsList = new Uint8Array(colors);\n const texCoordsList = new Float32Array(texCoords);\n const uvRegionsList = new Uint16Array(uvRegions);\n let positionsOffset = 0;\n let normalsOffset = 0;\n let colorsOffset = 0;\n let uvRegionsOffset = 0;\n let texCoordsOffset = 0;\n for (let index = 0; index < featureIds.length; index++) {\n const startIndex = faceRange[index * 2];\n const endIndex = faceRange[index * 2 + 1];\n const positionsCount = getSliceAttributeCount('positions', startIndex, endIndex);\n const normalsCount = getSliceAttributeCount('normals', startIndex, endIndex);\n const colorsCount = getSliceAttributeCount('colors', startIndex, endIndex);\n const uvRegionsCount = getSliceAttributeCount('uvRegions', startIndex, endIndex);\n const texCoordsCount = getSliceAttributeCount('texCoords', startIndex, endIndex);\n groupedData.push({\n featureId: featureIds[index],\n positions: positionsList.subarray(positionsOffset, positionsOffset + positionsCount),\n normals: normalsList.subarray(normalsOffset, normalsOffset + normalsCount),\n colors: colorsList.subarray(colorsOffset, colorsOffset + colorsCount),\n uvRegions: uvRegionsList.subarray(uvRegionsOffset, uvRegionsOffset + uvRegionsCount),\n texCoords: texCoordsList.subarray(texCoordsOffset, texCoordsOffset + texCoordsCount)\n });\n positionsOffset += positionsCount;\n normalsOffset += normalsCount;\n colorsOffset += colorsCount;\n uvRegionsOffset += uvRegionsCount;\n texCoordsOffset += texCoordsCount;\n }\n return groupedData;\n}\n/**\n * Generate sliced count for generating attribute objects depends on attribute name and range.\n * @param attributeName\n * @param startIndex\n * @param endIndex\n * @returns sliced count\n */\nfunction getSliceAttributeCount(attributeName, startIndex, endIndex) {\n const itemsPerVertex4 = 4;\n const texCoordsPerVertex = 2;\n const trianglesCount = endIndex - startIndex + 1;\n const vertexCount = trianglesCount * 3;\n switch (attributeName) {\n case 'positions':\n case 'normals':\n return trianglesCount * POSITIONS_AND_NORMALS_PER_TRIANGLE;\n case 'colors':\n case 'uvRegions':\n return vertexCount * itemsPerVertex4;\n case 'texCoords':\n return vertexCount * texCoordsPerVertex;\n default:\n return 0;\n }\n}\n/**\n * Generates unique object list depends on feature ids and concantenate their attributes.\n * @param sortedData\n * @returns unique list of objects\n */\nfunction unifyObjectsByFeatureId(sortedData) {\n const groupedMetadata = [];\n for (const data of sortedData) {\n const existingObject = groupedMetadata.find((obj) => obj.featureId === data.featureId);\n if (existingObject) {\n existingObject.attributes.push(data);\n }\n else {\n groupedMetadata.push({\n featureId: data.featureId,\n attributes: [data]\n });\n }\n }\n const uniqueObjects = [];\n for (const metatada of groupedMetadata) {\n const attributes = concatenateAttributes(metatada.attributes);\n uniqueObjects.push({\n featureId: metatada.featureId,\n ...attributes\n });\n }\n return uniqueObjects;\n}\n/**\n * Generates attribute objects with new faceRange and reordered attributes.\n * @param unifiedObjects\n * @returns generated attributes with new faceRange.\n */\nfunction groupAttributesAndRangesByFeatureId(unifiedObjects, featureCount) {\n const firstAttributeObject = unifiedObjects[0];\n const featureIds = [firstAttributeObject.featureId || 0];\n const range = [0];\n let objIndex = 0;\n let sum = 0;\n for (let index = 1; index < unifiedObjects.length; index++) {\n const currentAttributesObject = unifiedObjects[index];\n featureIds.push(currentAttributesObject.featureId || 0);\n const groupedObject = unifiedObjects[objIndex];\n range.push(groupedObject.positions.length / POSITIONS_AND_NORMALS_PER_TRIANGLE - 1 + sum);\n range.push(groupedObject.positions.length / POSITIONS_AND_NORMALS_PER_TRIANGLE + sum);\n sum += groupedObject.positions.length / POSITIONS_AND_NORMALS_PER_TRIANGLE;\n objIndex += 1;\n }\n const attributes = concatenateAttributes(unifiedObjects);\n range.push(attributes.positions.length / POSITIONS_AND_NORMALS_PER_TRIANGLE - 1);\n const faceRange = new Uint32Array(range);\n return { faceRange, featureIds, featureCount, ...attributes };\n}\n/**\n * Concatenate attributes typed arrays\n * @param attributes - grouped by featureId typed arrays\n * @returns - concatenated typed array list\n */\nfunction concatenateAttributes(attributes) {\n const positionGroups = attributes.map(({ positions }) => positions);\n const positions = positionGroups.length > 1 ? concatenateTypedArrays(...positionGroups) : positionGroups[0];\n const normalGroups = attributes.map(({ normals }) => normals);\n const normals = normalGroups.length > 1 ? concatenateTypedArrays(...normalGroups) : normalGroups[0];\n const colorGroups = attributes.map(({ colors }) => colors);\n const colors = colorGroups.length > 1 ? concatenateTypedArrays(...colorGroups) : colorGroups[0];\n const texCoordGroups = attributes.map(({ texCoords }) => texCoords);\n const texCoords = texCoordGroups.length > 1 ? concatenateTypedArrays(...texCoordGroups) : texCoordGroups[0];\n const uvRegionGroups = attributes.map(({ uvRegions }) => uvRegions);\n const uvRegions = uvRegionGroups.length > 1 ? concatenateTypedArrays(...uvRegionGroups) : uvRegionGroups[0];\n return {\n positions,\n normals,\n colors,\n texCoords,\n uvRegions\n };\n}\n", "import { Matrix3, Quaternion, Vector3 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\nimport { OrientedBoundingBox, makeOrientedBoundingBoxFromPoints, makeBoundingSphereFromPoints, BoundingSphere } from '@math.gl/culling';\n/**\n * Create bounding volumes object from tile and geoid height model.\n * @param sourceBoundingVolume - initialized bounding volume of the source tile\n * @param geoidHeightModel - instance of Geoid class that converts elevation from geoidal to ellipsoidal and back\n * @returns - Bounding volumes object\n */\nexport function createBoundingVolumes(sourceBoundingVolume, geoidHeightModel) {\n let radius;\n let halfSize;\n let quaternion;\n const cartographicCenter = Ellipsoid.WGS84.cartesianToCartographic(sourceBoundingVolume.center, new Vector3());\n cartographicCenter[2] =\n cartographicCenter[2] -\n geoidHeightModel.getHeight(cartographicCenter[1], cartographicCenter[0]);\n if (sourceBoundingVolume instanceof OrientedBoundingBox) {\n halfSize = sourceBoundingVolume.halfSize;\n radius = new Vector3(halfSize[0], halfSize[1], halfSize[2]).len();\n quaternion = sourceBoundingVolume.quaternion;\n }\n else {\n radius = sourceBoundingVolume.radius;\n halfSize = [radius, radius, radius];\n quaternion = new Quaternion()\n .fromMatrix3(new Matrix3([halfSize[0], 0, 0, 0, halfSize[1], 0, 0, 0, halfSize[2]]))\n .normalize();\n }\n return {\n mbs: [cartographicCenter[0], cartographicCenter[1], cartographicCenter[2], radius],\n obb: {\n center: [cartographicCenter[0], cartographicCenter[1], cartographicCenter[2]],\n halfSize,\n quaternion\n }\n };\n}\n/**\n * Generates bounding volumes from geometry positions\n * @param cartesianPositions\n * @param geoidHeightModel\n */\nexport function createBoundingVolumesFromGeometry(cartesianPositions, geoidHeightModel) {\n const positionVectors = convertPositionsToVectors(cartesianPositions);\n const geometryObb = makeOrientedBoundingBoxFromPoints(positionVectors);\n const geometryMbs = makeBoundingSphereFromPoints(positionVectors);\n const mbsCenter = Ellipsoid.WGS84.cartesianToCartographic(geometryMbs.center, new Vector3());\n const obbCenter = Ellipsoid.WGS84.cartesianToCartographic(geometryObb.center, new Vector3());\n mbsCenter[2] = mbsCenter[2] - geoidHeightModel.getHeight(mbsCenter[1], mbsCenter[0]);\n obbCenter[2] = obbCenter[2] - geoidHeightModel.getHeight(obbCenter[1], obbCenter[0]);\n return {\n mbs: [mbsCenter[0], mbsCenter[1], mbsCenter[2], geometryMbs.radius],\n obb: {\n center: obbCenter,\n halfSize: geometryObb.halfSize,\n quaternion: geometryObb.quaternion\n }\n };\n}\n/**\n * Create array of posisitons where each vertex is vector\n * @param {array} positions\n * @returns {Vector3[]}\n */\nexport function convertPositionsToVectors(positions) {\n const result = [];\n for (let i = 0; i < positions.length; i += 3) {\n // TODO: (perf) new Vector3 is not optimal but required in `makeOrientedBoundingBoxFromPoints`.\n // modify `makeOrientedBoundingBoxFromPoints` to use scratch vectors\n const positionVector = new Vector3([positions[i], positions[i + 1], positions[i + 2]]);\n result.push(positionVector);\n }\n return result;\n}\n/**\n * Convert common coordinate to fullExtent https://github.com/Esri/i3s-spec/blob/master/docs/1.8/fullExtent.cmn.md\n * @param boundingVolume\n * @returns - fullExtent object\n */\nexport function convertBoundingVolumeToI3SFullExtent(boundingVolume) {\n let sphere;\n if (boundingVolume instanceof BoundingSphere) {\n sphere = boundingVolume;\n }\n else {\n sphere = boundingVolume.getBoundingSphere();\n }\n const center = sphere.center;\n const radius = sphere.radius;\n const vertexMax = Ellipsoid.WGS84.cartesianToCartographic(new Vector3(center[0] + radius, center[1] + radius, center[2] + radius), new Vector3());\n const vertexMin = Ellipsoid.WGS84.cartesianToCartographic(new Vector3(center[0] - radius, center[1] - radius, center[2] - radius), new Vector3());\n // Converter sometimes returns min values that are bigger then max,\n // so we should check and take bigger value from max and smaller for nim\n return {\n xmin: Math.min(vertexMin[0], vertexMax[0]),\n xmax: Math.max(vertexMin[0], vertexMax[0]),\n ymin: Math.min(vertexMin[1], vertexMax[1]),\n ymax: Math.max(vertexMin[1], vertexMax[1]),\n zmin: Math.min(vertexMin[2], vertexMax[2]),\n zmax: Math.max(vertexMin[2], vertexMax[2])\n };\n}\n/**\n * Creates oriented boundinb box from mbs.\n * @param mbs - Minimum Bounding Sphere\n * @returns - Oriented Bounding Box\n */\nexport function createObbFromMbs(mbs) {\n const radius = mbs[3];\n const center = new Vector3(mbs[0], mbs[1], mbs[2]);\n const halfAxex = new Matrix3([radius, 0, 0, 0, radius, 0, 0, 0, radius]);\n return new OrientedBoundingBox(center, halfAxex);\n}\n", "import { Matrix4, Vector3 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\n/**\n * Prepare attributes for conversion to avoid binary data breaking in worker thread.\n * @param tileContent - 3DTiles tile content\n * @param tileTransform - transformation matrix of the tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n * @param boundingVolume - initialized bounding volume of the source tile\n * @returns 3DTiles content data, prepared for conversion\n */\nexport function prepareDataForAttributesConversion(tileContent, tileTransform, boundingVolume) {\n const nodes = tileContent.gltf?.scene?.nodes ||\n tileContent.gltf?.scenes?.[0]?.nodes ||\n tileContent.gltf?.nodes ||\n [];\n const images = tileContent.gltf?.images?.map((imageObject) => {\n // Need data only for uncompressed images because we can't get batchIds from compressed textures.\n if (imageObject?.image?.compressed) {\n return null;\n }\n const data = imageObject?.image?.data;\n const dataCopy = new Uint8Array(data.length);\n dataCopy.set(data);\n return {\n data: dataCopy,\n compressed: false,\n height: imageObject.image.height,\n width: imageObject.image.width,\n components: imageObject.image.components,\n mimeType: imageObject.mimeType\n };\n }) || [];\n prepareNodes(nodes);\n const { cartographicOrigin, modelMatrix: cartesianModelMatrix } = calculateTransformProps(tileContent, tileTransform, boundingVolume);\n return {\n nodes,\n images,\n cartographicOrigin,\n cartesianModelMatrix\n };\n}\n/**\n * Keep only values for glTF attributes to pass data to worker thread.\n * @param attributes - geometry attributes\n * @returns attributes with only `value` item\n */\nfunction getB3DMAttributesWithoutBufferView(attributes) {\n const attributesWithoutBufferView = {};\n for (const attributeName in attributes) {\n attributesWithoutBufferView[attributeName] = {\n value: attributes[attributeName].value\n };\n }\n return attributesWithoutBufferView;\n}\n/**\n * Calculate transformation properties to transform vertex attributes (POSITION, NORMAL, etc.)\n * from METER_OFFSET coorditantes to LNGLAT_OFFSET coordinates\n * @param tileContent - 3DTiles tile content\n * @param tileTransform - transformation matrix of the tile, calculated recursively multiplying\n * transform of all parent tiles and transform of the current tile\n * @param boundingVolume - initialized bounding volume of the source tile\n * @returns modelMatrix - transformation matrix to transform coordinates to cartographic coordinates\n * cartographicOrigin - tile origin coordinates to calculate offsets\n */\nexport function calculateTransformProps(tileContent, tileTransform, boundingVolume) {\n const { rtcCenter, gltfUpAxis } = tileContent;\n const { center } = boundingVolume;\n let modelMatrix = new Matrix4(tileTransform);\n // Translate if appropriate\n if (rtcCenter) {\n modelMatrix.translate(rtcCenter);\n }\n // glTF models need to be rotated from Y to Z up\n // https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#y-up-to-z-up\n switch (gltfUpAxis) {\n case 'Z':\n break;\n case 'Y':\n const rotationY = new Matrix4().rotateX(Math.PI / 2);\n modelMatrix = modelMatrix.multiplyRight(rotationY);\n break;\n case 'X':\n const rotationX = new Matrix4().rotateY(-Math.PI / 2);\n modelMatrix = modelMatrix.multiplyRight(rotationX);\n break;\n default:\n break;\n }\n const cartesianOrigin = new Vector3(center);\n const cartographicOrigin = Ellipsoid.WGS84.cartesianToCartographic(cartesianOrigin, new Vector3());\n return { modelMatrix, cartographicOrigin };\n}\n/**\n * Traverse all nodes to replace all sensible data with copy to avoid data corruption in worker.\n * @param nodes\n */\nfunction prepareNodes(nodes) {\n for (let index = 0; index < nodes.length; index++) {\n const node = nodes[index];\n if (node.mesh) {\n nodes[index] = {\n ...node,\n mesh: {\n ...node.mesh,\n primitives: node.mesh?.primitives.map((primitive) => ({\n ...primitive,\n indices: { value: primitive?.indices?.value },\n attributes: getB3DMAttributesWithoutBufferView(primitive.attributes),\n material: {\n id: primitive?.material?.id,\n uniqueId: primitive?.material?.uniqueId\n }\n }))\n }\n };\n }\n if (node.children) {\n prepareNodes(node.children);\n }\n }\n}\n", "import { emod } from '@loaders.gl/math';\nimport { EXT_MESH_FEATURES, EXT_FEATURE_METADATA } from '@loaders.gl/gltf';\n/**\n * Get featureTexture by a metadata class.\n * Metadata classes come from a structural metadata extesion (EXT_feature_metadata or EXT_structural_metadata).\n * The glTF might contain multiple texel-level metadata textures related to different classes. Having only one metadata class\n * selected to convert to I3S, we have to pick only one texture to convert to per-vertex property.\n * @param tileContent - 3d tile content\n * @param metadataClass - user selected feature metadata class name\n * @returns featureTexture key\n */\nexport function getTextureByMetadataClass(tileContent, metadataClass) {\n const extFeatureMetadata = tileContent.gltf?.extensions?.[EXT_FEATURE_METADATA];\n if (!extFeatureMetadata?.featureTextures) {\n return null;\n }\n for (const textureKey in extFeatureMetadata.featureTextures) {\n const texture = extFeatureMetadata.featureTextures[textureKey];\n if (texture.class === metadataClass) {\n return textureKey;\n }\n }\n return null;\n}\n/**\n * Getting batchIds from 3DTilesNext extensions.\n * @param attributes - gltf accessors\n * @param primitive - gltf primitive data\n * @param images - gltf texture images\n * @param featureTexture - feature texture key\n * @return array of batch IDs\n */\nexport function handleBatchIdsExtensions(attributes, primitive, images, featureTexture) {\n const extensions = primitive?.extensions;\n if (!extensions) {\n return [];\n }\n for (const [extensionName, extensionData] of Object.entries(extensions || {})) {\n switch (extensionName) {\n case EXT_FEATURE_METADATA:\n return handleExtFeatureMetadataExtension(attributes, extensionData, images, featureTexture);\n case EXT_MESH_FEATURES:\n return handleExtMeshFeaturesExtension(attributes, extensionData);\n default:\n return [];\n }\n }\n return [];\n}\n/**\n * Getting batchIds from EXT_mesh_features extensions.\n * @param attributes - gltf accessors\n * @param extMeshFeatures - EXT_mesh_features extension\n * @returns an array of attribute values\n */\nfunction handleExtMeshFeaturesExtension(attributes, extMeshFeatures) {\n for (const ids of extMeshFeatures.featureIds) {\n if (typeof ids.propertyTable !== 'undefined') {\n // propertyTable is an index that can be 0\n // return the first featureID set that corresponts to property table.\n return ids.data;\n }\n }\n return [];\n}\n/**\n * Get batchIds from EXT_feature_metadata extension.\n * @see - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata\n * @param attributes - glTF attributes\n * @param extFeatureMetadata - primitive-level EXT_FEATURE_METADATA extension data\n * @param textures - texture images\n * @param featureTexture - feature texture key\n */\nfunction handleExtFeatureMetadataExtension(attributes, extFeatureMetadata, images, featureTexture) {\n // Take only first extension object to get batchIds attribute name.\n const featureIdAttribute = extFeatureMetadata?.featureIdAttributes?.[0];\n if (featureIdAttribute?.featureIds?.attribute) {\n const batchIdsAttribute = attributes[featureIdAttribute.featureIds.attribute];\n return batchIdsAttribute.value;\n }\n if (featureIdAttribute?.featureIds?.hasOwnProperty('constant') &&\n featureIdAttribute?.featureIds?.hasOwnProperty('divisor')) {\n const featuresCount = attributes?.POSITIONS?.value.length / 3 || 0;\n return generateImplicitFeatureIds(featuresCount, featureIdAttribute.featureIds.constant, featureIdAttribute.featureIds.divisor);\n }\n // Take only first extension object to get batchIds attribute name.\n const featureIdTexture = extFeatureMetadata?.featureIdTextures && extFeatureMetadata?.featureIdTextures[0];\n if (featureIdTexture) {\n const textureAttributeIndex = featureIdTexture?.featureIds?.texture?.texCoord || 0;\n const textCoordAttribute = `TEXCOORD_${textureAttributeIndex}`;\n const textureCoordinates = attributes[textCoordAttribute].value;\n return generateBatchIdsFromTexture(featureIdTexture, textureCoordinates, images);\n }\n if (featureTexture) {\n const batchIdsAttribute = attributes[featureTexture];\n return batchIdsAttribute.value;\n }\n return [];\n}\n/**\n * Generates implicit feature ids\n * @see - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#implicit-feature-ids\n * @param featuresCount\n * @param constant\n * @param devisor\n */\nfunction generateImplicitFeatureIds(featuresCount, constant = 0, divisor = 0) {\n let featureIds = [];\n if (divisor > 0) {\n let currentValue = constant;\n let devisorCounter = divisor;\n for (let index = 0; index < featuresCount; index++) {\n featureIds.push(currentValue);\n devisorCounter -= 1;\n if (devisorCounter === 0) {\n currentValue++;\n devisorCounter = divisor;\n }\n }\n }\n else {\n featureIds = Array(featuresCount).fill(constant, 0, featuresCount);\n }\n return featureIds;\n}\n/**\n * Get batchIds from texture.\n * @param primitive\n * @param featureIdTextures\n */\nfunction generateBatchIdsFromTexture(featureIdTexture, textureCoordinates, images) {\n if (!images?.length) {\n return [];\n }\n const CHANNELS_MAP = {\n r: 0,\n g: 1,\n b: 2,\n a: 3\n };\n const textureIndex = featureIdTexture?.featureIds?.texture?.index;\n const featureChannel = featureIdTexture?.featureIds?.channels;\n if (!featureChannel || textureIndex === undefined) {\n return [];\n }\n const image = images[textureIndex];\n const batchIds = [];\n const channels = CHANNELS_MAP[featureChannel];\n if (image && image?.width && image?.height && image?.components) {\n for (let index = 0; index < textureCoordinates.length; index += 2) {\n const u = textureCoordinates[index];\n const v = textureCoordinates[index + 1];\n const tx = Math.min((emod(u) * image.width) | 0, image.width - 1);\n const ty = Math.min((emod(v) * image.height) | 0, image.height - 1);\n const offset = (ty * image.width + tx) * image.components + channels;\n const batchId = new Uint8Array(image.data)[offset];\n batchIds.push(batchId);\n }\n }\n else {\n // eslint-disable-next-line no-console\n console.warn(`Can't get batch Ids from ${image?.mimeType || ''} compressed texture`);\n }\n return batchIds;\n}\n", "import { AttributeType } from \"../types.js\";\nimport { EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA } from '@loaders.gl/gltf';\n/**\n * Takes attributes from property table based on featureIdsMap.\n * If there is no property value for particular featureId (index) the property will be null.\n * Example:\n * Initial data:\n * OBJECTID: {0: 0, 3: 33, 4: 333}\n * component: ['Windows', 'Frames', 'Wall', 'Roof', 'Skylight']\n * Result:\n * OBJECTID: [0, 33, 333]\n * component: ['Windows', 'Roof', 'Skylight']\n * @param featureIdsMap\n * @param propertyTable\n */\nexport function flattenPropertyTableByFeatureIds(featureIdsMap, propertyTable) {\n const resultPropertyTable = {};\n for (const propertyName in propertyTable) {\n const properties = propertyTable[propertyName];\n resultPropertyTable[propertyName] = getPropertiesByFeatureIds(properties, featureIdsMap);\n }\n return resultPropertyTable;\n}\n/**\n * Getting properties by featureId index\n * @param properties\n * @param featureIdsMap\n */\nfunction getPropertiesByFeatureIds(properties, featureIdsMap) {\n const resultProperties = [];\n if (properties) {\n for (const featureIdKey in featureIdsMap) {\n const property = properties[featureIdKey] || null;\n resultProperties.push(property);\n }\n }\n return resultProperties;\n}\n/**\n * Check that all attributes in propertyTable have the same length as FeatureIds.\n * If there are differencies between lengths we should flatten property table based on exiesting featureIds.\n * @param featureIds\n * @param propertyTable\n * @returns\n */\nexport function checkPropertiesLength(featureIds, propertyTable) {\n let needFlatten = false;\n for (const attribute of Object.values(propertyTable)) {\n if (!featureIds || !attribute || featureIds.length !== attribute.length) {\n needFlatten = true;\n }\n }\n return needFlatten;\n}\n/**\n * Get the attribute type for attributeStorageInfo https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md\n * @param attribute - attribute taken from propertyTable\n */\nexport function getAttributeType(attribute) {\n if (typeof attribute === 'string' || typeof attribute === 'bigint') {\n return AttributeType.STRING_TYPE;\n }\n else if (typeof attribute === 'number') {\n return Number.isInteger(attribute) ? AttributeType.SHORT_INT_TYPE : AttributeType.DOUBLE_TYPE;\n }\n return AttributeType.STRING_TYPE;\n}\n/**\n * Gets attribute's types based on the property table records.\n * @param propertyTable - Table with layer meta data.\n * @returns set of attribute types\n * @example of returned object:\n * {\n * \"opt_uint8\": \"Int32\",\n * \"opt_uint64\": \"string\"\n * }\n */\nexport function getAttributeTypesMapFromPropertyTable(propertyTable) {\n const attributeTypesMap = {};\n for (const key in propertyTable) {\n // Get attribute type based on the first element of each property.\n const firstAttribute = propertyTable[key][0];\n const attributeType = getAttributeType(firstAttribute);\n attributeTypesMap[key] = attributeType;\n }\n return attributeTypesMap;\n}\n/**\n * Gets attribute's types from the extension schema selected by the class name 'metadataClass'.\n * @param gltfJson - JSON part of GLB content\n * @param metadataClass - name of the schema class\n * @returns set of attribute's types\n * @example of returned object:\n * {\n * \"opt_uint8\": \"Int32\",\n * \"opt_uint64\": \"string\"\n * }\n */\nexport const getAttributeTypesMapFromSchema = (gltfJson, metadataClass) => {\n const attributeTypesMap = {};\n const extFeatureMetadataSchemaClass = gltfJson.extensions?.[EXT_FEATURE_METADATA]?.schema?.classes?.[metadataClass];\n if (extFeatureMetadataSchemaClass) {\n for (const propertyName in extFeatureMetadataSchemaClass.properties) {\n const property = extFeatureMetadataSchemaClass.properties[propertyName];\n const attributeProperty = getAttributeTypeFromExtFeatureMetadata(property);\n attributeTypesMap[propertyName] = attributeProperty;\n }\n return attributeTypesMap;\n }\n const extStructuralMetadataSchemaClass = gltfJson.extensions?.[EXT_STRUCTURAL_METADATA]?.schema?.classes?.[metadataClass];\n if (extStructuralMetadataSchemaClass) {\n for (const propertyName in extStructuralMetadataSchemaClass.properties) {\n const property = extStructuralMetadataSchemaClass.properties[propertyName];\n const attributeProperty = getAttributeTypeFromExtStructuralMetadata(property);\n attributeTypesMap[propertyName] = attributeProperty;\n }\n return attributeTypesMap;\n }\n return null;\n};\n/**\n * Gets the attribute type according to the Ext_feature_metadata extension class schema\n * @see https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md\n * @param property - schema of the class property for Ext_feature_metadata\n * @returns attribute's type\n */\n// eslint-disable-next-line complexity\nconst getAttributeTypeFromExtFeatureMetadata = (property) => {\n let attributeType;\n switch (property.type) {\n case 'INT8':\n case 'UINT8':\n case 'INT16':\n case 'UINT16':\n case 'INT32':\n case 'UINT32':\n attributeType = AttributeType.SHORT_INT_TYPE;\n break;\n case 'FLOAT32':\n case 'FLOAT64':\n attributeType = AttributeType.DOUBLE_TYPE;\n break;\n case 'INT64':\n case 'UINT64':\n case 'BOOLEAN':\n case 'ENUM':\n case 'STRING':\n case 'ARRAY':\n attributeType = AttributeType.STRING_TYPE;\n break;\n default:\n attributeType = AttributeType.STRING_TYPE;\n break;\n }\n return attributeType;\n};\n/**\n * Gets the attribute type according to the Ext_structural_metadata extension class schema\n * @see https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md\n * @param property - schema of the class property for Ext_structural_metadata\n * @returns attribute's type\n */\n// eslint-disable-next-line complexity\nconst getAttributeTypeFromExtStructuralMetadata = (property) => {\n let attributeType;\n if (property.array) {\n attributeType = AttributeType.STRING_TYPE;\n }\n else {\n switch (property.componentType) {\n case 'INT8':\n case 'UINT8':\n case 'INT16':\n case 'UINT16':\n case 'INT32':\n case 'UINT32':\n attributeType = AttributeType.SHORT_INT_TYPE;\n break;\n case 'FLOAT32':\n case 'FLOAT64':\n attributeType = AttributeType.DOUBLE_TYPE;\n break;\n case 'INT64':\n case 'UINT64':\n attributeType = AttributeType.STRING_TYPE;\n break;\n default:\n attributeType = AttributeType.STRING_TYPE;\n break;\n }\n }\n return attributeType;\n};\n", "/**\n * luma.gl can not work without indices now:\n * https://github.com/visgl/luma.gl/blob/d8cad75b9f8ca3e578cf078ed9d19e619c2ddbc9/modules/experimental/src/gltf/gltf-instantiator.js#L115\n * This method generates syntetic indices array: [0, 1, 2, 3, .... , vertexCount-1]\n * @param {number} vertexCount - vertex count in the geometry\n * @returns {Uint32Array} indices array.\n */\nexport const generateSyntheticIndices = (vertexCount) => {\n const result = new Uint32Array(vertexCount);\n for (let index = 0; index < vertexCount; index++) {\n result[index] = index;\n }\n return result;\n};\n", "import { v4 as uuidv4 } from 'uuid';\nimport transform from 'json-map-transform';\nimport { join } from 'path';\nimport { SCENE_SERVER as sceneServerTemplate } from \"../json-templates/scene-server.js\";\nimport { writeFile } from \"../../lib/utils/file-utils.js\";\n/**\n * Form and save sceneServer meta data into a file\n * @param layerName - layer name to display\n * @param layers0 - layer object embedded into sceneServer meta data\n * @param rootPath - root path of new converted tileset\n */\nexport async function createSceneServerPath(layerName, layers0, rootPath) {\n const sceneServerData = {\n serviceItemId: uuidv4().replace(/-/gi, ''),\n layerName,\n layers0\n };\n const sceneServer = transform(sceneServerData, sceneServerTemplate());\n const nodePagePath = join(rootPath, 'SceneServer');\n await writeFile(nodePagePath, JSON.stringify(sceneServer));\n}\n", "export const SCENE_SERVER = () => ({\n serviceItemId: {\n path: 'serviceItemId'\n },\n serviceName: {\n path: 'layerName'\n },\n name: {\n path: 'layerName'\n },\n currentVersion: {\n path: 'currentVersion',\n default: 10.7\n },\n serviceVersion: {\n path: 'serviceVersion',\n default: '1.8'\n },\n supportedBindings: {\n path: 'supportedBindings',\n default: ['REST']\n },\n layers: {\n path: 'layers0',\n transform: (layers0) => [layers0]\n }\n});\n", "// https://cesium.com/docs/cesiumjs-ref-doc/Cesium3DTileset.html\nconst DEFAULT_MAXIMUM_SCREEN_SPACE_ERROR = 16;\n/**\n * Do conversion from geometric error to screen threshold\n *\n * In 3DTiles we have HLOD logic and parent tile also has bigger lodMetric value then its children.\n * In I3s we have reverse logic related to maxError. Parent has lower maxError than its child.\n * In nodes where are no children tile.lodMetricValue is 0. This is because of logic of HLOD in 3DTiles\n * 3DTiles spec:\n * https://github.com/CesiumGS/3d-tiles/tree/master/specification#geometric-error\n * I3S spec:\n * https://github.com/Esri/i3s-spec/blob/master/docs/1.7/lodSelection.cmn.md\n * To avoid infinity values when we do calculations of maxError we shold replace 0 with value which allows us\n * to make child maxError bigger than his parent maxError.\n *\n * @param tile - 3d-tiles tile JSON\n * @param coordinates - node converted coordinates\n * @returns An array of LOD metrics in format compatible with i3s 3DNodeIndexDocument.lodSelection\n * @example\n * [\n {\n \"metricType\": \"maxScreenThresholdSQ\",\n \"maxError\": 870638.071285568\n },\n {\n \"metricType\": \"maxScreenThreshold\",\n \"maxError\": 1052.8679031638949\n }\n ]\n */\nexport function convertGeometricErrorToScreenThreshold(tile, coordinates) {\n const lodSelection = [];\n const boundingVolume = tile.boundingVolume;\n const lodMetricValue = tile.lodMetricValue || 0.1;\n const maxScreenThreshold = {\n metricType: 'maxScreenThreshold',\n maxError: (coordinates.mbs[3] * 2 * DEFAULT_MAXIMUM_SCREEN_SPACE_ERROR) / lodMetricValue\n };\n const maxScreenThresholdSQ = {\n metricType: 'maxScreenThresholdSQ',\n maxError: Math.PI * 0.25 * maxScreenThreshold.maxError * maxScreenThreshold.maxError\n };\n if (boundingVolume.constructor.name === 'OrientedBoundingBox') {\n lodSelection.push(maxScreenThresholdSQ);\n lodSelection.push(maxScreenThreshold);\n }\n else {\n lodSelection.push(maxScreenThreshold);\n lodSelection.push(maxScreenThresholdSQ);\n }\n return lodSelection;\n}\n/**\n * Convert LOD metric from \"Screen Threshold\" to \"Screen Space Error\"\n * @param node - i3s node data\n * @returns lod metric in 3d-tiles format\n */\nexport function convertScreenThresholdToGeometricError(node) {\n const metricData = node.lodSelection?.find((metric) => metric.metricType === 'maxScreenThreshold');\n let maxError = metricData?.maxError;\n if (!maxError) {\n const sqMetricData = node.lodSelection?.find((metric) => metric.metricType === 'maxScreenThresholdSQ');\n if (sqMetricData) {\n maxError = Math.sqrt(sqMetricData.maxError / (Math.PI * 0.25));\n }\n }\n if (!maxError) {\n maxError = DEFAULT_MAXIMUM_SCREEN_SPACE_ERROR;\n }\n return (node.mbs[3] * 2 * DEFAULT_MAXIMUM_SCREEN_SPACE_ERROR) / maxError;\n}\n", "import { Geoid, parsePGM } from '@math.gl/geoid';\n// __VERSION__ is injected by babel-plugin-version-inline\n// @ts-ignore TS2304: Cannot find name '__VERSION__'.\nconst VERSION = typeof \"4.2.0-beta.2\" !== 'undefined' ? \"4.2.0-beta.2\" : 'latest';\nexport { Geoid };\n/**\n * Loader for PGM - Netpbm grayscale image format\n */\nexport const PGMLoader = {\n dataType: null,\n batchType: null,\n name: 'PGM - Netpbm grayscale image format',\n id: 'pgm',\n module: 'tile-converter',\n version: VERSION,\n mimeTypes: ['image/x-portable-graymap'],\n parse: async (arrayBuffer, options) => parsePGM(new Uint8Array(arrayBuffer), options?.pgm || {}),\n extensions: ['pgm'],\n options: {\n pgm: {\n cubic: false\n }\n }\n};\n", "import transform from 'json-map-transform';\nimport { STORE } from \"./store.js\";\nconst SPATIAL_REFERENCE = () => ({\n wkid: {\n path: 'wkid',\n default: 4326\n },\n latestWkid: {\n path: 'latestWkid',\n default: 4326\n },\n vcsWkid: {\n path: 'vcsWkid',\n default: 5773\n },\n latestVcsWkid: {\n path: 'latestVcsWkid',\n default: 5773\n }\n});\nconst HEIGHT_MODEL_INFO = () => ({\n heightModel: {\n path: 'heightModel',\n default: 'gravity_related_height'\n },\n vertCRS: {\n path: 'vertCRS',\n default: 'EGM96_Geoid'\n },\n heightUnit: {\n path: 'heightUnit',\n default: 'meter'\n }\n});\nconst NODE_PAGES = () => ({\n nodesPerPage: {\n path: 'nodesPerPage'\n },\n lodSelectionMetricType: {\n path: 'lodSelectionMetricType',\n default: 'maxScreenThresholdSQ'\n }\n});\nconst FULL_EXTENT = () => ({\n xmin: {\n path: 'xmin'\n },\n ymin: {\n path: 'ymin'\n },\n xmax: {\n path: 'xmax'\n },\n ymax: {\n path: 'ymax'\n },\n zmin: {\n path: 'zmin'\n },\n zmax: {\n path: 'zmax'\n }\n});\nexport const LAYERS = () => ({\n version: {\n path: 'version',\n transform: (val) => val.toUpperCase()\n },\n id: {\n path: 'id',\n default: 0\n },\n name: {\n path: 'name'\n },\n href: {\n path: 'href',\n default: './layers/0'\n },\n layerType: {\n path: 'layerType',\n default: 'IntegratedMesh'\n },\n spatialReference: {\n path: 'spatialReference',\n transform: (val) => transform(val, SPATIAL_REFERENCE())\n },\n capabilities: {\n path: 'capabilities',\n default: ['View', 'Query']\n },\n store: {\n path: 'store',\n transform: (val) => transform(val, STORE)\n },\n fullExtent: {\n path: 'fullExtent',\n transform: (val) => transform(val, FULL_EXTENT())\n },\n heightModelInfo: {\n path: 'heightModelInfo',\n transform: (val) => transform(val, HEIGHT_MODEL_INFO())\n },\n nodePages: {\n path: 'nodePages',\n transform: (val) => transform(val, NODE_PAGES())\n },\n materialDefinitions: {\n path: 'materialDefinitions',\n default: []\n },\n textureSetDefinitions: {\n path: 'textureSetDefinitions',\n default: []\n },\n geometryDefinitions: {\n path: 'geometryDefinitions',\n default: []\n },\n attributeStorageInfo: {\n path: 'attributeStorageInfo',\n default: []\n },\n fields: {\n path: 'fields',\n default: []\n },\n popupInfo: {\n path: 'popupInfo',\n default: null\n }\n});\n", "export const STORE = {\n id: {\n path: 'id',\n transform: (val) => val.toUpperCase()\n },\n profile: {\n path: 'profile',\n default: 'meshpyramids'\n },\n version: {\n path: 'version',\n default: '1.8'\n },\n resourcePattern: {\n path: 'resourcePattern',\n default: ['3dNodeIndexDocument', 'Attributes', 'SharedResource', 'Geometry']\n },\n rootNode: {\n path: 'rootNode',\n default: './nodes/root'\n },\n extent: {\n path: 'extent'\n },\n indexCRS: {\n path: 'indexCRS',\n default: 'http://www.opengis.net/def/crs/EPSG/0/4326'\n },\n vertexCRS: {\n path: 'vertexCRS',\n default: 'http://www.opengis.net/def/crs/EPSG/0/4326'\n },\n normalReferenceFrame: {\n path: 'normalReferenceFrame',\n default: 'east-north-up'\n },\n attributeEncoding: {\n path: 'attributeEncoding',\n default: 'application/octet-stream; version=1.6'\n },\n textureEncoding: {\n path: 'textureEncoding',\n default: ['image/jpeg', 'image/ktx2']\n },\n lodType: {\n path: 'lodType',\n default: 'MeshPyramid'\n },\n lodModel: {\n path: 'lodModel',\n default: 'node-switching'\n },\n defaultGeometrySchema: {\n path: 'defaultGeometrySchema',\n default: {\n geometryType: 'triangles',\n header: [\n {\n property: 'vertexCount',\n type: 'UInt32'\n },\n {\n property: 'featureCount',\n type: 'UInt32'\n }\n ],\n topology: 'PerAttributeArray',\n ordering: ['position', 'normal', 'uv0', 'color'],\n vertexAttributes: {\n position: {\n valueType: 'Float32',\n valuesPerElement: 3\n },\n normal: {\n valueType: 'Float32',\n valuesPerElement: 3\n },\n uv0: {\n valueType: 'Float32',\n valuesPerElement: 2\n },\n color: {\n valueType: 'UInt8',\n valuesPerElement: 4\n }\n },\n featureAttributeOrder: ['id', 'faceRange'],\n featureAttributes: {\n id: {\n valueType: 'UInt64',\n valuesPerElement: 1\n },\n faceRange: {\n valueType: 'UInt32',\n valuesPerElement: 2\n }\n }\n }\n }\n};\n", "import transform from 'json-map-transform';\nconst PLAIN_GEOMETRY_DEFINITION = () => ({\n offset: {\n default: 8\n },\n position: {\n default: {\n type: 'Float32',\n component: 3\n }\n },\n normal: {\n default: {\n type: 'Float32',\n component: 3\n }\n },\n uv0: {\n path: 'hasTexture',\n transform: (val) => (val && { type: 'Float32', component: 2 }) || false,\n omitValues: [false]\n },\n color: {\n default: {\n type: 'UInt8',\n component: 4\n }\n },\n uvRegion: {\n path: 'hasUvRegions',\n transform: (val) => (val && { type: 'UInt16', component: 4 }) || false,\n omitValues: [false]\n },\n featureId: {\n default: {\n binding: 'per-feature',\n type: 'UInt64',\n component: 1\n }\n },\n faceRange: {\n default: {\n binding: 'per-feature',\n type: 'UInt32',\n component: 2\n }\n }\n});\nconst COMPRESSED_GEOMETRY_DEFINITION = () => ({\n 'compressedAttributes.encoding': {\n default: 'draco'\n },\n 'compressedAttributes.attributes': {\n path: 'geometryConfig',\n transform: (val) => {\n const result = ['position', 'normal'];\n if (val.hasTexture) {\n result.push('uv0');\n }\n result.push('color');\n if (val.hasUvRegions) {\n result.push('uv-region');\n }\n result.push('feature-index');\n return result;\n }\n }\n});\nexport const GEOMETRY_DEFINITION = () => ({\n geometryBuffers: {\n path: 'geometryConfig',\n transform: (val) => {\n const result = [transform(val, PLAIN_GEOMETRY_DEFINITION())];\n if (val.draco) {\n result.push(transform({ geometryConfig: val }, COMPRESSED_GEOMETRY_DEFINITION()));\n }\n return result;\n }\n }\n});\n", "import transform from 'json-map-transform';\nconst MATERIAL_DEFINITION_INFO_PARAMS = () => ({\n renderMode: {\n path: 'renderMode',\n default: 'solid'\n },\n shininess: {\n path: 'shininess',\n default: 1\n },\n reflectivity: {\n path: 'reflectivity',\n default: 0\n },\n ambient: {\n path: 'ambient',\n default: [1, 1, 1]\n },\n diffuse: {\n path: 'diffuse',\n default: [1, 1, 1]\n },\n specular: {\n path: 'specular',\n default: [0, 0, 0]\n },\n useVertexColorAlpha: {\n path: 'useVertexColorAlpha',\n default: false\n },\n vertexRegions: {\n path: 'vertexRegions',\n default: false\n },\n vertexColors: {\n path: 'vertexColors',\n default: true\n }\n});\nconst MATERIAL_DEFINITION_INFO = () => ({\n name: {\n path: 'name',\n default: 'standard'\n },\n type: {\n path: 'type',\n default: 'standard'\n },\n params: {\n path: 'params',\n transform: (val, thisObject, originalObject) => transform(originalObject, MATERIAL_DEFINITION_INFO_PARAMS())\n }\n});\nconst TEXTURE_DEFINITION_IMAGE = () => ({\n id: {\n path: 'id'\n },\n size: {\n path: 'size'\n },\n href: {\n path: 'href',\n default: ['../textures/0']\n },\n length: {\n path: 'length'\n }\n});\nconst TEXTURE_DEFINITION_INFO = () => ({\n encoding: {\n path: 'encoding'\n },\n wrap: {\n path: 'wrap',\n default: ['none']\n },\n atlas: {\n path: 'atlas',\n default: false\n },\n uvSet: {\n path: 'uvSet',\n default: 'uv0'\n },\n channels: {\n path: 'channels',\n default: 'rgb'\n },\n images: {\n path: 'images',\n transform: (val, thisObject, originalObject) => val.map((image) => transform(image, TEXTURE_DEFINITION_IMAGE()))\n }\n});\nexport const SHARED_RESOURCES = () => ({\n materialDefinitions: {\n path: 'materialDefinitionInfos',\n transform: transfromMaterialDefinitions\n },\n textureDefinitions: {\n path: 'textureDefinitionInfos',\n transform: transfromTextureDefinitions\n }\n});\nfunction transfromMaterialDefinitions(materialDefinitionInfos, thisObject, originalObject) {\n const result = {};\n for (const [index, materialDefinitionInfo] of materialDefinitionInfos.entries()) {\n result[`Mat${originalObject.nodePath}${index}`] = transform(materialDefinitionInfo, MATERIAL_DEFINITION_INFO());\n }\n return result;\n}\nfunction transfromTextureDefinitions(textureDefinitionInfos, thisObject, originalObject) {\n if (!textureDefinitionInfos) {\n return null;\n }\n const result = {};\n for (const [index, textureDefinitionInfo] of textureDefinitionInfos.entries()) {\n const imageIndex = `${originalObject.nodePath}${index}`;\n textureDefinitionInfo.imageIndex = imageIndex;\n result[imageIndex] = transform(textureDefinitionInfo, TEXTURE_DEFINITION_INFO());\n }\n return result;\n}\n", "import { OrientedBoundingBox, BoundingSphere } from '@math.gl/culling';\nimport { Vector3 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\n// prettier-ignore\nconst CUBE_POSITIONS = new Float32Array([\n -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1,\n -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1,\n -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1,\n -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1,\n 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1,\n -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1\n]);\n// TODO Unite Tile validation logic in i3s-17-and-debug with this code.\n/**\n * Do validation of bounding volumes for particular node.\n * Generates special warnings if there are some issues.\n * @param node\n */\nexport function validateNodeBoundingVolumes(node) {\n if (!node?.parentNode?.obb || !node?.parentNode?.mbs) {\n return [];\n }\n const tileWarnings = [];\n validateObb(tileWarnings, node);\n validateMbs(tileWarnings, node);\n return tileWarnings;\n}\n/**\n * Check if child Obb fit into parent Obb.\n * @param tileWarnings\n * @param node\n */\nfunction validateObb(tileWarnings, node) {\n // @ts-expect-error\n const parentObb = createBoundingBoxFromTileObb(node.parentNode.obb);\n const tileVertices = getTileObbVertices(node);\n const isTileObbInsideParentObb = isAllVerticesInsideBoundingVolume(parentObb, tileVertices);\n if (isTileObbInsideParentObb) {\n return;\n }\n const title = `OBB of Tile (${node.id}) doesn't fit into Parent (${node.parentNode?.id}) tile OBB`;\n tileWarnings.push(title);\n}\n/**\n * Check if child Mbs fit into parent Mbs.\n * @param tileWarnings\n * @param node\n */\nfunction validateMbs(tileWarnings, node) {\n // @ts-expect-error\n const tileMbs = createBoundingSphereFromTileMbs(node.mbs);\n // @ts-expect-error\n const parentMbs = createBoundingSphereFromTileMbs(node.parentNode.mbs);\n const distanceBetweenCenters = tileMbs.center.distanceTo(parentMbs.center);\n if (distanceBetweenCenters + tileMbs.radius > parentMbs.radius) {\n const title = `MBS of Tile (${node.id}) doesn't fit into Parent (${node.parentNode?.id}) tile MBS`;\n tileWarnings.push(title);\n }\n}\n/**\n * Generates bounding sphere from mbs\n * @param mbs\n */\nfunction createBoundingSphereFromTileMbs(mbs) {\n return new BoundingSphere([mbs[0], mbs[1], mbs[2]], mbs[3]);\n}\n/**\n * Generates oriented bounding box from tile obb\n * @param obb\n * @returns\n */\nfunction createBoundingBoxFromTileObb(obb) {\n const { center, halfSize, quaternion } = obb;\n return new OrientedBoundingBox().fromCenterHalfSizeQuaternion(center, halfSize, quaternion);\n}\n/**\n * Get vertices fromnode obb\n * TODO check if Obb generates properly\n * @param node\n */\nfunction getTileObbVertices(node) {\n // @ts-expect-error\n const halfSize = node.obb.halfSize;\n const positions = CUBE_POSITIONS;\n // @ts-expect-error\n const obbCenterCartesian = Ellipsoid.WGS84.cartographicToCartesian(node.obb.center);\n let vertices = [];\n for (let i = 0; i < positions.length; i += 3) {\n const positionsVector = new Vector3((positions[i] *= halfSize[0]), (positions[i + 1] *= halfSize[1]), (positions[i + 2] *= halfSize[2]));\n const rotatedPositions = positionsVector\n // @ts-expect-error\n .transformByQuaternion(node.obb.quaternion)\n .add(obbCenterCartesian);\n // @ts-expect-error\n vertices = vertices.concat(rotatedPositions);\n }\n return vertices;\n}\n/**\n * Check if all vertices inside bounding volume\n * @param boundingVolume\n * @param positions\n */\nfunction isAllVerticesInsideBoundingVolume(boundingVolume, positions) {\n let isVerticesInsideObb = true;\n for (let index = 0; index < positions.length / 3; index += 3) {\n const point = [positions[index], positions[index + 1], positions[index + 2]];\n const cartographicPoint = Ellipsoid.WGS84.cartesianToCartographic(point);\n const distance = boundingVolume.distanceTo(cartographicPoint);\n if (distance > 0) {\n isVerticesInsideObb = false;\n break;\n }\n }\n return isVerticesInsideObb;\n}\n", "export class Queue extends Array {\n enqueue(val) {\n this.push(val);\n }\n dequeue() {\n return this.shift();\n }\n peek() {\n return this[0];\n }\n isEmpty() {\n return this.length === 0;\n }\n}\n", "import { Queue } from \"./queue.js\";\nimport process from 'process';\n/** Memory limit size is based on testing */\nconst MEMORY_LIMIT = 4 * 1024 * 1024 * 1024; // 4GB\nexport default class WriteQueue extends Queue {\n intervalId; // eslint-disable-line no-undef\n conversionDump;\n writePromise = null;\n fileMap = {};\n listeningInterval;\n writeConcurrency;\n constructor(conversionDump, listeningInterval = 2000, writeConcurrency = 400) {\n super();\n this.conversionDump = conversionDump;\n this.listeningInterval = listeningInterval;\n this.writeConcurrency = writeConcurrency;\n }\n async enqueue(val, writeImmediately = false) {\n if (writeImmediately) {\n const { archiveKey, writePromise } = val;\n const result = await writePromise();\n if (archiveKey && result) {\n this.fileMap[archiveKey] = result;\n }\n }\n else {\n super.enqueue(val);\n /** https://nodejs.org/docs/latest-v14.x/api/process.html#process_process_memoryusage */\n if (process.memoryUsage().rss > MEMORY_LIMIT) {\n await this.startWrite();\n }\n }\n }\n startListening() {\n this.intervalId = setInterval(() => this.startWrite.bind(this), this.listeningInterval);\n }\n stopListening() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n async startWrite() {\n if (!this.writePromise) {\n this.writePromise = this.doWrite();\n }\n await this.writePromise;\n this.writePromise = null;\n }\n async finalize() {\n this.stopListening();\n await this.startWrite();\n }\n async doWrite() {\n while (this.length) {\n const promises = [];\n const archiveKeys = [];\n const changedRecords = [];\n for (let i = 0; i < this.writeConcurrency; i++) {\n const item = this.dequeue();\n if (!item) {\n break;\n }\n const { archiveKey, sourceId, outputId, resourceType, writePromise } = item;\n archiveKeys.push(archiveKey);\n changedRecords.push({ sourceId, outputId, resourceType });\n const promise = writePromise();\n promises.push(promise);\n }\n const writeResults = await Promise.allSettled(promises);\n this.updateFileMap(archiveKeys, writeResults);\n await this.conversionDump.updateConvertedTilesDump(changedRecords, writeResults);\n }\n }\n updateFileMap(archiveKeys, writeResults) {\n for (let i = 0; i < archiveKeys.length; i++) {\n const archiveKey = archiveKeys[i];\n if (archiveKey && 'value' in writeResults[i]) {\n this.fileMap[archiveKey] = writeResults[i].value;\n }\n }\n }\n}\n", "export const BROWSER_ERROR_MESSAGE = 'Tile converter does not work in browser, only in node js environment';\nexport const DUMP_FILE_SUFFIX = '.dump.json';\n", "import { join } from 'path';\nimport transform from 'json-map-transform';\nimport { v4 as uuidv4 } from 'uuid';\nimport { openJson, writeFile, writeFileForSlpk } from \"../../lib/utils/file-utils.js\";\nimport { NODE as nodeTemplate } from \"../json-templates/node.js\";\n/**\n * Wrapper for https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md data\n * The class allows working with 3DNodeIndexDocument in 2 modes:\n * in memory: the data is stored in `data` field\n * on disk: the data is written on disk in a file. The file can be rewritten when new childrend or neighbors have to be added\n */\nexport class NodeIndexDocument {\n /** Node id */\n id;\n /** Id in node pages */\n inPageId;\n /** 3DNodeIndexDocument data */\n data = null;\n /** children */\n children = [];\n /** converter instance */\n converter;\n /**\n * Finalized property. It means that all child nodes are saved and their data\n * is unloaded\n */\n _finalized = false;\n get finalized() {\n return this._finalized;\n }\n /**\n * Constructor\n * @param id - id of the node in node pages\n * @param converter - converter instance\n */\n constructor(id, converter) {\n this.inPageId = id;\n this.id = id === 0 ? 'root' : id.toString();\n this.converter = converter;\n }\n /**\n * Add Node3DIndexDocument data to the node\n * @param data Node3DIndexDocument data\n * @returns this NodeIndexDocument instance (to recurring with constructor)\n */\n async addData(data) {\n if (this.converter.options.instantNodeWriting) {\n await this.write(data);\n }\n else {\n this.data = data;\n }\n return this;\n }\n /**\n * Add child node references\n * @param childNodes - child NodeIndexDocument instances\n */\n async addChildren(childNodes) {\n const newChildren = [];\n for (const node of childNodes) {\n const nodeData = await node.load();\n newChildren.push({\n id: node.id,\n href: `../${node.id}`,\n obb: nodeData.obb,\n mbs: nodeData.mbs\n });\n }\n this.children = this.children.concat(childNodes);\n let data = this.data;\n if (this.converter.options.instantNodeWriting) {\n data = await this.load();\n }\n if (data) {\n data.children = data.children ?? [];\n data.children = data.children.concat(newChildren);\n }\n if (this.converter.options.instantNodeWriting && data) {\n await this.write(data);\n }\n }\n /**\n * Add neighbors to child nodes of this node\n */\n async addNeighbors() {\n if (this.finalized) {\n return;\n }\n const nodeData = await this.load();\n for (const childNode of this.children) {\n const childNodeData = await childNode.load();\n childNodeData.neighbors = childNodeData.neighbors ?? [];\n // Don't do large amount of \"neightbors\" to avoid big memory consumption\n if (Number(nodeData?.children?.length) < 1000) {\n for (const neighbor of nodeData.children || []) {\n if (childNode.id === neighbor.id) {\n continue; // eslint-disable-line\n }\n childNodeData.neighbors.push({ ...neighbor });\n }\n }\n else {\n // eslint-disable-next-line no-console, no-undef\n console.warn(`Node ${childNode.id}: neighbors attribute is omited because of large number of neigbors`);\n delete childNodeData.neighbors;\n }\n if (this.converter.options.instantNodeWriting && childNodeData) {\n await childNode.write(childNodeData);\n }\n await childNode.save();\n }\n // The save after adding neighbors is the last one. Finalize the the node\n this.finalize();\n }\n /** Save 3DNodeIndexDocument in file on disk */\n async save() {\n if (this.data) {\n await this.write(this.data);\n }\n }\n /** Finalize the node */\n finalize() {\n this._finalized = true;\n for (const child of this.children) {\n child.flush();\n }\n }\n /**\n * Write 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md\n * @param node - Node3DIndexDocument object\n */\n async write(node) {\n const path = join(this.converter.layers0Path, 'nodes', this.id);\n if (this.converter.options.slpk) {\n await this.converter.writeQueue.enqueue({\n archiveKey: `nodes/${this.id}/3dNodeIndexDocument.json.gz`,\n writePromise: () => writeFileForSlpk(path, JSON.stringify(node), '3dNodeIndexDocument.json', true, this.converter.compressList)\n }, true);\n }\n else {\n await this.converter.writeQueue.enqueue({ writePromise: () => writeFile(path, JSON.stringify(node)) }, true);\n }\n }\n /**\n * Load 3DNodeIndexDocument data from file on disk\n * @returns 3DNodeIndexDocument object\n */\n async load() {\n if (this.data) {\n return this.data;\n }\n const path = this.id;\n const parentNodePath = join(this.converter.layers0Path, 'nodes', path);\n let parentNodeFileName = 'index.json';\n if (this.converter.options.slpk) {\n parentNodeFileName = '3dNodeIndexDocument.json';\n }\n return (await openJson(parentNodePath, parentNodeFileName));\n }\n /**\n * Unload the Node data\n */\n flush() {\n this.data = null;\n }\n /**\n * Create root node of the tree\n * @param boundingVolumes - MBS and OOB bounding volumes data\n * @param converter - I3SConverter instance\n * @returns instance of NodeIndexDocument\n */\n static async createRootNode(boundingVolumes, converter) {\n const rootData = NodeIndexDocument.createRootNodeIndexDocument(boundingVolumes);\n const rootNode = await new NodeIndexDocument(0, converter).addData(rootData);\n return rootNode;\n }\n /**\n * Create NodeIndexDocument instance\n * @param parentNode - parent NodeIndexDocument\n * @param boundingVolumes - MBS and OOB bounding volumes data\n * @param lodSelection - LOD metrics data\n * @param nodeInPage - node data in node pages\n * @param resources - resources extracted from gltf/b3dm file\n * @param converter - I3SConverter instance\n * @returns NodeIndexDocument instance\n */\n static async createNode({ parentNode, boundingVolumes, lodSelection, nodeInPage, resources, converter }) {\n const data = await NodeIndexDocument.createNodeIndexDocument(parentNode, boundingVolumes, lodSelection, nodeInPage, resources);\n const node = await new NodeIndexDocument(nodeInPage.index, converter).addData(data);\n return node;\n }\n /**\n * Form 3DNodeIndexDocument data for the root node\n * @param boundingVolumes - mbs and obb data about node's bounding volume\n * @return 3DNodeIndexDocument data https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md\n */\n static createRootNodeIndexDocument(boundingVolumes) {\n const root0data = {\n version: `{${uuidv4().toUpperCase()}}`,\n id: 'root',\n level: 0,\n lodSelection: [\n {\n metricType: 'maxScreenThresholdSQ',\n maxError: 0\n },\n {\n metricType: 'maxScreenThreshold',\n maxError: 0\n }\n ],\n ...boundingVolumes,\n children: []\n };\n return transform(root0data, nodeTemplate());\n }\n /**\n * Create a new Node3DIndexDocument\n * @param parentNode - 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md object of the parent node\n * @param boundingVolumes - Bounding volumes\n * @param lodSelection - Level of Details (LOD) metrics\n * @param nodeInPage - corresponding node object in a node page\n * @param resources - the node resources data\n * @param resources.texture - texture image\n * @param resources.attributes - feature attributes\n * @return 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md object\n */\n // eslint-disable-next-line complexity\n static async createNodeIndexDocument(parentNode, boundingVolumes, lodSelection, nodeInPage, resources) {\n const nodeId = nodeInPage.index;\n const parentNodeData = await parentNode.load();\n const nodeData = {\n version: parentNodeData.version,\n id: nodeId.toString(),\n level: parentNodeData.level + 1,\n ...boundingVolumes,\n lodSelection,\n parentNode: {\n id: parentNode.id,\n href: `../${parentNode.id}`,\n mbs: parentNodeData.mbs,\n obb: parentNodeData.obb\n },\n children: [],\n neighbors: []\n };\n const node = transform(nodeData, nodeTemplate());\n if (nodeInPage.mesh) {\n node.geometryData = [{ href: './geometries/0' }];\n node.sharedResource = { href: './shared' };\n if (('texture' in resources && resources.texture) ||\n ('texelCountHint' in resources && resources.texelCountHint)) {\n node.textureData = [{ href: './textures/0' }, { href: './textures/1' }];\n }\n if (('attributes' in resources &&\n resources.attributes &&\n resources.attributes.length &&\n parentNode.converter.layers0?.attributeStorageInfo?.length) ||\n ('attributesCount' in resources &&\n resources.attributesCount &&\n parentNode.converter.layers0?.attributeStorageInfo?.length)) {\n const attributesLength = ('attributes' in resources ? resources.attributes?.length : resources.attributesCount) ||\n 0;\n node.attributeData = [];\n const minimumLength = attributesLength < parentNode.converter.layers0.attributeStorageInfo.length\n ? attributesLength\n : parentNode.converter.layers0.attributeStorageInfo.length;\n for (let index = 0; index < minimumLength; index++) {\n const folderName = parentNode.converter.layers0.attributeStorageInfo[index].key;\n node.attributeData.push({ href: `./attributes/${folderName}/0` });\n }\n }\n }\n return node;\n }\n}\n", "import transform from 'json-map-transform';\nconst COORDINATES = () => ({\n mbs: {\n path: 'mbs'\n },\n obb: {\n path: 'obb'\n }\n});\nconst HREF = () => ({\n href: {\n path: 'href'\n }\n});\nconst PARENT_NODE = () => ({\n id: {\n path: 'id'\n },\n ...HREF(),\n ...COORDINATES()\n});\nexport const NODE = () => ({\n version: {\n path: 'version'\n },\n id: {\n path: 'id'\n },\n path: {\n path: 'path'\n },\n level: {\n path: 'level'\n },\n ...COORDINATES(),\n lodSelection: {\n path: 'lodSelection',\n default: [\n {\n metricType: 'maxScreenThresholdSQ',\n maxError: 196349.54374999998\n },\n {\n metricType: 'maxScreenThreshold',\n maxError: 999.9999999999999\n }\n ]\n },\n children: {\n path: 'children',\n default: null\n },\n neighbors: {\n path: 'neighbors',\n default: null\n },\n parentNode: {\n path: 'parentNode',\n transform: (val) => transform(val, PARENT_NODE()),\n default: null\n },\n sharedResource: {\n path: 'sharedResource',\n default: null\n },\n featureData: {\n path: 'featureData',\n default: null\n },\n geometryData: {\n path: 'geometryData',\n default: null\n },\n textureData: {\n path: 'textureData',\n default: null\n },\n attributeData: {\n path: 'attributeData',\n default: null\n }\n});\n", "import { Tiles3DArchive } from '@loaders.gl/3d-tiles';\nimport { load } from '@loaders.gl/core';\nimport { FileHandleFile } from '@loaders.gl/loader-utils';\nimport { CD_HEADER_SIGNATURE, ZipFileSystem, parseHashTable, parseZipCDFileHeader, parseZipLocalFileHeader, searchFromTheEnd } from '@loaders.gl/zip';\n/**\n * Load nested 3DTiles tileset. If the sourceTile is not nested tileset - do nothing\n * @param sourceTileset - source root tileset JSON\n * @param sourceTile - source tile JSON that is supposed to has link to nested tileset\n * @param tilesetLoadOptions - load options for Tiles3DLoader\n * @returns nothing\n */\nexport const loadNestedTileset = async (sourceTileset, sourceTile, tilesetLoadOptions) => {\n const isTileset = isNestedTileset(sourceTile);\n if (!sourceTileset || !sourceTile.contentUrl || !isTileset) {\n return;\n }\n const loadOptions = {\n ...tilesetLoadOptions,\n [sourceTileset.loader.id]: {\n isTileset,\n assetGltfUpAxis: (sourceTileset.asset && sourceTileset.asset.gltfUpAxis) || 'Y'\n }\n };\n const tileContent = await loadFromArchive(sourceTile.contentUrl, sourceTileset.loader, loadOptions);\n if (tileContent.root) {\n sourceTile.children = [tileContent.root];\n }\n};\n/**\n * Load 3DTiles tile content, that includes glTF object\n * @param sourceTileset - source root tileset JSON\n * @param sourceTile - source tile JSON that has link to content data\n * @param tilesetLoadOptions - load options for Tiles3DLoader\n * @returns - 3DTiles tile content or null\n */\nexport const loadTile3DContent = async (sourceTileset, sourceTile, tilesetLoadOptions) => {\n const isTileset = isNestedTileset(sourceTile);\n if (!sourceTileset || !sourceTile.contentUrl || isTileset) {\n return null;\n }\n const loadOptions = {\n ...tilesetLoadOptions,\n [sourceTileset.loader.id]: {\n // @ts-ignore\n ...(tilesetLoadOptions[sourceTileset.loader.id] || {}),\n isTileset,\n assetGltfUpAxis: (sourceTileset.asset && sourceTileset.asset.gltfUpAxis) || 'Y'\n }\n };\n const tileContent = await loadFromArchive(sourceTile.contentUrl, sourceTileset.loader, loadOptions);\n return tileContent;\n};\n/**\n * Load a resource with load options and .3tz format support\n * @param url - resource URL\n * @param loader - loader to parse data (Tiles3DLoader / CesiumIonLoader)\n * @param loadOptions - 3d-tiles loader options\n * @returns 3d-tiles resource\n */\nexport async function loadFromArchive(url, loader, loadOptions) {\n const tz3UrlParts = url.split('.3tz');\n let filename;\n // No '.3tz'. The file will be loaded with global fetch function\n if (tz3UrlParts.length === 1) {\n filename = null;\n }\n else if (tz3UrlParts.length === 2) {\n filename = tz3UrlParts[1].slice(1);\n if (filename === '') {\n filename = 'tileset.json';\n }\n }\n else {\n throw new Error('Unexpected URL format');\n }\n if (filename) {\n const tz3Path = `${tz3UrlParts[0]}.3tz`;\n const fileProvider = new FileHandleFile(tz3Path);\n const hashTable = await loadHashTable(fileProvider);\n const archive = new Tiles3DArchive(fileProvider, hashTable, tz3Path);\n const fileSystem = new ZipFileSystem(archive);\n const content = await load(filename, loader, {\n ...loadOptions,\n fetch: fileSystem.fetch.bind(fileSystem)\n });\n await fileSystem.destroy();\n return content;\n }\n return await load(url, loader, loadOptions);\n}\n/**\n * Check if tile is nested tileset\n * @param tile - 3DTiles header data\n * @returns true if tile is nested tileset\n */\nexport function isNestedTileset(tile) {\n return tile?.type === 'json' || tile?.type === '3tz';\n}\n/**\n * Load hash file from 3TZ\n * @param fileProvider - binary reader of 3TZ\n * @returns hash table of the 3TZ file content or undefined if the hash file is not presented inside\n */\nasync function loadHashTable(fileProvider) {\n let hashTable;\n const hashCDOffset = await searchFromTheEnd(fileProvider, CD_HEADER_SIGNATURE);\n const cdFileHeader = await parseZipCDFileHeader(hashCDOffset, fileProvider);\n // '@3dtilesIndex1@' is index file that must be the last in the archive. It allows\n // to improve load and read performance when the archive contains a very large number\n // of files.\n if (cdFileHeader?.fileName === '@3dtilesIndex1@') {\n const localFileHeader = await parseZipLocalFileHeader(cdFileHeader.localHeaderOffset, fileProvider);\n if (!localFileHeader) {\n throw new Error('corrupted 3tz');\n }\n const fileDataOffset = localFileHeader.fileDataOffset;\n const hashFile = await fileProvider.slice(fileDataOffset, fileDataOffset + localFileHeader.compressedSize);\n hashTable = parseHashTable(hashFile);\n }\n return hashTable;\n}\n", "/**\n * Travesal of 3DTile tiles tree with making specific actions with each tile\n * @param tile - 3DTiles tile JSON metadata\n * @param traversalProps - traversal props used to pass data through recursive calls\n * @param processTile - callback to make some actions with the current tile\n * @param postprocessTile - callback to make some action after processing of the current tile and all the subtree\n * @param maxDepth - max recursive calls number the travesal function will do. If not set, the traversal function will\n * go through all the tree.\n * This value is used to limit the convertion with only partial number of levels of the tileset\n * @param level - counter to keep recursive calls number of the tiles tree. This value used to be able to break\n * traversal at the some level of the tree\n * @returns void\n */\nexport const traverseDatasetWith = async ({ tile, traversalProps, processTile, postprocessTile, maxDepth, level = 0 }) => {\n if (maxDepth && level > maxDepth) {\n return;\n }\n const processResults = [];\n const newTraversalProps = await processTile(tile, traversalProps);\n processResults.push(newTraversalProps);\n for (const childTile of tile.children) {\n await traverseDatasetWith({\n tile: childTile,\n traversalProps: newTraversalProps,\n processTile,\n postprocessTile,\n maxDepth,\n level: level + 1\n });\n }\n if (postprocessTile) {\n await postprocessTile(processResults, traversalProps);\n }\n};\n", "import { GLTFPrimitiveModeString } from \"../types.js\";\nimport { EXT_STRUCTURAL_METADATA, GLTFLoader } from '@loaders.gl/gltf';\nimport { parse } from '@loaders.gl/core';\nimport { EXT_FEATURE_METADATA } from '@loaders.gl/gltf';\n/**\n * glTF primitive modes\n * @see https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode\n */\nexport const GLTF_PRIMITIVE_MODES = [\n GLTFPrimitiveModeString.POINTS, // 0\n GLTFPrimitiveModeString.LINES, // 1\n GLTFPrimitiveModeString.LINE_LOOP, // 2\n GLTFPrimitiveModeString.LINE_STRIP, // 3\n GLTFPrimitiveModeString.TRIANGLES, // 4\n GLTFPrimitiveModeString.TRIANGLE_STRIP, // 5\n GLTFPrimitiveModeString.TRIANGLE_FAN // 6\n];\n/**\n * Analyze tile content. This function is used during preprocess stage of\n * conversion\n * @param tileContent - 3DTiles tile content ArrayBuffer\n * @returns\n */\nexport const analyzeTileContent = async (tileContent) => {\n const defaultResult = {\n meshTopologyTypes: new Set(),\n metadataClasses: new Set()\n };\n if (!tileContent?.gltfArrayBuffer) {\n return defaultResult;\n }\n const gltfData = await parse(tileContent.gltfArrayBuffer, GLTFLoader, {\n gltf: { normalize: false, loadBuffers: false, loadImages: false, decompressMeshes: false }\n });\n const gltf = gltfData.json;\n if (!gltf) {\n return defaultResult;\n }\n const meshTopologyTypes = getMeshTypesFromGLTF(gltf);\n const metadataClasses = getMetadataClassesFromGLTF(gltf);\n return {\n meshTopologyTypes,\n metadataClasses\n };\n};\n/**\n * Get mesh topology types that the glb content has\n * @param gltfJson - JSON part of GLB content\n * @returns array of mesh types found\n */\nconst getMeshTypesFromGLTF = (gltfJson) => {\n const result = new Set();\n for (const mesh of gltfJson.meshes || []) {\n for (const primitive of mesh.primitives) {\n let { mode } = primitive;\n if (typeof mode !== 'number') {\n mode = 4; // Default is 4 - TRIANGLES\n }\n result.add(GLTF_PRIMITIVE_MODES[mode]);\n }\n }\n return result;\n};\n/**\n * Get feature metadata classes from glTF\n * The tileset might contain multiple metadata classes provided by EXT_feature_metadata and EXT_structural_metadata extensions.\n * Every class is a set of properties. But I3S can consume only one set of properties.\n * On the pre-process we collect all classes from the tileset in order to show the prompt to select one class for conversion to I3S.\n * @param gltfJson - JSON part of GLB content\n * @returns array of classes\n */\nconst getMetadataClassesFromGLTF = (gltfJson) => {\n const result = new Set();\n // Try to parse from EXT_feature_metadata\n const extFeatureMetadataClasses = gltfJson.extensions?.[EXT_FEATURE_METADATA]?.schema?.classes;\n if (extFeatureMetadataClasses) {\n for (const classKey of Object.keys(extFeatureMetadataClasses)) {\n result.add(classKey);\n }\n }\n // Try to parse from EXT_structural_metadata\n const extStructuralMetadataClasses = gltfJson.extensions?.[EXT_STRUCTURAL_METADATA]?.schema?.classes;\n if (extStructuralMetadataClasses) {\n for (const classKey of Object.keys(extStructuralMetadataClasses)) {\n result.add(classKey);\n }\n }\n return result;\n};\n/**\n * Merge object2 into object1\n * @param object1\n * @param object2\n * @returns nothing\n */\nexport const mergePreprocessData = (object1, object2) => {\n // Merge topology mesh types info\n for (const type of object2.meshTopologyTypes) {\n object1.meshTopologyTypes.add(type);\n }\n // Merge feature metadata classes\n for (const metadataClass of object2.metadataClasses) {\n object1.metadataClasses.add(metadataClass);\n }\n};\n", "import process from 'process';\nimport { timeConverter } from \"../../lib/utils/statistic-utills.js\";\n/** Defines a threshold that is used to check if the process velocity can be consifered trust. */\nconst THRESHOLD_DEFAULT = 0.2;\n/**\n * Implements methods to keep track on the progress of a long process.\n */\nexport class Progress {\n /** Total amount of work, e.g. number of files to save or number of bytes to send */\n _stepsTotal = 0;\n /** Amount of work already done */\n _stepsDone = 0;\n /** Time in milli-seconds when the process started */\n startTime = 0;\n /** Time in milli-seconds when the process stopped */\n stopTime = 0;\n /** Time in milli-seconds when stepsDone was updated */\n timeOfUpdatingStepsDone = 0;\n /** Time in milli-seconds spent for performing one step*/\n milliSecForOneStep = 0;\n trust = false;\n /**\n * The number of digits to appear after decimal point in the string representation of the count of steps already done.\n * It's calculated based on the total count of steps.\n */\n numberOfDigitsInPercentage = 0;\n /** Defines a threshold that is used to check if the process velocity can be consifered trust. */\n threshold;\n /** Function that is used to get the time stamp */\n getTime;\n constructor(options = {}) {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.getTime = options.getTime || process.hrtime.bigint;\n this.threshold = options.threshold || THRESHOLD_DEFAULT;\n }\n /** Total amount of work, e.g. number of files to save or number of bytes to send */\n get stepsTotal() {\n return this._stepsTotal;\n }\n set stepsTotal(stepsTotal) {\n this._stepsTotal = stepsTotal;\n this.numberOfDigitsInPercentage =\n this.stepsTotal > 100 ? Math.ceil(Math.log10(this.stepsTotal)) - 2 : 0;\n }\n /** Amount of work already done */\n get stepsDone() {\n return this._stepsDone;\n }\n set stepsDone(stepsDone) {\n this._stepsDone = stepsDone;\n this.timeOfUpdatingStepsDone = this.getCurrentTimeInMilliSeconds();\n if (this._stepsDone) {\n const diff = this.timeOfUpdatingStepsDone - this.startTime;\n const milliSecForOneStep = diff / this._stepsDone;\n this.trust = this.isVelocityTrust(milliSecForOneStep, this.milliSecForOneStep);\n this.milliSecForOneStep = milliSecForOneStep;\n }\n }\n /**\n * Saves the current time as we start monitoring the process.\n */\n startMonitoring() {\n this.startTime = this.getCurrentTimeInMilliSeconds();\n this.milliSecForOneStep = 0;\n this.trust = false;\n this.timeOfUpdatingStepsDone = 0;\n this.stopTime = 0;\n this.stepsDone = 0;\n }\n /**\n * Saves the current time as we stop monitoring the process.\n */\n stopMonitoring() {\n this.stopTime = this.getCurrentTimeInMilliSeconds();\n }\n /**\n * Gets percentage of the work already done.\n * @returns percentage of the work already done.\n */\n getPercent() {\n if (!this._stepsTotal) {\n return null;\n }\n const percent = (this._stepsDone / this._stepsTotal) * 100.0;\n return percent;\n }\n /**\n * Gets string representation of percentage of the work already done.\n * @returns string representation of percentage or an empty string if the percetage value cannot be calculated.\n */\n getPercentString() {\n const percent = this.getPercent();\n return percent !== null ? percent.toFixed(this.numberOfDigitsInPercentage) : '';\n }\n /**\n * Gets the time elapsed since the monitoring started\n * @returns Number of milliseconds elapsed\n */\n getTimeCurrentlyElapsed() {\n const currentTime = this.stopTime ? this.stopTime : this.getCurrentTimeInMilliSeconds();\n const diff = currentTime - this.startTime;\n return diff;\n }\n /**\n * Gets the time remaining (expected at the moment of updating 'stepsDone') to complete the work.\n * @returns Number of milliseconds remaining\n */\n getTimeRemaining() {\n if (!this._stepsTotal || !this._stepsDone || !this.startTime) {\n return null;\n }\n const timeRemainingInMilliSeconds = (this._stepsTotal - this._stepsDone) * this.milliSecForOneStep;\n return { timeRemaining: timeRemainingInMilliSeconds, trust: this.trust };\n }\n /**\n * Gets the string representation of the time remaining (expected at the moment of updating 'stepsDone') to complete the work.\n * @returns string representation of the time remaining.\n * It's an empty string if the time cannot be pedicted or it's still being calculated.\n */\n getTimeRemainingString() {\n const timeRemainingObject = this.getTimeRemaining();\n return timeRemainingObject?.trust ? timeConverter(timeRemainingObject.timeRemaining) : '';\n }\n /**\n * Check if the computed velociy of the process can be considered trust.\n * At the beginning of the process the number of samples collected ('time necessary to perform one step' averaged) is too small,\n * which results in huge deviation of the cumputed velocity of the process.\n * It makes sense to perform the check before reporting the time remainig so the end user is not confused.\n * @param current - current value\n * @param previous - previous value\n * @returns true if the computed velociy can be considered trust, or false otherwise\n */\n isVelocityTrust(current, previous) {\n if (previous) {\n const dev = Math.abs((current - previous) / previous);\n return dev < this.threshold;\n }\n return false;\n }\n /**\n * Gets current time in milliseconds.\n * @returns current time in milliseconds.\n */\n getCurrentTimeInMilliSeconds() {\n // process.hrtime.bigint() returns the time in nanoseconds. We need the time in milliseconds.\n return Number(this.getTime() / BigInt(1e6));\n }\n}\n", "import { isDeepStrictEqual } from 'util';\nimport { DUMP_FILE_SUFFIX } from \"../../constants.js\";\nimport { isFileExists, openJson, removeFile, renameFile, writeFile } from \"./file-utils.js\";\nimport { join } from 'path';\nimport process from 'process';\nimport Ajv from 'ajv';\nimport { dumpJsonSchema } from \"../json-schemas/conversion-dump-json-schema.js\";\nexport class ConversionDump {\n /** Restored/resumed dump indicator */\n restored = false;\n /** Conversion options */\n options;\n /** Tiles conversion progress status map */\n tilesConverted;\n /** Textures formats definitions */\n textureSetDefinitions;\n /** Attributes Metadata */\n attributeMetadataInfo;\n /** Array of materials definitions */\n materialDefinitions;\n constructor() {\n this.tilesConverted = {};\n }\n /**\n * Create a dump with convertion options\n * @param currentOptions - converter options\n */\n async createDump(currentOptions) {\n const { tilesetName, slpk, egmFilePath, inputUrl, outputPath, draco = true, maxDepth, token, generateTextures, generateBoundingVolumes, mergeMaterials = true, metadataClass, analyze = false } = currentOptions;\n this.options = {\n tilesetName,\n slpk,\n egmFilePath,\n inputUrl,\n outputPath,\n draco,\n maxDepth,\n token,\n generateTextures,\n generateBoundingVolumes,\n mergeMaterials,\n metadataClass,\n analyze\n };\n const dumpFilename = join(this.options.outputPath, this.options.tilesetName, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`);\n if (await isFileExists(dumpFilename)) {\n try {\n const dump = await openJson(join(this.options.outputPath, this.options.tilesetName), `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`);\n const { options, tilesConverted, textureSetDefinitions, attributeMetadataInfo, materialDefinitions } = dump;\n const ajv = new Ajv();\n const dumpJsonValidate = ajv.compile(dumpJsonSchema);\n const isDumpValid = dumpJsonValidate(dump);\n if (isDumpValid && isDeepStrictEqual(options, JSON.parse(JSON.stringify(this.options)))) {\n this.tilesConverted = tilesConverted;\n this.textureSetDefinitions = textureSetDefinitions;\n this.attributeMetadataInfo = attributeMetadataInfo;\n this.materialDefinitions = materialDefinitions;\n this.restored = true;\n return;\n }\n }\n catch (error) {\n // prettier-ignore\n console.log('Can\\'t open dump file', error); // eslint-disable-line no-console\n }\n }\n await this.deleteDumpFile();\n }\n /**\n * Reset a dump\n */\n reset() {\n this.restored = false;\n this.tilesConverted = {};\n if (this.textureSetDefinitions) {\n delete this.textureSetDefinitions;\n }\n if (this.attributeMetadataInfo) {\n delete this.attributeMetadataInfo;\n }\n if (this.materialDefinitions) {\n delete this.materialDefinitions;\n }\n }\n /**\n * Update conversion status in the dump file\n */\n async updateDumpFile() {\n if (this.options?.outputPath && this.options.tilesetName) {\n try {\n const time = process.hrtime();\n await writeFile(join(this.options.outputPath, this.options.tilesetName), JSON.stringify({\n options: this.options,\n tilesConverted: this.tilesConverted,\n textureSetDefinitions: this.textureSetDefinitions,\n attributeMetadataInfo: this.attributeMetadataInfo,\n materialDefinitions: this.materialDefinitions\n }), `${this.options.tilesetName}${DUMP_FILE_SUFFIX}.${time[0]}.${time[1]}`);\n await renameFile(join(this.options.outputPath, this.options.tilesetName, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}.${time[0]}.${time[1]}`), join(this.options.outputPath, this.options.tilesetName, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`));\n }\n catch (error) {\n // prettier-ignore\n console.log('Can\\'t update dump file', error); // eslint-disable-line no-console\n }\n }\n }\n /**\n * Delete a dump file\n */\n async deleteDumpFile() {\n if (this.options?.outputPath &&\n this.options.tilesetName &&\n (await isFileExists(join(this.options.outputPath, this.options.tilesetName, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`)))) {\n await removeFile(join(this.options.outputPath, this.options.tilesetName, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`));\n }\n }\n /**\n * Get record from the tilesConverted Map\n * @param fileName - source filename\n * @returns existing object from the tilesConverted Map\n */\n getRecord(fileName) {\n return this.tilesConverted[fileName];\n }\n /**\n * Set a record for the dump file\n * @param fileName - key - source filename\n * @param object - value\n */\n setRecord(fileName, object) {\n this.tilesConverted[fileName] = object;\n }\n /**\n * Add a node into the dump file for the source file record\n * @param fileName - source filename\n * @param nodeId - nodeId of the node\n */\n async addNode(filename, nodeId, dumpMetadata) {\n const { nodes } = this.getRecord(filename) || { nodes: [] };\n nodes.push({ nodeId, done: false, dumpMetadata });\n if (nodes.length === 1) {\n this.setRecord(filename, { nodes });\n }\n await this.updateDumpFile();\n }\n /**\n * Clear dump record got the source filename\n * @param fileName - source filename\n */\n clearDumpRecord(filename) {\n this.setRecord(filename, { nodes: [] });\n }\n /**\n * Add textures definitions into the dump file\n * @param textureDefinitions - textures definitions array\n */\n addTexturesDefinitions(textureDefinitions) {\n this.textureSetDefinitions = textureDefinitions;\n }\n /**\n * Update done status object for the writing resources\n * @param fileName - key - source filename\n * @param nodeId - nodeId for the source filename\n * @param resourceType - resource type to update status\n * @param value - value\n */\n updateDoneStatus(filename, nodeId, resourceType, value) {\n const nodeDump = this.tilesConverted[filename]?.nodes.find((element) => element.nodeId === nodeId);\n if (nodeDump) {\n if (!nodeDump.progress) {\n nodeDump.progress = {};\n }\n nodeDump.progress[resourceType] = value;\n if (!value) {\n nodeDump.done = false;\n }\n }\n }\n /**\n * Update dump file according to writing results\n * @param changedRecords - array of parameters ids for the written resources\n * @param writeResults - array of writing resource files results\n */\n async updateConvertedTilesDump(changedRecords, writeResults) {\n for (let i = 0; i < changedRecords.length; i++) {\n if (changedRecords[i] && 'value' in writeResults[i]) {\n const { sourceId, resourceType, outputId } = changedRecords[i];\n this.updateNodes(sourceId, outputId, resourceType);\n }\n }\n await this.updateDumpFile();\n }\n /**\n * Update done status for a node\n * @param sourceId - source resource Id\n * @param outputId - output node/tile Id\n * @param resourceType - type of resource\n * @returns void\n */\n updateNodes(sourceId, outputId, resourceType) {\n if (!sourceId || !resourceType || !outputId) {\n return;\n }\n for (const node of this.tilesConverted[sourceId].nodes) {\n if (node.nodeId === outputId && node.progress) {\n node.progress[resourceType] = true;\n let done = false;\n for (const key in node.progress) {\n done = node.progress[key];\n if (!done)\n break;\n }\n node.done = done;\n if (node.done) {\n delete node.progress;\n }\n break;\n }\n }\n }\n /**\n * Update 3d-tiles-converter dump file\n * @param filename - source filename\n * @param nodeId - nodeId\n * @param done - conversion status\n */\n async updateConvertedNodesDumpFile(filename, nodeId, done) {\n const nodeDump = this.tilesConverted[filename]?.nodes.find((element) => element.nodeId === nodeId);\n if (nodeDump) {\n nodeDump.done = done;\n await this.updateDumpFile();\n }\n }\n /**\n * Check is source file conversion complete\n * @param filename - source filename\n * @returns true if source file conversion complete\n */\n isFileConversionComplete(filename) {\n let result = true;\n for (const node of this.tilesConverted[filename]?.nodes || []) {\n if (!node.done) {\n result = false;\n break;\n }\n }\n return result && this.tilesConverted[filename]?.nodes?.length > 0;\n }\n /**\n * Set materialDefinitions into a dump\n * @param materialDefinitions - Array materialDefinitions\n */\n setMaterialsDefinitions(materialDefinitions) {\n this.materialDefinitions = materialDefinitions;\n }\n}\n", "export const dumpJsonSchema = {\n type: 'object',\n properties: {\n options: {\n type: 'object',\n properties: {\n inputUrl: { type: 'string' },\n outputPath: { type: 'string' },\n tilesetName: { type: 'string' },\n maxDepth: { type: 'number' },\n slpk: { type: 'boolean' },\n egmFilePath: { type: 'string' },\n token: { type: 'string' },\n draco: { type: 'boolean' },\n mergeMaterials: { type: 'boolean' },\n generateTextures: { type: 'boolean' },\n generateBoundingVolumes: { type: 'boolean' },\n metadataClass: { type: 'string' },\n analyze: { type: 'boolean' }\n },\n required: ['inputUrl', 'outputPath', 'tilesetName']\n },\n tilesConverted: {\n type: 'object',\n patternProperties: {\n '.*': {\n type: 'object',\n properties: {\n nodes: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n nodeId: { type: ['number', 'string'] },\n done: { type: 'boolean' },\n progress: { type: 'object', patternProperties: { '.*': { type: 'boolean' } } },\n dumpMetadata: {\n type: 'object',\n properties: {\n boundingVolumes: {\n type: ['object', 'null'],\n properties: {\n mbs: {\n type: 'array',\n minItems: 4,\n maxItems: 4,\n items: { type: 'number' }\n },\n obb: {\n type: 'object',\n properties: {\n center: {\n type: 'array',\n minItems: 3,\n maxItems: 3,\n items: { type: 'number' }\n },\n halfSize: {\n type: 'array',\n minItems: 3,\n maxItems: 3,\n items: { type: 'number' }\n },\n quaternion: {\n type: 'array',\n minItems: 4,\n maxItems: 4,\n items: { type: 'number' }\n }\n },\n required: ['center', 'halfSize', 'quaternion']\n }\n },\n required: ['mbs', 'obb']\n },\n attributesCount: { type: 'number' },\n featureCount: { type: 'number' },\n geometry: { type: 'boolean' },\n hasUvRegions: { type: 'boolean' },\n materialId: { type: 'number' },\n texelCountHint: { type: 'number' },\n vertexCount: { type: 'number' }\n },\n required: [\n 'boundingVolumes',\n 'featureCount',\n 'geometry',\n 'hasUvRegions',\n 'materialId',\n 'vertexCount'\n ]\n }\n },\n required: ['nodeId', 'done']\n }\n }\n },\n required: ['nodes']\n }\n }\n },\n textureSetDefinitions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n formats: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n format: { enum: ['jpg', 'png', 'ktx-etc2', 'dds', 'ktx2'] }\n },\n required: ['name', 'format']\n }\n },\n atlas: { type: 'boolean' }\n },\n required: ['formats']\n }\n },\n attributeMetadataInfo: {\n type: 'object',\n properties: {\n attributeStorageInfo: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n key: { type: 'string' },\n name: { type: 'string' },\n header: {\n type: 'array',\n items: {\n type: 'object',\n properties: { property: { type: 'string' }, valueType: { type: 'string' } },\n required: ['property', 'valueType']\n }\n },\n ordering: { type: 'array', items: { type: 'string' } },\n attributeValues: { $ref: '#/$defs/AttributeValue' },\n attributeByteCounts: { $ref: '#/$defs/AttributeValue' },\n objectIds: { $ref: '#/$defs/AttributeValue' }\n },\n required: ['key', 'name', 'header']\n }\n },\n fields: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n type: { $ref: '#/$defs/ESRIField' },\n alias: { type: 'string' },\n domain: { $ref: '#/$defs/Domain' }\n },\n required: ['name', 'type']\n }\n },\n popupInfo: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n expressionInfos: { type: 'array', items: {} },\n fieldInfos: { type: 'array', items: { $ref: '#/$defs/FieldInfo' } },\n mediaInfos: { type: 'array', items: {} },\n popupElements: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n text: { type: 'string' },\n type: { type: 'string' },\n fieldInfos: { type: 'array', items: { $ref: '#/$defs/FieldInfo' } }\n }\n }\n }\n }\n }\n },\n required: ['attributeStorageInfo', 'fields']\n },\n materialDefinitions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n pbrMetallicRoughness: {\n type: 'object',\n properties: {\n baseColorFactor: {\n type: 'array',\n minItems: 4,\n maxItems: 4,\n items: { type: 'number' }\n },\n baseColorTexture: { $ref: '#/$defs/I3SMaterialTexture' },\n metallicFactor: { type: 'number' },\n roughnessFactor: { type: 'number' },\n metallicRoughnessTexture: { $ref: '#/$defs/I3SMaterialTexture' }\n },\n required: ['metallicFactor', 'roughnessFactor']\n },\n normalTexture: { $ref: '#/$defs/I3SMaterialTexture' },\n occlusionTexture: { $ref: '#/$defs/I3SMaterialTexture' },\n emissiveTexture: { $ref: '#/$defs/I3SMaterialTexture' },\n emissiveFactor: { type: 'array', minItems: 3, maxItems: 3, items: { type: 'number' } },\n alphaMode: { enum: ['opaque', 'mask', 'blend'] },\n alphaCutoff: { type: 'number' },\n doubleSided: { type: 'boolean' },\n cullFace: { enum: ['none', 'front', 'back'] }\n },\n required: ['pbrMetallicRoughness', 'alphaMode']\n }\n }\n },\n required: ['options', 'tilesConverted'],\n $defs: {\n AttributeValue: {\n type: 'object',\n properties: {\n valueType: { type: 'string' },\n encoding: { type: 'string' },\n valuesPerElement: { type: 'number' }\n },\n required: ['valueType']\n },\n ESRIField: {\n enum: [\n 'esriFieldTypeDate',\n 'esriFieldTypeSingle',\n 'esriFieldTypeDouble',\n 'esriFieldTypeGUID',\n 'esriFieldTypeGlobalID',\n 'esriFieldTypeInteger',\n 'esriFieldTypeOID',\n 'esriFieldTypeSmallInteger',\n 'esriFieldTypeString'\n ]\n },\n Domain: {\n type: 'object',\n properties: {\n type: { type: 'string' },\n name: { type: 'string' },\n description: { type: 'string' },\n fieldType: { type: 'string' },\n range: { type: 'array', items: { type: 'number' } },\n codedValues: {\n type: 'array',\n items: {\n type: 'object',\n properties: { name: { type: 'string' }, code: { type: ['string', 'number'] } },\n required: ['name', 'code']\n }\n },\n mergePolicy: { type: 'string' },\n splitPolicy: { type: 'string' }\n },\n required: ['type', 'name']\n },\n FieldInfo: {\n type: 'object',\n properties: {\n fieldName: { type: 'string' },\n visible: { type: 'boolean' },\n isEditable: { type: 'boolean' },\n label: { type: 'string' }\n },\n required: ['fieldName', 'visible', 'isEditable', 'label']\n },\n I3SMaterialTexture: {\n type: 'object',\n properties: {\n textureSetDefinitionId: { type: 'number' },\n texCoord: { type: 'number' },\n factor: { type: 'number' }\n },\n required: ['textureSetDefinitionId']\n }\n }\n};\n", "import { join } from 'path';\nimport process from 'process';\nimport transform from 'json-map-transform';\nimport { load, isBrowser } from '@loaders.gl/core';\nimport { I3SLoader, I3SAttributeLoader, COORDINATE_SYSTEM } from '@loaders.gl/i3s';\nimport { PGMLoader } from \"../pgm-loader.js\";\nimport { i3sObbTo3dTilesObb } from \"./helpers/i3s-obb-to-3d-tiles-obb.js\";\nimport { convertScreenThresholdToGeometricError } from \"../lib/utils/lod-conversion-utils.js\";\nimport { writeFile, removeDir } from \"../lib/utils/file-utils.js\";\nimport { calculateFilesSize, timeConverter } from \"../lib/utils/statistic-utills.js\";\nimport { TILESET as tilesetTemplate } from \"./json-templates/tileset.js\";\nimport { createObbFromMbs } from \"../i3s-converter/helpers/coordinate-converter.js\";\nimport { WorkerFarm } from '@loaders.gl/worker-utils';\nimport { BROWSER_ERROR_MESSAGE } from \"../constants.js\";\nimport B3dmConverter from \"./helpers/b3dm-converter.js\";\nimport { getNodeCount, loadFromArchive, loadI3SContent, openSLPK } from \"./helpers/load-i3s.js\";\nimport { ConversionDump } from \"../lib/utils/conversion-dump.js\";\nimport { Progress } from \"../i3s-converter/helpers/progress.js\";\nconst I3S = 'I3S';\n/**\n * Converter from i3s to 3d-tiles\n */\nexport default class Tiles3DConverter {\n options;\n tilesetPath;\n vertexCounter;\n conversionStartTime;\n geoidHeightModel;\n sourceTileset;\n attributeStorageInfo;\n workerSource = {};\n slpkFilesystem = null;\n loaderOptions = {\n _nodeWorkers: true,\n reuseWorkers: true,\n // TODO: converter freezes in the end because of i3s-content-worker\n worker: false,\n i3s: { coordinateSystem: COORDINATE_SYSTEM.LNGLAT_OFFSETS, decodeTextures: false },\n // We need to load local fs workers because nodejs can't load workers from the Internet\n 'i3s-content': {\n workerUrl: './modules/i3s/dist/i3s-content-worker-node.js'\n }\n };\n conversionDump;\n progress;\n constructor() {\n this.options = {};\n this.tilesetPath = '';\n this.vertexCounter = 0;\n this.conversionStartTime = [0, 0];\n this.geoidHeightModel = null;\n this.sourceTileset = null;\n this.attributeStorageInfo = null;\n this.workerSource = {};\n this.conversionDump = new ConversionDump();\n this.progress = new Progress();\n }\n /**\n * Convert i3s format data to 3dTiles\n * @param options\n * @param options.inputUrl the url to read the tileset from\n * @param options.outputPath the output filename\n * @param options.tilesetName the output name of the tileset\n * @param options.egmFilePath location of *.pgm file to convert heights from ellipsoidal to gravity-related format\n * @param options.maxDepth The max tree depth of conversion\n */\n // eslint-disable-next-line complexity, max-statements\n async convert(options) {\n if (isBrowser) {\n console.log(BROWSER_ERROR_MESSAGE); // eslint-disable-line no-console\n return BROWSER_ERROR_MESSAGE;\n }\n const { inputUrl, outputPath, tilesetName, maxDepth, egmFilePath, inquirer, analyze } = options;\n this.conversionStartTime = process.hrtime();\n this.options = { maxDepth, inquirer };\n console.log('Loading egm file...'); // eslint-disable-line\n this.geoidHeightModel = await load(egmFilePath, PGMLoader);\n console.log('Loading egm file completed!'); // eslint-disable-line\n this.slpkFilesystem = await openSLPK(inputUrl);\n let preprocessResult = true;\n if (analyze || this.slpkFilesystem) {\n preprocessResult = await this.preprocessConversion();\n if (!preprocessResult || analyze) {\n return undefined;\n }\n }\n this.progress.startMonitoring();\n this.sourceTileset = await loadFromArchive(inputUrl, I3SLoader, {\n ...this.loaderOptions,\n // @ts-expect-error `isTileset` can be boolean of 'auto' but TS expects a string\n i3s: { ...this.loaderOptions.i3s, isTileset: true }\n }, this.slpkFilesystem);\n if (!this.sourceTileset) {\n return undefined;\n }\n const rootNode = this.sourceTileset?.root;\n if (!rootNode.obb) {\n rootNode.obb = createObbFromMbs(rootNode.mbs);\n }\n this.tilesetPath = join(`${outputPath}`, `${tilesetName}`);\n this.attributeStorageInfo = this.sourceTileset.attributeStorageInfo;\n await this.conversionDump.createDump(options);\n if (this.conversionDump.restored && this.options.inquirer) {\n const result = await this.options.inquirer.prompt([\n {\n name: 'resumeConversion',\n type: 'confirm',\n message: 'Dump file of the previous conversion exists, do you want to resume that conversion?'\n }\n ]);\n if (!result.resumeConversion) {\n this.conversionDump.reset();\n }\n }\n // Removing the tilesetPath needed to exclude erroneous files after conversion\n if (!this.conversionDump.restored) {\n try {\n await removeDir(this.tilesetPath);\n }\n catch (e) {\n // do nothing\n }\n }\n const rootTile = {\n boundingVolume: {\n box: i3sObbTo3dTilesObb(rootNode.obb, this.geoidHeightModel)\n },\n geometricError: convertScreenThresholdToGeometricError(rootNode),\n children: [],\n refine: 'REPLACE'\n };\n await this._addChildren(rootNode, rootTile, 1);\n const tileset = transform({ root: rootTile }, tilesetTemplate());\n await writeFile(this.tilesetPath, JSON.stringify(tileset), 'tileset.json');\n await this.conversionDump.deleteDumpFile();\n this.progress.stopMonitoring();\n await this._finishConversion({ slpk: false, outputPath, tilesetName });\n if (this.slpkFilesystem) {\n this.slpkFilesystem.destroy();\n }\n // Clean up worker pools\n const workerFarm = WorkerFarm.getWorkerFarm({});\n workerFarm.destroy();\n return undefined;\n }\n /**\n * Preprocess stage of the tile converter. Calculate number of nodes\n * @returns true - the conversion is possible, false - the tileset's content is not supported\n */\n async preprocessConversion() {\n // eslint-disable-next-line no-console\n console.log('Analyze source layer');\n const nodesCount = await getNodeCount(this.slpkFilesystem);\n this.progress.stepsTotal = nodesCount;\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n // eslint-disable-next-line no-console\n console.log('Preprocess results:');\n if (this.slpkFilesystem) {\n // eslint-disable-next-line no-console\n console.log(`Node count: ${nodesCount}`);\n if (nodesCount === 0) {\n // eslint-disable-next-line no-console\n console.log('Node count is 0. The conversion will be interrupted.');\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n return false;\n }\n }\n else {\n // eslint-disable-next-line no-console\n console.log('Node count cannot be calculated for the remote dataset');\n }\n // eslint-disable-next-line no-console\n console.log('------------------------------------------------');\n return true;\n }\n /**\n * Convert particular I3S Node\n * @param parentSourceNode the parent node tile object (@loaders.gl/tiles/Tile3D)\n * @param parentNode object in resulting tileset\n * @param level a current level of a tree depth\n * @param childNodeInfo child node to convert\n */\n // eslint-disable-next-line complexity, max-statements\n async convertChildNode(parentSourceNode, parentNode, level, childNodeInfo) {\n let nextParentNode = parentNode;\n const sourceChild = await this._loadChildNode(parentSourceNode, childNodeInfo);\n if (sourceChild.contentUrl) {\n if (this.conversionDump.restored &&\n this.conversionDump.isFileConversionComplete(`${sourceChild.id}.b3dm`) &&\n (sourceChild.obb || sourceChild.mbs)) {\n const { child } = this._createChildAndBoundingVolume(sourceChild);\n parentNode.children.push(child);\n await this._addChildren(sourceChild, child, level + 1);\n return;\n }\n const content = await loadI3SContent(this.sourceTileset, sourceChild, this.loaderOptions, this.slpkFilesystem);\n if (!content) {\n await this._addChildren(sourceChild, parentNode, level + 1);\n return;\n }\n this.vertexCounter += content?.vertexCount || 0;\n let featureAttributes = null;\n if (this.attributeStorageInfo) {\n featureAttributes = await this._loadChildAttributes(sourceChild, this.attributeStorageInfo);\n }\n const { child, boundingVolume } = this._createChildAndBoundingVolume(sourceChild);\n const i3sAttributesData = {\n tileContent: content,\n box: boundingVolume.box || [],\n textureFormat: sourceChild.textureFormat\n };\n const b3dmConverter = new B3dmConverter();\n const b3dm = await b3dmConverter.convert(i3sAttributesData, featureAttributes);\n await this.conversionDump.addNode(`${sourceChild.id}.b3dm`, sourceChild.id);\n await writeFile(this.tilesetPath, new Uint8Array(b3dm), `${sourceChild.id}.b3dm`);\n await this.conversionDump.updateConvertedNodesDumpFile(`${sourceChild.id}.b3dm`, sourceChild.id, true);\n parentNode.children.push(child);\n nextParentNode = child;\n }\n this.progress.stepsDone += 1;\n let timeRemainingString = 'Calculating time left...';\n const timeRemaining = this.progress.getTimeRemainingString();\n if (timeRemaining) {\n timeRemainingString = `${timeRemaining} left`;\n }\n const percentString = this.progress.getPercentString();\n const progressString = percentString ? ` ${percentString}%, ${timeRemainingString}` : '';\n console.log(`[converted${progressString}]: ${childNodeInfo.id}`); // eslint-disable-line\n await this._addChildren(sourceChild, nextParentNode, level + 1);\n }\n /**\n * The recursive function of traversal of a nodes tree\n * @param parentSourceNode the parent node tile object (@loaders.gl/tiles/Tile3D)\n * @param parentNode object in resulting tileset\n * @param level a current level of a tree depth\n */\n async _addChildren(parentSourceNode, parentNode, level) {\n if (this.options.maxDepth && level > this.options.maxDepth) {\n return;\n }\n for (const childNodeInfo of parentSourceNode.children || []) {\n await this.convertChildNode(parentSourceNode, parentNode, level, childNodeInfo);\n }\n }\n /**\n * Load a child node having information from the node header\n * @param parentNode a parent node tile object (@loaders.gl/tiles/Tile3D)\n * @param childNodeInfo child information from 3DNodeIndexDocument\n * (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/nodeReference.cmn.md)\n */\n async _loadChildNode(parentNode, childNodeInfo) {\n let header;\n if (this.sourceTileset?.nodePagesTile) {\n console.log(`Node conversion: ${childNodeInfo.id}`); // eslint-disable-line no-console,no-undef\n header = await this.sourceTileset.nodePagesTile.formTileFromNodePages(parseInt(childNodeInfo.id));\n }\n else {\n const nodeUrl = this._relativeUrlToFullUrl(parentNode.url, childNodeInfo.href);\n // load metadata\n const options = {\n i3s: {\n ...this.loaderOptions,\n // @ts-expect-error\n isTileHeader: true,\n loadContent: false\n }\n };\n console.log(`Node conversion: ${nodeUrl}`); // eslint-disable-line no-console,no-undef\n header = await loadFromArchive(nodeUrl, I3SLoader, options, this.slpkFilesystem);\n }\n return header;\n }\n /**\n * Create child and child's boundingVolume for the converted node\n * @param sourceChild\n * @returns child and child's boundingVolume\n */\n _createChildAndBoundingVolume(sourceChild) {\n if (!sourceChild.obb) {\n sourceChild.obb = createObbFromMbs(sourceChild.mbs);\n }\n const boundingVolume = {\n box: i3sObbTo3dTilesObb(sourceChild.obb, this.geoidHeightModel)\n };\n const child = {\n boundingVolume,\n geometricError: convertScreenThresholdToGeometricError(sourceChild),\n children: [],\n content: {\n uri: `${sourceChild.id}.b3dm`,\n boundingVolume\n }\n };\n return { boundingVolume, child };\n }\n /**\n * Make an url of a resource from its relative url having the base url\n * @param baseUrl the base url. A resulting url will be related from this url\n * @param relativeUrl a realtive url of a resource\n */\n _relativeUrlToFullUrl(baseUrl = '', relativeUrl) {\n let resultArray = baseUrl.split('/');\n const relativeUrlArray = relativeUrl.split('/');\n for (const folder of relativeUrlArray) {\n switch (folder) {\n case '.':\n continue; // eslint-disable-line no-continue\n case '..':\n resultArray = resultArray.slice(0, -1);\n break;\n default:\n resultArray.push(folder);\n }\n }\n return resultArray.join('/');\n }\n /**\n * Do loading all attributes related to particular node.\n * @param sourceChild\n * @param attributeStorageInfo\n * @returns Promise of attributes object.\n */\n async _loadChildAttributes(sourceChild, attributeStorageInfo) {\n const promises = [];\n const { attributeUrls = [] } = sourceChild;\n for (let index = 0; index < attributeUrls.length; index++) {\n const inputUrl = attributeUrls[index];\n const attribute = attributeStorageInfo[index];\n const options = {\n attributeName: attribute.name,\n attributeType: this._getAttributeType(attribute)\n };\n promises.push(loadFromArchive(inputUrl, I3SAttributeLoader, options, this.slpkFilesystem));\n }\n const attributesList = await Promise.all(promises);\n this._replaceNestedArrays(attributesList);\n return Object.assign({}, ...attributesList);\n }\n /**\n * Returns attribute type for loading attributes\n * @param attribute\n * Workaround for I3S v1.6. There is no attribute.attributeValues.valueType field in attribute.\n * There is an 'Oid32' type if attribute has objectIds property.\n * Doc: https://github.com/Esri/i3s-spec/blob/master/docs/1.6/attributeStorageInfo.cmn.md\n */\n _getAttributeType(attribute) {\n if (attribute.attributeValues) {\n return attribute.attributeValues.valueType;\n }\n else if (attribute.objectIds) {\n return 'Oid32';\n }\n return '';\n }\n /**\n * Make simple arrays from attribute typed arrays.\n * @param attributesList\n */\n _replaceNestedArrays(attributesList) {\n for (let index = 0; index < attributesList.length; index++) {\n const attributeObject = attributesList[index];\n for (const key in attributeObject) {\n attributeObject[key] = Array.from(attributeObject[key]);\n }\n }\n }\n /**\n * Print statistics in the end of conversion\n * @param params - output files data\n */\n async _finishConversion(params) {\n const filesSize = await calculateFilesSize(params);\n const diff = process.hrtime(this.conversionStartTime);\n const conversionTime = timeConverter(diff);\n console.log(`------------------------------------------------`); // eslint-disable-line\n console.log(`Finish conversion of ${I3S}`); // eslint-disable-line\n console.log(`Total conversion time: ${conversionTime}`); // eslint-disable-line\n console.log(`Vertex count: `, this.vertexCounter); // eslint-disable-line\n console.log(`File(s) size: `, filesSize, ' bytes'); // eslint-disable-line\n console.log(`------------------------------------------------`); // eslint-disable-line\n }\n}\n", "import { Vector3 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\nimport { OrientedBoundingBox } from '@math.gl/culling';\n/**\n * Convert quaternion-based OBB to half-axes-based OBB\n * @param i3SObb quaternion based OBB\n * @param geoidHeightModel the Earth Gravity Model instance\n * @returns number[12] 3DTiles OBB https://github.com/CesiumGS/3d-tiles/tree/master/specification#box\n */\nexport function i3sObbTo3dTilesObb(i3SObb, geoidHeightModel) {\n const tiles3DCenter = [\n i3SObb.center[0],\n i3SObb.center[1],\n i3SObb.center[2] + geoidHeightModel.getHeight(i3SObb.center[1], i3SObb.center[0])\n ];\n const cartesianCenter = Ellipsoid.WGS84.cartographicToCartesian(tiles3DCenter, new Vector3());\n const tiles3DObb = new OrientedBoundingBox().fromCenterHalfSizeQuaternion(cartesianCenter, i3SObb.halfSize, i3SObb.quaternion);\n return [...tiles3DObb.center, ...tiles3DObb.halfAxes.toArray()];\n}\n", "import transform from 'json-map-transform';\nconst ASSET = () => ({\n version: {\n path: 'version',\n default: '1.0'\n }\n});\nconst TILE = () => ({\n boundingVolume: {\n path: 'boundingVolume'\n },\n geometricError: {\n path: 'geometricError'\n },\n refine: {\n path: 'refine'\n },\n content: {\n path: 'content'\n },\n children: {\n path: 'children',\n transform: (val) => val.map((tile) => transform(tile, TILE()))\n }\n});\nexport const TILESET = () => ({\n asset: {\n path: 'asset',\n transform: (val) => transform(val, ASSET())\n },\n geometricError: {\n path: 'root',\n transform: (val) => val.geometricError\n },\n root: {\n path: 'root',\n transform: (val) => transform(val, TILE())\n }\n});\n", "import { encodeSync } from '@loaders.gl/core';\nimport { GLTFScenegraph, GLTFWriter } from '@loaders.gl/gltf';\nimport { Tile3DWriter } from '@loaders.gl/3d-tiles';\nimport { Matrix4, Vector3 } from '@math.gl/core';\nimport { Ellipsoid } from '@math.gl/geospatial';\nimport { convertTextureAtlas } from \"./texture-atlas.js\";\nimport { generateSyntheticIndices } from \"../../lib/utils/geometry-utils.js\";\nconst Z_UP_TO_Y_UP_MATRIX = new Matrix4([1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1]);\nconst scratchVector = new Vector3();\nconst KHR_MATERIALS_UNLIT = 'KHR_materials_unlit';\nconst METALLIC_FACTOR_DEFAULT = 1.0;\nconst ROUGHNESS_FACTOR_DEFAULT = 1.0;\n/**\n * Converts content of an I3S node to *.b3dm's file content\n */\nexport default class B3dmConverter {\n // @ts-expect-error\n rtcCenter;\n i3sTile;\n /**\n * The starter of content conversion\n * @param i3sTile - Tile3D instance for I3S node\n * @returns - encoded content\n */\n async convert(i3sAttributesData, featureAttributes = null) {\n const gltf = await this.buildGLTF(i3sAttributesData, featureAttributes);\n const b3dm = encodeSync({\n gltfEncoded: new Uint8Array(gltf),\n type: 'b3dm',\n featuresLength: this._getFeaturesLength(featureAttributes),\n batchTable: featureAttributes\n }, Tile3DWriter);\n return b3dm;\n }\n /**\n * Build and encode gltf\n * @param i3sTile - Tile3D instance for I3S node\n * @returns - encoded glb content\n */\n // eslint-disable-next-line max-statements\n async buildGLTF(i3sAttributesData, featureAttributes) {\n const { tileContent, textureFormat, box } = i3sAttributesData;\n const { material, attributes, indices: originalIndices, modelMatrix } = tileContent;\n const gltfBuilder = new GLTFScenegraph();\n const textureIndex = await this._addI3sTextureToGLTF(tileContent, textureFormat, gltfBuilder);\n // Add KHR_MATERIALS_UNLIT extension in the following cases:\n // - metallicFactor or roughnessFactor are set to default values\n // - metallicFactor or roughnessFactor are not set\n const pbrMetallicRoughness = material?.pbrMetallicRoughness;\n if (pbrMetallicRoughness &&\n (pbrMetallicRoughness.metallicFactor === undefined ||\n pbrMetallicRoughness.metallicFactor === METALLIC_FACTOR_DEFAULT) &&\n (pbrMetallicRoughness.roughnessFactor === undefined ||\n pbrMetallicRoughness.roughnessFactor === ROUGHNESS_FACTOR_DEFAULT)) {\n gltfBuilder.addObjectExtension(material, KHR_MATERIALS_UNLIT, {});\n gltfBuilder.addExtension(KHR_MATERIALS_UNLIT);\n }\n const pbrMaterialInfo = this._convertI3sMaterialToGLTFMaterial(material, textureIndex);\n const materialIndex = gltfBuilder.addMaterial(pbrMaterialInfo);\n const positions = attributes.positions;\n const positionsValue = positions.value;\n if (attributes.uvRegions && attributes.texCoords) {\n attributes.texCoords.value = convertTextureAtlas(attributes.texCoords.value, attributes.uvRegions.value);\n }\n const cartesianOrigin = new Vector3(box);\n const cartographicOrigin = Ellipsoid.WGS84.cartesianToCartographic(cartesianOrigin, new Vector3());\n attributes.positions.value = this._normalizePositions(positionsValue, cartesianOrigin, cartographicOrigin, modelMatrix);\n this._createBatchIds(tileContent, featureAttributes);\n if (attributes.normals && !this._checkNormals(attributes.normals.value)) {\n delete attributes.normals;\n }\n const indices = originalIndices || generateSyntheticIndices(positionsValue.length / positions.size);\n const meshIndex = gltfBuilder.addMesh({\n attributes,\n indices,\n material: materialIndex,\n mode: 4\n });\n const transformMatrix = this._generateTransformMatrix(cartesianOrigin);\n const nodeIndex = gltfBuilder.addNode({ meshIndex, matrix: transformMatrix });\n const sceneIndex = gltfBuilder.addScene({ nodeIndices: [nodeIndex] });\n gltfBuilder.setDefaultScene(sceneIndex);\n gltfBuilder.createBinaryChunk();\n const gltfBuffer = encodeSync(gltfBuilder.gltf, GLTFWriter);\n return gltfBuffer;\n }\n /**\n * Update gltfBuilder with texture from I3S tile\n * @param {object} i3sTile - Tile3D object\n * @param {GLTFScenegraph} gltfBuilder - gltfScenegraph instance to construct GLTF\n * @returns {Promise<number | null>} - GLTF texture index\n */\n async _addI3sTextureToGLTF(tileContent, textureFormat, gltfBuilder) {\n const { texture, material, attributes } = tileContent;\n let textureIndex = null;\n let selectedTexture = texture;\n if (!texture && material) {\n selectedTexture =\n material.pbrMetallicRoughness &&\n material.pbrMetallicRoughness.baseColorTexture &&\n material.pbrMetallicRoughness.baseColorTexture.texture.source.image;\n }\n if (selectedTexture) {\n const mimeType = this._deduceMimeTypeFromFormat(textureFormat);\n const imageIndex = gltfBuilder.addImage(selectedTexture, mimeType);\n textureIndex = gltfBuilder.addTexture({ imageIndex });\n delete attributes.colors;\n }\n return textureIndex;\n }\n /**\n * Generate a positions array which is correct for 3DTiles/GLTF format\n * @param {Float64Array} positionsValue - the input geometry positions array\n * @param {number[]} cartesianOrigin - the tile center in the cartesian coordinate system\n * @param {number[]} cartographicOrigin - the tile center in the cartographic coordinate system\n * @param {number[]} modelMatrix - the model matrix of geometry\n * @returns {Float32Array} - the output geometry positions array\n */\n _normalizePositions(positionsValue, cartesianOrigin, cartographicOrigin, modelMatrix) {\n const newPositionsValue = new Float32Array(positionsValue.length);\n for (let index = 0; index < positionsValue.length; index += 3) {\n const vertex = positionsValue.subarray(index, index + 3);\n const cartesianOriginVector = new Vector3(cartesianOrigin);\n let vertexVector = new Vector3(Array.from(vertex))\n .transform(modelMatrix)\n .add(cartographicOrigin);\n Ellipsoid.WGS84.cartographicToCartesian(vertexVector, scratchVector);\n vertexVector = scratchVector.subtract(cartesianOriginVector);\n newPositionsValue.set(vertexVector, index);\n }\n return newPositionsValue;\n }\n /**\n * Generate the transformation matrix for GLTF node:\n * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-node\n * 1. Create the translate transformation from cartesianOrigin (the positions array stores offsets from this cartesianOrigin)\n * 2. Create the rotation transformation to rotate model from z-up coordinates (I3S specific) to y-up coordinates (GLTF specific)\n * @param {number[]} cartesianOrigin - the tile center in the cartesian coordinate system\n * @returns {Matrix4} - an array of 16 numbers (4x4 matrix)\n */\n _generateTransformMatrix(cartesianOrigin) {\n const translateOriginMatrix = new Matrix4().translate(cartesianOrigin);\n const result = translateOriginMatrix.multiplyLeft(Z_UP_TO_Y_UP_MATRIX);\n return result;\n }\n /**\n * Create _BATCHID attribute\n * @param {Object} i3sContent - the source object\n * @returns {void}\n */\n _createBatchIds(i3sContent, featureAttributes) {\n const { featureIds } = i3sContent;\n const { OBJECTID: objectIds } = featureAttributes || {};\n if (!featureIds || !objectIds) {\n return;\n }\n for (let i = 0; i < featureIds.length; i++) {\n const featureId = featureIds[i];\n const batchId = objectIds.indexOf(featureId);\n featureIds[i] = batchId;\n }\n i3sContent.attributes._BATCHID = {\n size: 1,\n byteOffset: 0,\n value: featureIds\n };\n }\n /**\n * Deduce mime type by format from `textureSetDefinition.formats[0].format`\n * https://github.com/Esri/i3s-spec/blob/master/docs/1.7/textureSetDefinitionFormat.cmn.md\n * @param {string} format - format name\n * @returns {string} mime type.\n */\n _deduceMimeTypeFromFormat(format) {\n switch (format) {\n case 'jpg':\n return 'image/jpeg';\n case 'png':\n return 'image/png';\n case 'ktx2':\n return 'image/ktx2';\n default:\n console.warn(`Unexpected texture format in I3S: ${format}`); // eslint-disable-line no-console, no-undef\n return 'image/jpeg';\n }\n }\n /**\n * Convert i3s material to GLTF compatible material\n * @param {object} material - i3s material definition\n * @param {number | null} textureIndex - texture index in GLTF\n * @returns {object} GLTF material\n */\n _convertI3sMaterialToGLTFMaterial(material, textureIndex) {\n const isTextureIndexExists = textureIndex !== null;\n if (!material) {\n material = {\n alphaMode: 'OPAQUE',\n doubleSided: false,\n pbrMetallicRoughness: {\n metallicFactor: 0,\n roughnessFactor: 1\n }\n };\n if (isTextureIndexExists) {\n material.pbrMetallicRoughness.baseColorTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n else {\n material.pbrMetallicRoughness.baseColorFactor = [1, 1, 1, 1];\n }\n return material;\n }\n if (textureIndex !== null) {\n material = this._setGLTFTexture(material, textureIndex);\n }\n return material;\n }\n /**\n * Set texture properties in material with GLTF textureIndex\n * @param {object} materialDefinition - i3s material definition\n * @param {number} textureIndex - texture index in GLTF\n * @returns {void}\n */\n _setGLTFTexture(materialDefinition, textureIndex) {\n const material = {\n ...materialDefinition,\n pbrMetallicRoughness: { ...materialDefinition.pbrMetallicRoughness }\n };\n // I3SLoader now support loading only one texture. This elseif sequence will assign this texture to one of\n // properties defined in materialDefinition\n if (materialDefinition.pbrMetallicRoughness &&\n materialDefinition.pbrMetallicRoughness.baseColorTexture) {\n material.pbrMetallicRoughness.baseColorTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n else if (materialDefinition.emissiveTexture) {\n material.emissiveTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n else if (materialDefinition.pbrMetallicRoughness &&\n materialDefinition.pbrMetallicRoughness.metallicRoughnessTexture) {\n material.pbrMetallicRoughness.metallicRoughnessTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n else if (materialDefinition.normalTexture) {\n material.normalTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n else if (materialDefinition.occlusionTexture) {\n material.occlusionTexture = {\n index: textureIndex,\n texCoord: 0\n };\n }\n return material;\n }\n /*\n * Returns Features length based on attribute array in attribute object.\n * @param {Object} attributes\n * @returns {Number} Features length .\n */\n _getFeaturesLength(attributes) {\n if (!attributes) {\n return 0;\n }\n const firstKey = Object.keys(attributes)[0];\n return firstKey ? attributes[firstKey].length : 0;\n }\n /* Checks that normals buffer is correct\n * @param {TypedArray} normals\n * @returns {boolean} true - normals are correct; false - normals are incorrect\n */\n _checkNormals(normals) {\n // If all normals === 0, the resulting tileset is all in black colors on Cesium\n return normals.find((value) => value);\n }\n}\n", "/**\n * Apply uvRegions to texture coordinates.\n * Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/geometryUVRegion.cmn.md\n * Shader formula vec2 uv = fract(texCoords) * (uvRegions.zw - uvRegions.xy) + uvRegions.xy;\n * @param texCoords\n * @param uvRegions\n */\nexport function convertTextureAtlas(texCoords, uvRegions) {\n const convertedTexCoords = new Float32Array(texCoords.length);\n const normalisedRegions = normalizeRegions(uvRegions);\n for (let index = 0; index < texCoords.length; index += 2) {\n const uv = texCoords.subarray(index, index + 2);\n const regions = normalisedRegions.slice(index * 2, index * 2 + 4);\n // fract(texCoords)\n const fractatedUV = fract([uv[0], uv[1]]);\n // (uvRegions.zw - uvRegions.xy)\n const subtracted = [regions[2] - regions[0], regions[3] - regions[1]];\n // fract(texCoords) * (uvRegions.zw - uvRegions.xy)\n const multiplicationResult = [fractatedUV[0] * subtracted[0], fractatedUV[1] * subtracted[1]];\n // fract(texCoords) * (uvRegions.zw - uvRegions.xy) + uvRegions.xy;\n const convertedUV = [\n multiplicationResult[0] + regions[0],\n multiplicationResult[1] + regions[1]\n ];\n convertedTexCoords[index] = convertedUV[0];\n convertedTexCoords[index + 1] = convertedUV[1];\n }\n return convertedTexCoords;\n}\n/**\n * Do fractation of UV array.\n * @param uv\n */\nfunction fract(uv) {\n return [uv[0] - Math.floor(uv[0]), uv[1] - Math.floor(uv[1])];\n}\n/**\n * Normalize uvRegions by dividing by the maximum Uint16 value\n * @param regions\n */\nfunction normalizeRegions(regions) {\n // The code is for Uint16Array because it is the spec requirement\n // https://github.com/Esri/i3s-spec/blob/master/docs/1.8/geometryUVRegion.cmn.md\n const MAX_UINT_16_VALUE = 65535;\n const normalizedRegions = [];\n for (let index = 0; index < regions.length; index++) {\n normalizedRegions[index] = regions[index] / MAX_UINT_16_VALUE;\n }\n return normalizedRegions;\n}\n", "import { load } from '@loaders.gl/core';\nimport { I3SLoader, parseSLPKArchive } from '@loaders.gl/i3s';\nimport { FileHandleFile } from '@loaders.gl/loader-utils';\nimport { ZipFileSystem, makeZipCDHeaderIterator } from '@loaders.gl/zip';\n/**\n * Load I3S node content\n * @param sourceTileset - source layer JSON\n * @param sourceTile - source I3S node metadata\n * @param tilesetLoadOptions - load options for Tiles3DLoader\n * @param slpkFilesystem - loaded instance of ZipFileSystem for local convertion from SLPK file\n * @returns - 3DTiles tile content or null\n */\nexport const loadI3SContent = async (sourceTileset, sourceTile, tilesetLoadOptions, slpkFilesystem) => {\n if (!sourceTileset || !sourceTile.contentUrl) {\n return null;\n }\n const loadOptions = {\n ...tilesetLoadOptions,\n i3s: {\n ...tilesetLoadOptions.i3s,\n // @ts-expect-error\n isTileset: false,\n // @ts-expect-error\n isTileHeader: false,\n _tileOptions: {\n attributeUrls: sourceTile.attributeUrls || [],\n textureUrl: sourceTile.textureUrl,\n textureFormat: sourceTile.textureFormat,\n textureLoaderOptions: sourceTile.textureLoaderOptions,\n materialDefinition: sourceTile.materialDefinition,\n isDracoGeometry: sourceTile.isDracoGeometry,\n mbs: sourceTile.mbs\n },\n _tilesetOptions: {\n store: sourceTileset.store,\n // @ts-expect-error\n attributeStorageInfo: sourceTileset.attributeStorageInfo,\n // @ts-expect-error\n fields: sourceTileset.fields\n }\n }\n };\n const tileContent = await loadFromArchive(sourceTile.contentUrl, I3SLoader, loadOptions, slpkFilesystem);\n return tileContent;\n};\n/**\n * Load local SLPK file to ZipFileSystem instance\n * @param url - path to SLPK file\n * @returns instance of ZipFileSystem or null if url is not an SLPK file\n */\nexport async function openSLPK(url) {\n const slpkUrlParts = url.split('.slpk');\n if (slpkUrlParts.length === 2) {\n const slpkFileName = `${slpkUrlParts[0]}.slpk`;\n const fileProvider = new FileHandleFile(slpkFileName);\n const archive = await parseSLPKArchive(fileProvider, undefined, slpkFileName);\n const fileSystem = new ZipFileSystem(archive);\n return fileSystem;\n }\n return null;\n}\n/**\n * Load a resource with load options and .3tz format support\n * @param url - resource URL\n * @param loader - loader to parse data (Tiles3DLoader / CesiumIonLoader)\n * @param loadOptions - i3s loader options\n * @returns i3s resource\n */\nexport async function loadFromArchive(url, loader, loadOptions, fileSystem) {\n if (fileSystem !== null) {\n const content = await load(url, loader, {\n ...loadOptions,\n fetch: fileSystem.fetch.bind(fileSystem)\n });\n return content;\n }\n return await load(url, loader, loadOptions);\n}\n/**\n * Get nodes count inside SLPK\n * @param fileSystem - file system of SLPK\n * @returns number of nodes\n */\nexport async function getNodeCount(fileSystem) {\n if (!fileSystem?.fileProvider) {\n return 0;\n }\n let count = 0;\n const filesIterator = makeZipCDHeaderIterator(fileSystem.fileProvider);\n for await (const file of filesIterator) {\n const filename = file.fileName;\n if (filename.indexOf('3dNodeIndexDocument.json.gz') >= 0) {\n count++;\n }\n }\n return count;\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["GLTFPrimitiveModeString", "ResourceType", "import_core", "import_d_tiles", "import_path", "import_uuid", "import_process", "import_json_map_transform", "import_md5", "import_path", "import_fs", "fs", "_a", "transform", "import_path", "import_fs", "timeInSeconds", "milliseconds", "fs", "import_core", "import_geospatial", "import_loader_utils", "import_loader_utils", "positions", "normals", "colors", "texCoords", "uvRegions", "import_core", "import_core", "import_geospatial", "_a", "_b", "_a", "import_gltf", "_a", "import_math", "import_gltf", "VALUES_PER_VERTEX", "_a", "uuidv4", "md5", "getAttributeType", "import_uuid", "import_json_map_transform", "import_path", "uuidv4", "transform", "_a", "import_json_map_transform", "transform", "import_json_map_transform", "transform", "import_json_map_transform", "transform", "import_culling", "import_core", "import_geospatial", "_a", "process", "import_path", "import_json_map_transform", "import_uuid", "import_json_map_transform", "transform", "_a", "uuidv4", "transform", "import_core", "import_loader_utils", "import_core", "import_gltf", "import_core", "_a", "import_process", "process", "import_zip", "import_path", "import_process", "mergeMaterials", "Ajv", "_a", "process", "process", "mergeMaterials", "_a", "md5", "transform", "uuidv4", "import_path", "import_process", "import_json_map_transform", "import_core", "import_i3s", "import_core", "import_geospatial", "import_culling", "import_json_map_transform", "transform", "import_worker_utils", "import_core", "import_gltf", "import_d_tiles", "import_geospatial", "scratchVector", "import_core", "import_loader_utils", "import_zip", "loadFromArchive", "_a", "process", "loadFromArchive", "transform", "child"]
|
|
7
7
|
}
|