@loaders.gl/tile-converter 4.2.0-alpha.4 → 4.2.0-alpha.6
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/3d-tiles-converter/3d-tiles-converter.d.ts +4 -4
- package/dist/3d-tiles-converter/3d-tiles-converter.d.ts.map +1 -1
- package/dist/3d-tiles-converter/3d-tiles-converter.js +349 -293
- package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts.map +1 -1
- package/dist/3d-tiles-converter/helpers/b3dm-converter.js +261 -200
- package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +14 -5
- package/dist/3d-tiles-converter/helpers/load-i3s.d.ts.map +1 -1
- package/dist/3d-tiles-converter/helpers/load-i3s.js +83 -77
- package/dist/3d-tiles-converter/helpers/texture-atlas.js +44 -21
- package/dist/3d-tiles-converter/json-templates/tileset.js +32 -33
- package/dist/constants.js +0 -1
- package/dist/converter-cli.js +257 -234
- package/dist/converter.min.cjs +95 -105
- package/dist/deps-installer/deps-installer.d.ts.map +1 -1
- package/dist/deps-installer/deps-installer.js +78 -59
- package/dist/i3s-converter/helpers/attribute-metadata-info.js +210 -153
- package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts +1 -1
- package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/batch-ids-extensions.js +146 -103
- package/dist/i3s-converter/helpers/coordinate-converter.js +100 -65
- package/dist/i3s-converter/helpers/create-scene-server-path.js +14 -9
- package/dist/i3s-converter/helpers/feature-attributes.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/feature-attributes.js +170 -105
- package/dist/i3s-converter/helpers/geometry-attributes.d.ts +1 -1
- package/dist/i3s-converter/helpers/geometry-attributes.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/geometry-attributes.js +205 -212
- package/dist/i3s-converter/helpers/geometry-converter.d.ts +17 -3
- package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/geometry-converter.js +1189 -830
- package/dist/i3s-converter/helpers/gltf-attributes.d.ts +1 -1
- package/dist/i3s-converter/helpers/gltf-attributes.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/gltf-attributes.js +109 -97
- package/dist/i3s-converter/helpers/load-3d-tiles.js +103 -66
- package/dist/i3s-converter/helpers/node-debug.js +98 -54
- package/dist/i3s-converter/helpers/node-index-document.d.ts +11 -4
- package/dist/i3s-converter/helpers/node-index-document.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/node-index-document.js +255 -177
- package/dist/i3s-converter/helpers/node-pages.d.ts +1 -1
- package/dist/i3s-converter/helpers/node-pages.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/node-pages.js +299 -193
- package/dist/i3s-converter/helpers/preprocess-3d-tiles.d.ts +1 -1
- package/dist/i3s-converter/helpers/preprocess-3d-tiles.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/preprocess-3d-tiles.js +92 -60
- package/dist/i3s-converter/helpers/progress.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/progress.js +139 -83
- package/dist/i3s-converter/helpers/tileset-traversal.d.ts +9 -2
- package/dist/i3s-converter/helpers/tileset-traversal.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/tileset-traversal.js +33 -13
- package/dist/i3s-converter/i3s-converter.d.ts +7 -7
- package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
- package/dist/i3s-converter/i3s-converter.js +1165 -895
- package/dist/i3s-converter/json-templates/geometry-definitions.js +70 -79
- package/dist/i3s-converter/json-templates/layers.js +120 -121
- package/dist/i3s-converter/json-templates/metadata.js +19 -20
- package/dist/i3s-converter/json-templates/node.js +73 -71
- package/dist/i3s-converter/json-templates/scene-server.js +25 -26
- package/dist/i3s-converter/json-templates/shared-resources.js +107 -108
- package/dist/i3s-converter/json-templates/store.js +96 -94
- package/dist/i3s-converter/types.js +35 -23
- package/dist/i3s-server/app.js +15 -12
- package/dist/i3s-server/bin/i3s-server.min.cjs +69 -69
- package/dist/i3s-server/bin/www.js +16 -7
- package/dist/i3s-server/controllers/index-controller.js +18 -15
- package/dist/i3s-server/controllers/slpk-controller.d.ts.map +1 -1
- package/dist/i3s-server/controllers/slpk-controller.js +24 -11
- package/dist/i3s-server/routes/index.js +13 -9
- package/dist/i3s-server/routes/slpk-router.d.ts.map +1 -1
- package/dist/i3s-server/routes/slpk-router.js +26 -19
- package/dist/i3s-server/utils/create-scene-server.js +15 -10
- package/dist/i3s-server/utils/server-utils.d.ts.map +1 -1
- package/dist/i3s-server/utils/server-utils.js +52 -32
- package/dist/index.cjs +616 -967
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/lib/json-schemas/conversion-dump-json-schema.js +243 -421
- package/dist/lib/utils/cli-utils.d.ts.map +1 -1
- package/dist/lib/utils/cli-utils.js +65 -36
- package/dist/lib/utils/compress-util.js +20 -15
- package/dist/lib/utils/conversion-dump.d.ts +10 -2
- package/dist/lib/utils/conversion-dump.d.ts.map +1 -1
- package/dist/lib/utils/conversion-dump.js +242 -197
- package/dist/lib/utils/file-utils.d.ts +1 -1
- package/dist/lib/utils/file-utils.d.ts.map +1 -1
- package/dist/lib/utils/file-utils.js +120 -74
- package/dist/lib/utils/geometry-utils.js +13 -7
- package/dist/lib/utils/lod-conversion-utils.js +65 -33
- package/dist/lib/utils/queue.js +12 -13
- package/dist/lib/utils/statistic-utills.d.ts +6 -23
- package/dist/lib/utils/statistic-utills.d.ts.map +1 -1
- package/dist/lib/utils/statistic-utills.js +58 -55
- package/dist/lib/utils/write-queue.d.ts +2 -2
- package/dist/lib/utils/write-queue.d.ts.map +1 -1
- package/dist/lib/utils/write-queue.js +72 -86
- package/dist/pgm-loader.js +17 -13
- package/dist/slpk-extractor/slpk-extractor.d.ts.map +1 -1
- package/dist/slpk-extractor/slpk-extractor.js +60 -50
- package/dist/slpk-extractor-cli.d.ts.map +1 -1
- package/dist/slpk-extractor-cli.js +90 -59
- package/dist/slpk-extractor.min.cjs +1 -1
- package/package.json +27 -26
- package/src/3d-tiles-converter/3d-tiles-converter.ts +21 -10
- package/src/3d-tiles-converter/helpers/b3dm-converter.ts +1 -0
- package/src/3d-tiles-converter/helpers/load-i3s.ts +3 -27
- package/src/converter-cli.ts +4 -2
- package/src/deps-installer/deps-installer.ts +7 -0
- package/src/i3s-converter/helpers/attribute-metadata-info.ts +1 -1
- package/src/i3s-converter/helpers/batch-ids-extensions.ts +3 -1
- package/src/i3s-converter/helpers/coordinate-converter.ts +2 -2
- package/src/i3s-converter/helpers/feature-attributes.ts +5 -2
- package/src/i3s-converter/helpers/geometry-attributes.ts +6 -5
- package/src/i3s-converter/helpers/geometry-converter.ts +118 -72
- package/src/i3s-converter/helpers/gltf-attributes.ts +12 -13
- package/src/i3s-converter/helpers/node-index-document.ts +18 -10
- package/src/i3s-converter/helpers/node-pages.ts +27 -29
- package/src/i3s-converter/helpers/preprocess-3d-tiles.ts +1 -0
- package/src/i3s-converter/helpers/progress.ts +1 -0
- package/src/i3s-converter/helpers/tileset-traversal.ts +22 -13
- package/src/i3s-converter/i3s-converter.ts +173 -114
- package/src/i3s-converter/json-templates/node.ts +1 -1
- package/src/i3s-server/bin/www.ts +6 -4
- package/src/i3s-server/controllers/slpk-controller.ts +4 -2
- package/src/i3s-server/routes/index.ts +10 -7
- package/src/i3s-server/routes/slpk-router.ts +22 -16
- package/src/i3s-server/utils/server-utils.ts +6 -4
- package/src/lib/utils/cli-utils.ts +2 -0
- package/src/lib/utils/conversion-dump.ts +35 -20
- package/src/lib/utils/file-utils.ts +11 -11
- package/src/lib/utils/statistic-utills.ts +5 -6
- package/src/lib/utils/write-queue.ts +2 -2
- package/src/slpk-extractor/slpk-extractor.ts +2 -1
- package/src/slpk-extractor-cli.ts +16 -8
- package/dist/3d-tiles-converter/3d-tiles-converter.js.map +0 -1
- package/dist/3d-tiles-converter/helpers/b3dm-converter.js.map +0 -1
- package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js.map +0 -1
- package/dist/3d-tiles-converter/helpers/load-i3s.js.map +0 -1
- package/dist/3d-tiles-converter/helpers/texture-atlas.js.map +0 -1
- package/dist/3d-tiles-converter/json-templates/tileset.js.map +0 -1
- package/dist/constants.js.map +0 -1
- package/dist/converter-cli.js.map +0 -1
- package/dist/deps-installer/deps-installer.js.map +0 -1
- package/dist/i3s-converter/helpers/attribute-metadata-info.js.map +0 -1
- package/dist/i3s-converter/helpers/batch-ids-extensions.js.map +0 -1
- package/dist/i3s-converter/helpers/coordinate-converter.js.map +0 -1
- package/dist/i3s-converter/helpers/create-scene-server-path.js.map +0 -1
- package/dist/i3s-converter/helpers/feature-attributes.js.map +0 -1
- package/dist/i3s-converter/helpers/geometry-attributes.js.map +0 -1
- package/dist/i3s-converter/helpers/geometry-converter.js.map +0 -1
- package/dist/i3s-converter/helpers/gltf-attributes.js.map +0 -1
- package/dist/i3s-converter/helpers/load-3d-tiles.js.map +0 -1
- package/dist/i3s-converter/helpers/node-debug.js.map +0 -1
- package/dist/i3s-converter/helpers/node-index-document.js.map +0 -1
- package/dist/i3s-converter/helpers/node-pages.js.map +0 -1
- package/dist/i3s-converter/helpers/preprocess-3d-tiles.js.map +0 -1
- package/dist/i3s-converter/helpers/progress.js.map +0 -1
- package/dist/i3s-converter/helpers/tileset-traversal.js.map +0 -1
- package/dist/i3s-converter/i3s-converter.js.map +0 -1
- package/dist/i3s-converter/json-templates/geometry-definitions.js.map +0 -1
- package/dist/i3s-converter/json-templates/layers.js.map +0 -1
- package/dist/i3s-converter/json-templates/metadata.js.map +0 -1
- package/dist/i3s-converter/json-templates/node.js.map +0 -1
- package/dist/i3s-converter/json-templates/scene-server.js.map +0 -1
- package/dist/i3s-converter/json-templates/shared-resources.js.map +0 -1
- package/dist/i3s-converter/json-templates/store.js.map +0 -1
- package/dist/i3s-converter/types.js.map +0 -1
- package/dist/i3s-server/README.md +0 -63
- package/dist/i3s-server/app.js.map +0 -1
- package/dist/i3s-server/bin/www.js.map +0 -1
- package/dist/i3s-server/certs/cert.pem +0 -19
- package/dist/i3s-server/certs/key.pem +0 -27
- package/dist/i3s-server/controllers/index-controller.js.map +0 -1
- package/dist/i3s-server/controllers/slpk-controller.js.map +0 -1
- package/dist/i3s-server/routes/index.js.map +0 -1
- package/dist/i3s-server/routes/slpk-router.js.map +0 -1
- package/dist/i3s-server/utils/create-scene-server.js.map +0 -1
- package/dist/i3s-server/utils/server-utils.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/json-schemas/conversion-dump-json-schema.js.map +0 -1
- package/dist/lib/utils/cli-utils.js.map +0 -1
- package/dist/lib/utils/compress-util.js.map +0 -1
- package/dist/lib/utils/conversion-dump.js.map +0 -1
- package/dist/lib/utils/file-utils.js.map +0 -1
- package/dist/lib/utils/geometry-utils.js.map +0 -1
- package/dist/lib/utils/lod-conversion-utils.js.map +0 -1
- package/dist/lib/utils/queue.js.map +0 -1
- package/dist/lib/utils/statistic-utills.js.map +0 -1
- package/dist/lib/utils/write-queue.js.map +0 -1
- package/dist/pgm-loader.js.map +0 -1
- package/dist/slpk-extractor/slpk-extractor.js.map +0 -1
- package/dist/slpk-extractor-cli.js.map +0 -1
- package/src/lib/utils/statistic-utills.d.ts +0 -25
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
// loaders.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
2
4
|
import { AttributeMetadataInfo } from "./helpers/attribute-metadata-info.js";
|
|
3
5
|
import { load, encode, isBrowser } from '@loaders.gl/core';
|
|
4
6
|
import { CesiumIonLoader, Tiles3DLoader } from '@loaders.gl/3d-tiles';
|
|
@@ -30,952 +32,1220 @@ import { getAttributeTypesMapFromPropertyTable, getAttributeTypesMapFromSchema }
|
|
|
30
32
|
import { NodeIndexDocument } from "./helpers/node-index-document.js";
|
|
31
33
|
import { isNestedTileset, loadNestedTileset, loadTile3DContent, loadFromArchive } from "./helpers/load-3d-tiles.js";
|
|
32
34
|
import { Matrix4 } from '@math.gl/core';
|
|
33
|
-
import { createBoundingVolume } from '@loaders.gl/tiles';
|
|
35
|
+
import { TILE_REFINEMENT, createBoundingVolume } from '@loaders.gl/tiles';
|
|
34
36
|
import { traverseDatasetWith } from "./helpers/tileset-traversal.js";
|
|
35
37
|
import { analyzeTileContent, mergePreprocessData } from "./helpers/preprocess-3d-tiles.js";
|
|
36
38
|
import { Progress } from "./helpers/progress.js";
|
|
37
39
|
import { composeHashFile, createZip } from '@loaders.gl/zip';
|
|
38
40
|
import { ConversionDump } from "../lib/utils/conversion-dump.js";
|
|
39
|
-
const ION_DEFAULT_TOKEN =
|
|
41
|
+
const ION_DEFAULT_TOKEN = process.env?.IonToken;
|
|
40
42
|
const HARDCODED_NODES_PER_PAGE = 64;
|
|
41
43
|
const _3D_TILES = '3DTILES';
|
|
42
44
|
const _3D_OBJECT_LAYER_TYPE = '3DObject';
|
|
43
|
-
const REFRESH_TOKEN_TIMEOUT = 1800;
|
|
45
|
+
const REFRESH_TOKEN_TIMEOUT = 1800; // 30 minutes in seconds
|
|
44
46
|
const CESIUM_DATASET_PREFIX = 'https://';
|
|
47
|
+
// const FS_FILE_TOO_LARGE = 'ERR_FS_FILE_TOO_LARGE';
|
|
45
48
|
const PROGRESS_PHASE1_COUNT = 'phase1-count';
|
|
49
|
+
/**
|
|
50
|
+
* Converter from 3d-tiles tileset to i3s layer
|
|
51
|
+
*/
|
|
46
52
|
export default class I3SConverter {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
workerUrl: './modules/draco/dist/draco-worker-node.js'
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
modules: {}
|
|
78
|
-
};
|
|
79
|
-
this.geoidHeightModel = null;
|
|
80
|
-
this.Loader = Tiles3DLoader;
|
|
81
|
-
this.generateTextures = void 0;
|
|
82
|
-
this.generateBoundingVolumes = void 0;
|
|
83
|
-
this.layersHasTexture = void 0;
|
|
84
|
-
this.workerSource = {};
|
|
85
|
-
this.writeQueue = new WriteQueue(new ConversionDump());
|
|
86
|
-
this.compressList = null;
|
|
87
|
-
this.preprocessData = {
|
|
88
|
-
meshTopologyTypes: new Set(),
|
|
89
|
-
metadataClasses: new Set()
|
|
90
|
-
};
|
|
91
|
-
this.progresses = {};
|
|
92
|
-
this.conversionDump = void 0;
|
|
93
|
-
this.attributeMetadataInfo = new AttributeMetadataInfo();
|
|
94
|
-
this.nodePages = new NodePages(writeFile, HARDCODED_NODES_PER_PAGE, this);
|
|
95
|
-
this.options = {};
|
|
96
|
-
this.layers0Path = '';
|
|
97
|
-
this.materialMap = new Map();
|
|
98
|
-
this.materialDefinitions = [];
|
|
99
|
-
this.geometryMap = new Map();
|
|
100
|
-
this.geometryConfigs = [];
|
|
101
|
-
this.vertexCounter = 0;
|
|
102
|
-
this.layers0 = null;
|
|
103
|
-
this.featuresHashArray = [];
|
|
104
|
-
this.refinementCounter = {
|
|
105
|
-
tilesCount: 0,
|
|
106
|
-
tilesWithAddRefineCount: 0
|
|
53
|
+
attributeMetadataInfo;
|
|
54
|
+
nodePages;
|
|
55
|
+
options;
|
|
56
|
+
layers0Path;
|
|
57
|
+
materialMap;
|
|
58
|
+
materialDefinitions;
|
|
59
|
+
geometryMap;
|
|
60
|
+
geometryConfigs;
|
|
61
|
+
vertexCounter;
|
|
62
|
+
layers0;
|
|
63
|
+
featuresHashArray;
|
|
64
|
+
refinementCounter;
|
|
65
|
+
validate;
|
|
66
|
+
boundingVolumeWarnings = [];
|
|
67
|
+
conversionStartTime = [0, 0];
|
|
68
|
+
refreshTokenTime = [0, 0];
|
|
69
|
+
sourceTileset = null;
|
|
70
|
+
loadOptions = {
|
|
71
|
+
_nodeWorkers: true,
|
|
72
|
+
reuseWorkers: true,
|
|
73
|
+
useLocalLibraries: true,
|
|
74
|
+
basis: {
|
|
75
|
+
format: 'rgba32',
|
|
76
|
+
// We need to load local fs workers because nodejs can't load workers from the Internet
|
|
77
|
+
workerUrl: './modules/textures/dist/basis-worker-node.js'
|
|
78
|
+
},
|
|
79
|
+
// We need to load local fs workers because nodejs can't load workers from the Internet
|
|
80
|
+
draco: { workerUrl: './modules/draco/dist/draco-worker-node.js' },
|
|
81
|
+
fetch: {},
|
|
82
|
+
modules: {}
|
|
107
83
|
};
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
this.conversionStartTime = process.hrtime();
|
|
121
|
-
const {
|
|
122
|
-
tilesetName,
|
|
123
|
-
slpk,
|
|
124
|
-
egmFilePath,
|
|
125
|
-
inputUrl,
|
|
126
|
-
validate,
|
|
127
|
-
outputPath,
|
|
128
|
-
draco = true,
|
|
129
|
-
sevenZipExe,
|
|
130
|
-
maxDepth,
|
|
131
|
-
token,
|
|
132
|
-
generateTextures,
|
|
133
|
-
generateBoundingVolumes,
|
|
134
|
-
instantNodeWriting = false,
|
|
135
|
-
mergeMaterials = true,
|
|
136
|
-
inquirer,
|
|
137
|
-
metadataClass,
|
|
138
|
-
analyze = false
|
|
139
|
-
} = options;
|
|
140
|
-
this.options = {
|
|
141
|
-
outputPath,
|
|
142
|
-
tilesetName,
|
|
143
|
-
maxDepth,
|
|
144
|
-
slpk,
|
|
145
|
-
sevenZipExe,
|
|
146
|
-
egmFilePath,
|
|
147
|
-
draco,
|
|
148
|
-
token,
|
|
149
|
-
inputUrl,
|
|
150
|
-
instantNodeWriting,
|
|
151
|
-
mergeMaterials,
|
|
152
|
-
inquirer,
|
|
153
|
-
metadataClass
|
|
84
|
+
geoidHeightModel = null;
|
|
85
|
+
Loader = Tiles3DLoader;
|
|
86
|
+
generateTextures;
|
|
87
|
+
generateBoundingVolumes;
|
|
88
|
+
layersHasTexture;
|
|
89
|
+
workerSource = {};
|
|
90
|
+
writeQueue = new WriteQueue(new ConversionDump());
|
|
91
|
+
compressList = null;
|
|
92
|
+
preprocessData = {
|
|
93
|
+
meshTopologyTypes: new Set(),
|
|
94
|
+
metadataClasses: new Set()
|
|
154
95
|
};
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (preloadOptions.url) {
|
|
173
|
-
tilesetUrl = preloadOptions.url;
|
|
174
|
-
}
|
|
175
|
-
if (preloadOptions.headers) {
|
|
176
|
-
this.loadOptions.fetch = {
|
|
177
|
-
headers: preloadOptions.headers
|
|
96
|
+
progresses = {};
|
|
97
|
+
conversionDump;
|
|
98
|
+
constructor() {
|
|
99
|
+
this.attributeMetadataInfo = new AttributeMetadataInfo();
|
|
100
|
+
this.nodePages = new NodePages(writeFile, HARDCODED_NODES_PER_PAGE, this);
|
|
101
|
+
this.options = {};
|
|
102
|
+
this.layers0Path = '';
|
|
103
|
+
this.materialMap = new Map();
|
|
104
|
+
this.materialDefinitions = [];
|
|
105
|
+
this.geometryMap = new Map();
|
|
106
|
+
this.geometryConfigs = [];
|
|
107
|
+
this.vertexCounter = 0;
|
|
108
|
+
this.layers0 = null;
|
|
109
|
+
this.featuresHashArray = [];
|
|
110
|
+
this.refinementCounter = {
|
|
111
|
+
tilesCount: 0,
|
|
112
|
+
tilesWithAddRefineCount: 0
|
|
178
113
|
};
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
await this._createAndSaveTileset(outputPath, tilesetName);
|
|
186
|
-
await this._finishConversion({
|
|
187
|
-
slpk: Boolean(slpk),
|
|
188
|
-
outputPath,
|
|
189
|
-
tilesetName
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
} catch (error) {
|
|
194
|
-
throw error;
|
|
195
|
-
} finally {
|
|
196
|
-
await this.writeQueue.finalize();
|
|
197
|
-
const workerFarm = WorkerFarm.getWorkerFarm({});
|
|
198
|
-
workerFarm.destroy();
|
|
199
|
-
}
|
|
200
|
-
return 'success';
|
|
201
|
-
}
|
|
202
|
-
async preprocessConversion() {
|
|
203
|
-
console.log(`Analyze source tileset`);
|
|
204
|
-
const sourceRootTile = this.sourceTileset.root;
|
|
205
|
-
await traverseDatasetWith(sourceRootTile, null, this.analyzeTile.bind(this), undefined, this.options.maxDepth);
|
|
206
|
-
const {
|
|
207
|
-
meshTopologyTypes,
|
|
208
|
-
metadataClasses
|
|
209
|
-
} = this.preprocessData;
|
|
210
|
-
console.log(`------------------------------------------------`);
|
|
211
|
-
console.log(`Preprocess results:`);
|
|
212
|
-
console.log(`Tile count: ${this.progresses[PROGRESS_PHASE1_COUNT].stepsTotal}`);
|
|
213
|
-
console.log(`glTF mesh topology types: ${Array.from(meshTopologyTypes).join(', ')}`);
|
|
214
|
-
if (metadataClasses.size) {
|
|
215
|
-
console.log(`Feature metadata classes have been found: ${Array.from(metadataClasses).join(', ')}`);
|
|
216
|
-
} else {
|
|
217
|
-
console.log('Feature metadata classes have not been found');
|
|
218
|
-
}
|
|
219
|
-
if (!meshTopologyTypes.has(GLTFPrimitiveModeString.TRIANGLES) && !meshTopologyTypes.has(GLTFPrimitiveModeString.TRIANGLE_STRIP)) {
|
|
220
|
-
console.log('The tileset is of unsupported mesh topology types. The conversion will be interrupted.');
|
|
221
|
-
console.log(`------------------------------------------------`);
|
|
222
|
-
return false;
|
|
223
|
-
}
|
|
224
|
-
console.log(`------------------------------------------------`);
|
|
225
|
-
return true;
|
|
226
|
-
}
|
|
227
|
-
async analyzeTile(sourceTile, traversalProps) {
|
|
228
|
-
const isTileset = isNestedTileset(sourceTile);
|
|
229
|
-
if (isTileset) {
|
|
230
|
-
await loadNestedTileset(this.sourceTileset, sourceTile, this.loadOptions);
|
|
231
|
-
return null;
|
|
232
|
-
}
|
|
233
|
-
if (sourceTile.id) {
|
|
234
|
-
this.progresses[PROGRESS_PHASE1_COUNT].stepsTotal += 1;
|
|
235
|
-
console.log(`[analyze]: ${sourceTile.id}`);
|
|
236
|
-
}
|
|
237
|
-
let tileContent = null;
|
|
238
|
-
try {
|
|
239
|
-
tileContent = await loadTile3DContent(this.sourceTileset, sourceTile, {
|
|
240
|
-
...this.loadOptions,
|
|
241
|
-
'3d-tiles': {
|
|
242
|
-
...this.loadOptions['3d-tiles'],
|
|
243
|
-
loadGLTF: false
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
} catch (error) {
|
|
247
|
-
console.log(`[warning]: Failed to load ${sourceTile.contentUrl}. An I3S tile with empty content will be added to the output tileset`);
|
|
114
|
+
this.validate = false;
|
|
115
|
+
this.generateTextures = false;
|
|
116
|
+
this.generateBoundingVolumes = false;
|
|
117
|
+
this.layersHasTexture = false;
|
|
118
|
+
this.compressList = null;
|
|
119
|
+
this.conversionDump = new ConversionDump();
|
|
248
120
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
this.
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
if (this.conversionDump.restored && this.conversionDump.textureSetDefinitions) {
|
|
334
|
-
this.layers0.textureSetDefinitions = this.conversionDump.textureSetDefinitions;
|
|
335
|
-
}
|
|
336
|
-
this.layers0.materialDefinitions = this.materialDefinitions;
|
|
337
|
-
this.layers0.geometryDefinitions = transform(this.geometryConfigs.map(config => ({
|
|
338
|
-
geometryConfig: {
|
|
339
|
-
...config,
|
|
340
|
-
draco: this.options.draco
|
|
341
|
-
}
|
|
342
|
-
})), geometryDefinitionTemlate());
|
|
343
|
-
if (this.layersHasTexture === false) {
|
|
344
|
-
this.layers0.store.defaultGeometrySchema.ordering = this.layers0.store.defaultGeometrySchema.ordering.filter(attribute => attribute !== 'uv0');
|
|
345
|
-
}
|
|
346
|
-
await this._writeLayers0();
|
|
347
|
-
createSceneServerPath(tilesetName, this.layers0, tilesetPath);
|
|
348
|
-
for (const filePath of this.compressList || []) {
|
|
349
|
-
await compressFileWithGzip(filePath);
|
|
350
|
-
await removeFile(filePath);
|
|
351
|
-
}
|
|
352
|
-
await this.nodePages.save();
|
|
353
|
-
await this.writeQueue.finalize();
|
|
354
|
-
await this._createSlpk(tilesetPath);
|
|
355
|
-
}
|
|
356
|
-
_formLayers0(tilesetName, sourceBoundingVolume, boundingVolumeRegion) {
|
|
357
|
-
var _this$sourceTileset2;
|
|
358
|
-
if (!((_this$sourceTileset2 = this.sourceTileset) !== null && _this$sourceTileset2 !== void 0 && _this$sourceTileset2.root)) {
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
const fullExtent = convertBoundingVolumeToI3SFullExtent(sourceBoundingVolume);
|
|
362
|
-
if (boundingVolumeRegion) {
|
|
363
|
-
fullExtent.zmin = boundingVolumeRegion[4];
|
|
364
|
-
fullExtent.zmax = boundingVolumeRegion[5];
|
|
365
|
-
}
|
|
366
|
-
const extent = [fullExtent.xmin, fullExtent.ymin, fullExtent.xmax, fullExtent.ymax];
|
|
367
|
-
const layers0data = {
|
|
368
|
-
version: `{${uuidv4().toUpperCase()}}`,
|
|
369
|
-
id: 0,
|
|
370
|
-
name: tilesetName,
|
|
371
|
-
href: './layers/0',
|
|
372
|
-
store: {
|
|
373
|
-
id: `{${uuidv4().toUpperCase()}}`,
|
|
374
|
-
extent
|
|
375
|
-
},
|
|
376
|
-
nodePages: {
|
|
377
|
-
nodesPerPage: HARDCODED_NODES_PER_PAGE
|
|
378
|
-
},
|
|
379
|
-
compressGeometry: this.options.draco,
|
|
380
|
-
fullExtent
|
|
381
|
-
};
|
|
382
|
-
this.layers0 = transform(layers0data, layersTemplate());
|
|
383
|
-
}
|
|
384
|
-
async _writeLayers0() {
|
|
385
|
-
if (this.options.slpk) {
|
|
386
|
-
await this.writeQueue.enqueue({
|
|
387
|
-
archiveKey: '3dSceneLayer.json.gz',
|
|
388
|
-
writePromise: () => writeFileForSlpk(this.layers0Path, JSON.stringify(this.layers0), '3dSceneLayer.json')
|
|
389
|
-
});
|
|
390
|
-
} else {
|
|
391
|
-
await this.writeQueue.enqueue({
|
|
392
|
-
writePromise: () => writeFile(this.layers0Path, JSON.stringify(this.layers0))
|
|
393
|
-
});
|
|
121
|
+
/**
|
|
122
|
+
* Convert a 3d tileset
|
|
123
|
+
* @param options
|
|
124
|
+
* @param options.inputUrl the url to read the tileset from
|
|
125
|
+
* @param options.outputPath the output filename
|
|
126
|
+
* @param options.tilesetName the output name of the tileset
|
|
127
|
+
* @param options.maxDepth The max tree depth of conversion
|
|
128
|
+
* @param options.slpk Generate slpk (Scene Layer Packages) output file
|
|
129
|
+
* @param options.sevenZipExe Location of 7z.exe archiver to create slpk on Windows
|
|
130
|
+
* @param options.egmFilePath location of *.pgm file to convert heights from ellipsoidal to gravity-related format
|
|
131
|
+
* @param options.token Token for Cesium ION tilesets authentication
|
|
132
|
+
* @param options.draco Generate I3S 1.7 draco compressed geometries
|
|
133
|
+
* @param options.validate -enable validation
|
|
134
|
+
* @param options.generateTextures - generate alternative type of textures (to have non-compressed jpeg/png and compressed ktx2)
|
|
135
|
+
* @param options.generateBoundingVolumes - generate bounding volumes from vertices coordinates instead of source tiles bounding volumes
|
|
136
|
+
* @param options.instantNodeWriting - Keep created 3DNodeIndexDocument files on disk instead of memory. This option reduce memory usage but decelerates conversion speed
|
|
137
|
+
*/
|
|
138
|
+
// eslint-disable-next-line max-statements, complexity
|
|
139
|
+
async convert(options) {
|
|
140
|
+
if (isBrowser) {
|
|
141
|
+
console.log(BROWSER_ERROR_MESSAGE); // eslint-disable-line no-console
|
|
142
|
+
return BROWSER_ERROR_MESSAGE;
|
|
143
|
+
}
|
|
144
|
+
this.conversionStartTime = process.hrtime();
|
|
145
|
+
const { tilesetName, slpk, egmFilePath, inputUrl, validate, outputPath, draco = true, sevenZipExe, maxDepth, token, generateTextures, generateBoundingVolumes, instantNodeWriting = false, mergeMaterials = true, inquirer, metadataClass, analyze = false } = options;
|
|
146
|
+
this.options = {
|
|
147
|
+
outputPath,
|
|
148
|
+
tilesetName,
|
|
149
|
+
maxDepth,
|
|
150
|
+
slpk,
|
|
151
|
+
sevenZipExe,
|
|
152
|
+
egmFilePath,
|
|
153
|
+
draco,
|
|
154
|
+
token,
|
|
155
|
+
inputUrl,
|
|
156
|
+
instantNodeWriting,
|
|
157
|
+
mergeMaterials,
|
|
158
|
+
inquirer,
|
|
159
|
+
metadataClass
|
|
160
|
+
};
|
|
161
|
+
this.progresses[PROGRESS_PHASE1_COUNT] = new Progress();
|
|
162
|
+
this.compressList = (this.options.instantNodeWriting && []) || null;
|
|
163
|
+
this.validate = Boolean(validate);
|
|
164
|
+
this.Loader = inputUrl.indexOf(CESIUM_DATASET_PREFIX) !== -1 ? CesiumIonLoader : Tiles3DLoader;
|
|
165
|
+
this.generateTextures = Boolean(generateTextures);
|
|
166
|
+
this.generateBoundingVolumes = Boolean(generateBoundingVolumes);
|
|
167
|
+
this.writeQueue = new WriteQueue(this.conversionDump);
|
|
168
|
+
this.writeQueue.startListening();
|
|
169
|
+
console.log('Loading egm file...'); // eslint-disable-line
|
|
170
|
+
this.geoidHeightModel = await load(egmFilePath, PGMLoader);
|
|
171
|
+
console.log('Loading egm file completed!'); // eslint-disable-line
|
|
172
|
+
if (slpk) {
|
|
173
|
+
this.nodePages.useWriteFunction(writeFileForSlpk);
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const preloadOptions = await this._fetchPreloadOptions();
|
|
177
|
+
let tilesetUrl = inputUrl;
|
|
178
|
+
if (preloadOptions.url) {
|
|
179
|
+
tilesetUrl = preloadOptions.url;
|
|
180
|
+
}
|
|
181
|
+
if (preloadOptions.headers) {
|
|
182
|
+
this.loadOptions.fetch = { headers: preloadOptions.headers };
|
|
183
|
+
}
|
|
184
|
+
this.sourceTileset = await loadFromArchive(tilesetUrl, this.Loader, this.loadOptions);
|
|
185
|
+
const preprocessResult = this.Loader === Tiles3DLoader || analyze ? await this.preprocessConversion() : true;
|
|
186
|
+
if (preprocessResult && !analyze) {
|
|
187
|
+
const selectMetadataClassResult = await this.selectMetadataClass();
|
|
188
|
+
if (selectMetadataClassResult) {
|
|
189
|
+
await this._createAndSaveTileset(outputPath, tilesetName);
|
|
190
|
+
await this._finishConversion({ slpk: Boolean(slpk), outputPath, tilesetName });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
await this.writeQueue.finalize();
|
|
199
|
+
// Clean up worker pools
|
|
200
|
+
const workerFarm = WorkerFarm.getWorkerFarm({});
|
|
201
|
+
workerFarm.destroy();
|
|
202
|
+
}
|
|
203
|
+
return 'success';
|
|
394
204
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
205
|
+
/**
|
|
206
|
+
* Preprocess stage of the tile converter. Traverse all the tiles tree and
|
|
207
|
+
* check a tile content to be sure that the data is supported
|
|
208
|
+
* @returns true - the conversion is possible, false - the tileset's content is not supported
|
|
209
|
+
*/
|
|
210
|
+
async preprocessConversion() {
|
|
211
|
+
// eslint-disable-next-line no-console
|
|
212
|
+
console.log('Analyze source tileset');
|
|
213
|
+
const sourceRootTile = this.sourceTileset.root;
|
|
214
|
+
await traverseDatasetWith({
|
|
215
|
+
tile: sourceRootTile,
|
|
216
|
+
traversalProps: null,
|
|
217
|
+
processTile: this.analyzeTile.bind(this),
|
|
218
|
+
postprocessTile: undefined,
|
|
219
|
+
maxDepth: this.options.maxDepth
|
|
220
|
+
});
|
|
221
|
+
const { meshTopologyTypes, metadataClasses } = this.preprocessData;
|
|
222
|
+
// eslint-disable-next-line no-console
|
|
223
|
+
console.log('------------------------------------------------');
|
|
224
|
+
// eslint-disable-next-line no-console
|
|
225
|
+
console.log('Preprocess results:');
|
|
226
|
+
// eslint-disable-next-line no-console
|
|
227
|
+
console.log(`Tile count: ${this.progresses[PROGRESS_PHASE1_COUNT].stepsTotal}`);
|
|
228
|
+
// eslint-disable-next-line no-console
|
|
229
|
+
console.log(`glTF mesh topology types: ${Array.from(meshTopologyTypes).join(', ')}`);
|
|
230
|
+
if (metadataClasses.size) {
|
|
231
|
+
// eslint-disable-next-line no-console
|
|
232
|
+
console.log(`Feature metadata classes have been found: ${Array.from(metadataClasses).join(', ')}`);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// eslint-disable-next-line no-console
|
|
236
|
+
console.log('Feature metadata classes have not been found');
|
|
237
|
+
}
|
|
238
|
+
if (!meshTopologyTypes.has(GLTFPrimitiveModeString.TRIANGLES) &&
|
|
239
|
+
!meshTopologyTypes.has(GLTFPrimitiveModeString.TRIANGLE_STRIP)) {
|
|
240
|
+
// eslint-disable-next-line no-console
|
|
241
|
+
console.log('The tileset is of unsupported mesh topology types. The conversion will be interrupted.');
|
|
242
|
+
// eslint-disable-next-line no-console
|
|
243
|
+
console.log('------------------------------------------------');
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
// eslint-disable-next-line no-console
|
|
247
|
+
console.log('------------------------------------------------');
|
|
248
|
+
return true;
|
|
408
249
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
250
|
+
/**
|
|
251
|
+
* Analyze a tile content. The callback for preprocess stage.
|
|
252
|
+
* @param sourceTile - 3DTiles tile JSON metadata
|
|
253
|
+
* @param traversalProps - mandatory argument but it is not used for the preprocess stage
|
|
254
|
+
* @returns - nothing
|
|
255
|
+
*/
|
|
256
|
+
async analyzeTile(sourceTile, traversalProps) {
|
|
257
|
+
const isTileset = isNestedTileset(sourceTile);
|
|
258
|
+
if (isTileset) {
|
|
259
|
+
await loadNestedTileset(this.sourceTileset, sourceTile, this.loadOptions);
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
414
262
|
if (sourceTile.id) {
|
|
415
|
-
|
|
263
|
+
this.progresses[PROGRESS_PHASE1_COUNT].stepsTotal += 1;
|
|
264
|
+
console.log(`[analyze]: ${sourceTile.id}`); // eslint-disable-line
|
|
416
265
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
const parentNode = parentNodes[0];
|
|
433
|
-
const restoreResult = await this._restoreNode(parentNode, sourceTile, transformationMatrix);
|
|
434
|
-
let childNodes;
|
|
435
|
-
if (restoreResult === null) {
|
|
436
|
-
childNodes = await this._createNode(parentNode, sourceTile, transformationMatrix);
|
|
437
|
-
} else {
|
|
438
|
-
childNodes = restoreResult;
|
|
439
|
-
}
|
|
440
|
-
await parentNode.addChildren(childNodes);
|
|
441
|
-
const newTraversalProps = {
|
|
442
|
-
transform: transformationMatrix,
|
|
443
|
-
parentNodes: childNodes
|
|
444
|
-
};
|
|
445
|
-
if (sourceTile.id) {
|
|
446
|
-
this.progresses[PROGRESS_PHASE1_COUNT].stepsDone += 1;
|
|
447
|
-
let timeRemainingString = 'Calculating time left...';
|
|
448
|
-
const timeRemainingStringBasedOnCount = this.progresses[PROGRESS_PHASE1_COUNT].getTimeRemainingString();
|
|
449
|
-
if (timeRemainingStringBasedOnCount) {
|
|
450
|
-
timeRemainingString = `${timeRemainingStringBasedOnCount} left`;
|
|
451
|
-
}
|
|
452
|
-
const percentString = this.progresses[PROGRESS_PHASE1_COUNT].getPercentString();
|
|
453
|
-
const progressString = percentString ? ` ${percentString}%, ${timeRemainingString}` : '';
|
|
454
|
-
console.log(`[converted${progressString}]: ${sourceTile.id}`);
|
|
455
|
-
}
|
|
456
|
-
return newTraversalProps;
|
|
457
|
-
}
|
|
458
|
-
async finalizeTile(conversionResults, currentTraversalProps) {
|
|
459
|
-
for (const result of conversionResults) {
|
|
460
|
-
for (const node of result.parentNodes) {
|
|
461
|
-
await node.addNeighbors();
|
|
462
|
-
}
|
|
266
|
+
let tileContent = null;
|
|
267
|
+
try {
|
|
268
|
+
tileContent = await loadTile3DContent(this.sourceTileset, sourceTile, {
|
|
269
|
+
...this.loadOptions,
|
|
270
|
+
'3d-tiles': { ...this.loadOptions['3d-tiles'], loadGLTF: false }
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
// eslint-disable-next-line no-console
|
|
275
|
+
console.log(`[warning]: Failed to load ${sourceTile.contentUrl}. An I3S tile with empty content will be added to the output tileset`);
|
|
276
|
+
}
|
|
277
|
+
const tilePreprocessData = await analyzeTileContent(tileContent);
|
|
278
|
+
mergePreprocessData(this.preprocessData, tilePreprocessData);
|
|
279
|
+
return null;
|
|
463
280
|
}
|
|
464
|
-
|
|
465
|
-
|
|
281
|
+
/**
|
|
282
|
+
* Select metadata class associated with the set of feature attributes
|
|
283
|
+
* @returns true if the metadata class has been successfully selected
|
|
284
|
+
*/
|
|
285
|
+
async selectMetadataClass() {
|
|
286
|
+
const { metadataClasses } = this.preprocessData;
|
|
287
|
+
if (metadataClasses.size > 1) {
|
|
288
|
+
if (this.options.metadataClass?.length) {
|
|
289
|
+
// eslint-disable-next-line no-console
|
|
290
|
+
console.log(`${this.options.metadataClass} has been selected`);
|
|
291
|
+
}
|
|
292
|
+
else if (this.options.inquirer) {
|
|
293
|
+
const result = await this.options.inquirer.prompt([
|
|
294
|
+
{
|
|
295
|
+
name: 'metadataClass',
|
|
296
|
+
type: 'list',
|
|
297
|
+
message: 'Select feature metadata data class to convert...',
|
|
298
|
+
choices: Array.from(metadataClasses)
|
|
299
|
+
}
|
|
300
|
+
]);
|
|
301
|
+
this.options.metadataClass = result.metadataClass;
|
|
302
|
+
// eslint-disable-next-line no-console
|
|
303
|
+
console.log(`${result.metadataClass} has been selected`);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
// eslint-disable-next-line no-console
|
|
307
|
+
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]}"`);
|
|
308
|
+
// eslint-disable-next-line no-console
|
|
309
|
+
console.log('------------------------------------------------');
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return true;
|
|
466
314
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
315
|
+
/**
|
|
316
|
+
* Convert and save the layer and embedded tiles
|
|
317
|
+
* @param outputPath - path to save output data
|
|
318
|
+
* @param tilesetName - new tileset path
|
|
319
|
+
*/
|
|
320
|
+
// eslint-disable-next-line max-statements, complexity
|
|
321
|
+
async _createAndSaveTileset(outputPath, tilesetName) {
|
|
322
|
+
const tilesetPath = join(`${outputPath}`, `${tilesetName}`);
|
|
323
|
+
await this.conversionDump.createDump(this.options);
|
|
324
|
+
if (this.conversionDump.restored && this.options.inquirer) {
|
|
325
|
+
const result = await this.options.inquirer.prompt([
|
|
326
|
+
{
|
|
327
|
+
name: 'resumeConversion',
|
|
328
|
+
type: 'confirm',
|
|
329
|
+
message: 'Dump file of the previous conversion exists, do you want to resume that conversion?'
|
|
330
|
+
}
|
|
331
|
+
]);
|
|
332
|
+
if (!result.resumeConversion) {
|
|
333
|
+
this.conversionDump.reset();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
this.layers0Path = join(tilesetPath, 'SceneServer', 'layers', '0');
|
|
337
|
+
// Removing the tilesetPath needed to exclude erroneous files after conversion
|
|
338
|
+
const removePath = this.conversionDump.restored
|
|
339
|
+
? join(this.layers0Path, 'nodepages')
|
|
340
|
+
: tilesetPath;
|
|
341
|
+
try {
|
|
342
|
+
await removeDir(removePath);
|
|
343
|
+
}
|
|
344
|
+
catch (e) {
|
|
345
|
+
// do nothing
|
|
346
|
+
}
|
|
347
|
+
if (this.conversionDump.restored && this.conversionDump.attributeMetadataInfo) {
|
|
348
|
+
this.attributeMetadataInfo.fromObject(this.conversionDump.attributeMetadataInfo);
|
|
349
|
+
}
|
|
350
|
+
this.materialDefinitions = [];
|
|
351
|
+
this.materialMap = new Map();
|
|
352
|
+
if (this.conversionDump.restored && this.conversionDump.materialDefinitions) {
|
|
353
|
+
for (let i = 0; i < this.conversionDump.materialDefinitions.length; i++) {
|
|
354
|
+
const hash = md5(JSON.stringify(this.conversionDump.materialDefinitions[i]));
|
|
355
|
+
this.materialMap.set(hash, i);
|
|
356
|
+
}
|
|
357
|
+
this.materialDefinitions = this.conversionDump.materialDefinitions;
|
|
358
|
+
}
|
|
359
|
+
const sourceRootTile = this.sourceTileset.root;
|
|
360
|
+
const sourceBoundingVolume = createBoundingVolume(sourceRootTile.boundingVolume, new Matrix4(sourceRootTile.transform), null);
|
|
361
|
+
this._formLayers0(tilesetName, sourceBoundingVolume, this.sourceTileset?.root?.boundingVolume?.region);
|
|
362
|
+
const boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);
|
|
363
|
+
await this.nodePages.push({
|
|
364
|
+
index: 0,
|
|
365
|
+
lodThreshold: 0,
|
|
366
|
+
obb: boundingVolumes.obb,
|
|
367
|
+
children: []
|
|
368
|
+
});
|
|
369
|
+
this.progresses[PROGRESS_PHASE1_COUNT].startMonitoring();
|
|
370
|
+
const rootNode = await NodeIndexDocument.createRootNode(boundingVolumes, this);
|
|
371
|
+
await traverseDatasetWith({
|
|
372
|
+
tile: sourceRootTile,
|
|
373
|
+
traversalProps: {
|
|
374
|
+
transform: new Matrix4(sourceRootTile.transform),
|
|
375
|
+
parentNodes: [rootNode]
|
|
376
|
+
},
|
|
377
|
+
processTile: this.convertTile.bind(this),
|
|
378
|
+
postprocessTile: this.finalizeTile.bind(this),
|
|
379
|
+
maxDepth: this.options.maxDepth
|
|
380
|
+
});
|
|
381
|
+
this.progresses[PROGRESS_PHASE1_COUNT].stopMonitoring();
|
|
382
|
+
console.log(`[finalizing conversion]`); // eslint-disable-line
|
|
383
|
+
this.layers0.attributeStorageInfo = this.attributeMetadataInfo.attributeStorageInfo;
|
|
384
|
+
this.layers0.fields = this.attributeMetadataInfo.fields;
|
|
385
|
+
this.layers0.popupInfo = this.attributeMetadataInfo.popupInfo;
|
|
386
|
+
if (this.attributeMetadataInfo.attributeStorageInfo.length) {
|
|
387
|
+
this.layers0.layerType = _3D_OBJECT_LAYER_TYPE;
|
|
388
|
+
}
|
|
389
|
+
if (this.conversionDump.restored && this.conversionDump.textureSetDefinitions) {
|
|
390
|
+
this.layers0.textureSetDefinitions = this.conversionDump.textureSetDefinitions;
|
|
391
|
+
}
|
|
392
|
+
this.layers0.materialDefinitions = this.materialDefinitions;
|
|
393
|
+
// @ts-ignore
|
|
394
|
+
this.layers0.geometryDefinitions = transform(this.geometryConfigs.map((config) => ({
|
|
395
|
+
geometryConfig: { ...config, draco: this.options.draco }
|
|
396
|
+
})), geometryDefinitionTemlate());
|
|
397
|
+
if (this.layersHasTexture === false) {
|
|
398
|
+
this.layers0.store.defaultGeometrySchema.ordering =
|
|
399
|
+
this.layers0.store.defaultGeometrySchema.ordering.filter((attribute) => attribute !== 'uv0');
|
|
400
|
+
}
|
|
401
|
+
await this._writeLayers0();
|
|
402
|
+
createSceneServerPath(tilesetName, this.layers0, tilesetPath);
|
|
403
|
+
for (const filePath of this.compressList || []) {
|
|
404
|
+
await compressFileWithGzip(filePath);
|
|
405
|
+
await removeFile(filePath);
|
|
406
|
+
}
|
|
407
|
+
await this.nodePages.save();
|
|
408
|
+
await this.writeQueue.finalize();
|
|
409
|
+
await this._createSlpk(tilesetPath);
|
|
472
410
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
411
|
+
/**
|
|
412
|
+
* Form object of 3DSceneLayer https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DSceneLayer.cmn.md
|
|
413
|
+
* @param tilesetName - Name of layer
|
|
414
|
+
* @param sourceBoundingVolume - initialized bounding volume of the source root tile
|
|
415
|
+
* @param boundingVolumeRegion - region bounding volume of the source root tile
|
|
416
|
+
*/
|
|
417
|
+
_formLayers0(tilesetName, sourceBoundingVolume, boundingVolumeRegion) {
|
|
418
|
+
if (!this.sourceTileset?.root) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const fullExtent = convertBoundingVolumeToI3SFullExtent(sourceBoundingVolume);
|
|
422
|
+
if (boundingVolumeRegion) {
|
|
423
|
+
fullExtent.zmin = boundingVolumeRegion[4];
|
|
424
|
+
fullExtent.zmax = boundingVolumeRegion[5];
|
|
425
|
+
}
|
|
426
|
+
const extent = [fullExtent.xmin, fullExtent.ymin, fullExtent.xmax, fullExtent.ymax];
|
|
427
|
+
const layers0data = {
|
|
428
|
+
version: `{${uuidv4().toUpperCase()}}`,
|
|
429
|
+
id: 0,
|
|
430
|
+
name: tilesetName,
|
|
431
|
+
href: './layers/0',
|
|
432
|
+
store: {
|
|
433
|
+
id: `{${uuidv4().toUpperCase()}}`,
|
|
434
|
+
extent
|
|
435
|
+
},
|
|
436
|
+
nodePages: {
|
|
437
|
+
nodesPerPage: HARDCODED_NODES_PER_PAGE
|
|
438
|
+
},
|
|
439
|
+
compressGeometry: this.options.draco,
|
|
440
|
+
fullExtent
|
|
441
|
+
};
|
|
442
|
+
this.layers0 = transform(layers0data, layersTemplate());
|
|
487
443
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
const nodes = [];
|
|
504
|
-
for (const convertedNode of this.conversionDump.tilesConverted[sourceTile.id].nodes) {
|
|
505
|
-
const {
|
|
506
|
-
node
|
|
507
|
-
} = await this._generateNodeIndexDocument(boundingVolumes, {
|
|
508
|
-
...convertedNode.dumpMetadata,
|
|
509
|
-
nodeId: convertedNode.nodeId
|
|
510
|
-
}, parentNode, sourceTile, true);
|
|
511
|
-
nodes.push(node);
|
|
512
|
-
}
|
|
513
|
-
return nodes;
|
|
514
|
-
} else if (this.conversionDump.restored && sourceTile.id) {
|
|
515
|
-
this.conversionDump.clearDumpRecord(sourceTile.id);
|
|
444
|
+
/**
|
|
445
|
+
* Write 3DSceneLayer https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DSceneLayer.cmn.md in file
|
|
446
|
+
*/
|
|
447
|
+
async _writeLayers0() {
|
|
448
|
+
if (this.options.slpk) {
|
|
449
|
+
await this.writeQueue.enqueue({
|
|
450
|
+
archiveKey: '3dSceneLayer.json.gz',
|
|
451
|
+
writePromise: () => writeFileForSlpk(this.layers0Path, JSON.stringify(this.layers0), '3dSceneLayer.json')
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
await this.writeQueue.enqueue({
|
|
456
|
+
writePromise: () => writeFile(this.layers0Path, JSON.stringify(this.layers0))
|
|
457
|
+
});
|
|
458
|
+
}
|
|
516
459
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
460
|
+
/**
|
|
461
|
+
* Pack files into *.slpk archive
|
|
462
|
+
* @param tilesetPath - Path to save file
|
|
463
|
+
*/
|
|
464
|
+
async _createSlpk(tilesetPath) {
|
|
465
|
+
await this.conversionDump.deleteDumpFile();
|
|
466
|
+
if (this.options.slpk) {
|
|
467
|
+
const slpkTilesetPath = join(tilesetPath, 'SceneServer', 'layers', '0');
|
|
468
|
+
const slpkFileName = `${tilesetPath}.slpk`;
|
|
469
|
+
await createZip(slpkTilesetPath, slpkFileName, async (fileList) => ({
|
|
470
|
+
path: '@specialIndexFileHASH128@',
|
|
471
|
+
file: await composeHashFile(fileList)
|
|
472
|
+
}));
|
|
473
|
+
try {
|
|
474
|
+
await removeDir(tilesetPath);
|
|
475
|
+
}
|
|
476
|
+
catch (e) {
|
|
477
|
+
// do nothing
|
|
478
|
+
}
|
|
479
|
+
}
|
|
527
480
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
meshMaterial: null,
|
|
548
|
-
vertexCount: null,
|
|
549
|
-
attributes: null,
|
|
550
|
-
featureCount: null,
|
|
551
|
-
boundingVolumes: null
|
|
552
|
-
};
|
|
553
|
-
for (const resources of resourcesData || [emptyResources]) {
|
|
554
|
-
const {
|
|
555
|
-
node,
|
|
556
|
-
nodeInPage,
|
|
557
|
-
nodeData
|
|
558
|
-
} = await this._generateNodeIndexDocument(boundingVolumes, resources, parentNode, sourceTile, false);
|
|
559
|
-
nodes.push(node);
|
|
560
|
-
if (nodeInPage.mesh) {
|
|
481
|
+
/**
|
|
482
|
+
* Convert the specific 3DTiles tile to I3S nodes.
|
|
483
|
+
* This is callback function for the traversal generic function
|
|
484
|
+
* @param sourceTile - current 3DTiles tile JSON metadata
|
|
485
|
+
* @param traversalProps - traversal properties calculated recursively
|
|
486
|
+
* @returns - traversal properties for the child tiles
|
|
487
|
+
*/
|
|
488
|
+
// eslint-disable-next-line max-statements
|
|
489
|
+
async convertTile(sourceTile, traversalProps) {
|
|
490
|
+
const isTileset = isNestedTileset(sourceTile);
|
|
491
|
+
if (isTileset || sourceTile.type === 'empty') {
|
|
492
|
+
if (isTileset) {
|
|
493
|
+
if (sourceTile.id) {
|
|
494
|
+
console.log(`[load]: ${sourceTile.id}`); // eslint-disable-line
|
|
495
|
+
}
|
|
496
|
+
await loadNestedTileset(this.sourceTileset, sourceTile, this.loadOptions);
|
|
497
|
+
}
|
|
498
|
+
return traversalProps;
|
|
499
|
+
}
|
|
561
500
|
if (sourceTile.id) {
|
|
562
|
-
|
|
563
|
-
const dumpMetadata = {
|
|
564
|
-
boundingVolumes: resources.boundingVolumes,
|
|
565
|
-
attributesCount: (_resources$attributes = resources.attributes) === null || _resources$attributes === void 0 ? void 0 : _resources$attributes.length,
|
|
566
|
-
featureCount: resources.featureCount,
|
|
567
|
-
geometry: Boolean(resources.geometry),
|
|
568
|
-
hasUvRegions: resources.hasUvRegions,
|
|
569
|
-
materialId: nodeInPage.mesh.material.definition,
|
|
570
|
-
texelCountHint: nodeInPage.mesh.material.texelCountHint,
|
|
571
|
-
vertexCount: resources.vertexCount
|
|
572
|
-
};
|
|
573
|
-
this.conversionDump.setMaterialsDefinitions(this.materialDefinitions);
|
|
574
|
-
await this.conversionDump.addNode(sourceTile.id, nodeInPage.index, dumpMetadata);
|
|
575
|
-
}
|
|
576
|
-
await this._writeResources(resources, node.id, sourceTile);
|
|
577
|
-
}
|
|
578
|
-
if (this.validate) {
|
|
579
|
-
this.boundingVolumeWarnings = validateNodeBoundingVolumes(nodeData);
|
|
580
|
-
if (this.boundingVolumeWarnings && this.boundingVolumeWarnings.length) {
|
|
581
|
-
console.warn('Bounding Volume Warnings: ', ...this.boundingVolumeWarnings);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
nodeIds.push(nodeInPage.index);
|
|
585
|
-
nodesInPage.push(nodeInPage);
|
|
586
|
-
}
|
|
587
|
-
return nodes;
|
|
588
|
-
}
|
|
589
|
-
async _convertResources(sourceTile, transformationMatrix, boundingVolume, tileContent, parentId, propertyTable) {
|
|
590
|
-
if (!this.isContentSupported(sourceTile) || !tileContent) {
|
|
591
|
-
return null;
|
|
592
|
-
}
|
|
593
|
-
const draftObb = {
|
|
594
|
-
center: [],
|
|
595
|
-
halfSize: [],
|
|
596
|
-
quaternion: []
|
|
597
|
-
};
|
|
598
|
-
const resourcesData = await convertB3dmToI3sGeometry(tileContent, transformationMatrix, boundingVolume, async () => (await this.nodePages.push({
|
|
599
|
-
index: 0,
|
|
600
|
-
obb: draftObb
|
|
601
|
-
}, parentId)).index, propertyTable, this.featuresHashArray, this.attributeMetadataInfo.attributeStorageInfo, this.options.draco, this.generateBoundingVolumes, this.options.mergeMaterials, this.geoidHeightModel, this.loadOptions.modules, this.options.metadataClass);
|
|
602
|
-
return resourcesData;
|
|
603
|
-
}
|
|
604
|
-
async _updateNodeInNodePages(maxScreenThresholdSQ, boundingVolumes, sourceTile, parentId, resources) {
|
|
605
|
-
const {
|
|
606
|
-
vertexCount,
|
|
607
|
-
featureCount,
|
|
608
|
-
geometry,
|
|
609
|
-
hasUvRegions
|
|
610
|
-
} = resources;
|
|
611
|
-
const nodeInPage = {
|
|
612
|
-
index: 0,
|
|
613
|
-
lodThreshold: maxScreenThresholdSQ.maxError,
|
|
614
|
-
obb: boundingVolumes.obb,
|
|
615
|
-
children: []
|
|
616
|
-
};
|
|
617
|
-
if (geometry && this.isContentSupported(sourceTile)) {
|
|
618
|
-
nodeInPage.mesh = {
|
|
619
|
-
geometry: {
|
|
620
|
-
definition: this.findOrCreateGeometryDefinition(Boolean('texture' in resources && resources.texture || 'texelCountHint' in resources && resources.texelCountHint), hasUvRegions),
|
|
621
|
-
resource: 0
|
|
622
|
-
},
|
|
623
|
-
attribute: {
|
|
624
|
-
resource: 0
|
|
625
|
-
},
|
|
626
|
-
material: {
|
|
627
|
-
definition: 0
|
|
501
|
+
console.log(`[convert]: ${sourceTile.id}`); // eslint-disable-line
|
|
628
502
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
503
|
+
const { parentNodes, transform } = traversalProps;
|
|
504
|
+
let transformationMatrix = transform.clone();
|
|
505
|
+
if (sourceTile.transform) {
|
|
506
|
+
transformationMatrix = transformationMatrix.multiplyRight(sourceTile.transform);
|
|
507
|
+
}
|
|
508
|
+
const parentNode = parentNodes[0];
|
|
509
|
+
const restoreResult = await this._restoreNode(parentNode, sourceTile, transformationMatrix);
|
|
510
|
+
let childNodes;
|
|
511
|
+
if (restoreResult === null) {
|
|
512
|
+
childNodes = await this._createNode(parentNode, sourceTile, transformationMatrix);
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
childNodes = restoreResult;
|
|
516
|
+
}
|
|
517
|
+
await parentNode.addChildren(childNodes);
|
|
518
|
+
const newTraversalProps = {
|
|
519
|
+
transform: transformationMatrix,
|
|
520
|
+
parentNodes: childNodes
|
|
521
|
+
};
|
|
522
|
+
if (sourceTile.id) {
|
|
523
|
+
this.progresses[PROGRESS_PHASE1_COUNT].stepsDone += 1;
|
|
524
|
+
let timeRemainingString = 'Calculating time left...';
|
|
525
|
+
const timeRemainingStringBasedOnCount = this.progresses[PROGRESS_PHASE1_COUNT].getTimeRemainingString();
|
|
526
|
+
if (timeRemainingStringBasedOnCount) {
|
|
527
|
+
timeRemainingString = `${timeRemainingStringBasedOnCount} left`;
|
|
528
|
+
}
|
|
529
|
+
const percentString = this.progresses[PROGRESS_PHASE1_COUNT].getPercentString();
|
|
530
|
+
const progressString = percentString ? ` ${percentString}%, ${timeRemainingString}` : '';
|
|
531
|
+
console.log(`[converted${progressString}]: ${sourceTile.id}`); // eslint-disable-line
|
|
532
|
+
}
|
|
533
|
+
return newTraversalProps;
|
|
637
534
|
}
|
|
638
|
-
|
|
639
|
-
|
|
535
|
+
/**
|
|
536
|
+
* Do final action with nodes after the current node and all child nodes been converted.
|
|
537
|
+
* @param conversionResults - array of conversion results of the current node
|
|
538
|
+
* @param currentTraversalProps - traversal properties of the current node
|
|
539
|
+
*/
|
|
540
|
+
async finalizeTile(conversionResults, currentTraversalProps) {
|
|
541
|
+
for (const result of conversionResults) {
|
|
542
|
+
for (const node of result.parentNodes) {
|
|
543
|
+
await node.addNeighbors();
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
for (const node of currentTraversalProps.parentNodes) {
|
|
547
|
+
await node.save();
|
|
548
|
+
}
|
|
640
549
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
550
|
+
/**
|
|
551
|
+
* Generate NodeIndexDocument
|
|
552
|
+
* @param boundingVolumes - Bounding volumes
|
|
553
|
+
* @param resources - converted or dumped node resources data
|
|
554
|
+
* @param parentNode - 3DNodeIndexDocument of parent node
|
|
555
|
+
* @param sourceTile - source 3DTile data
|
|
556
|
+
* @param isDumped - indicator if the node is dumped
|
|
557
|
+
* @return NodeIndexDocument, nodeInPage and node data
|
|
558
|
+
*/
|
|
559
|
+
async _generateNodeIndexDocument(boundingVolumes, resources, parentNode, sourceTile, isDumped) {
|
|
560
|
+
this.layersHasTexture =
|
|
561
|
+
this.layersHasTexture ||
|
|
562
|
+
Boolean(('texture' in resources && resources.texture) ||
|
|
563
|
+
('texelCountHint' in resources && resources.texelCountHint));
|
|
564
|
+
if (this.generateBoundingVolumes && resources.boundingVolumes) {
|
|
565
|
+
boundingVolumes = resources.boundingVolumes;
|
|
566
|
+
}
|
|
567
|
+
const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);
|
|
568
|
+
const maxScreenThresholdSQ = lodSelection.find((val) => val.metricType === 'maxScreenThresholdSQ') || { maxError: 0 };
|
|
569
|
+
if (isDumped) {
|
|
570
|
+
const draftObb = {
|
|
571
|
+
center: [],
|
|
572
|
+
halfSize: [],
|
|
573
|
+
quaternion: []
|
|
574
|
+
};
|
|
575
|
+
await this.nodePages.push({ index: 0, obb: draftObb }, parentNode.inPageId);
|
|
576
|
+
}
|
|
577
|
+
const nodeInPage = await this._updateNodeInNodePages(maxScreenThresholdSQ, boundingVolumes, sourceTile, parentNode.inPageId, resources);
|
|
578
|
+
const nodeData = await NodeIndexDocument.createNodeIndexDocument(parentNode, boundingVolumes, lodSelection, nodeInPage, resources);
|
|
579
|
+
const node = await new NodeIndexDocument(nodeInPage.index, this).addData(nodeData);
|
|
580
|
+
return { node, nodeInPage, nodeData };
|
|
646
581
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
582
|
+
/**
|
|
583
|
+
* Restore 3DNodeIndexDocument from a comversion dump file
|
|
584
|
+
* @param parentNode - 3DNodeIndexDocument of parent node
|
|
585
|
+
* @param sourceTile - source 3DTile data
|
|
586
|
+
* @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying
|
|
587
|
+
* transform of all parent tiles and transform of the current tile
|
|
588
|
+
*/
|
|
589
|
+
async _restoreNode(parentNode, sourceTile, transformationMatrix) {
|
|
590
|
+
this._checkAddRefinementTypeForTile(sourceTile);
|
|
591
|
+
await this._updateTilesetOptions();
|
|
592
|
+
if (this.conversionDump.restored &&
|
|
593
|
+
sourceTile.id &&
|
|
594
|
+
this.conversionDump.isFileConversionComplete(sourceTile.id)) {
|
|
595
|
+
const sourceBoundingVolume = createBoundingVolume(sourceTile.boundingVolume, transformationMatrix, null);
|
|
596
|
+
const boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);
|
|
597
|
+
const nodes = [];
|
|
598
|
+
for (const convertedNode of this.conversionDump.tilesConverted[sourceTile.id].nodes) {
|
|
599
|
+
const { node } = await this._generateNodeIndexDocument(boundingVolumes, {
|
|
600
|
+
...convertedNode.dumpMetadata,
|
|
601
|
+
nodeId: convertedNode.nodeId
|
|
602
|
+
}, parentNode, sourceTile, true);
|
|
603
|
+
nodes.push(node);
|
|
604
|
+
}
|
|
605
|
+
return nodes;
|
|
606
|
+
}
|
|
607
|
+
else if (this.conversionDump.restored && sourceTile.id) {
|
|
608
|
+
// clear existing record in a dump
|
|
609
|
+
this.conversionDump.clearDumpRecord(sourceTile.id);
|
|
610
|
+
}
|
|
611
|
+
return null;
|
|
652
612
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
613
|
+
/**
|
|
614
|
+
* Convert tile to one or more I3S nodes
|
|
615
|
+
* @param parentNode - 3DNodeIndexDocument of parent node
|
|
616
|
+
* @param sourceTile - source 3DTile data
|
|
617
|
+
* @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying
|
|
618
|
+
* transform of all parent tiles and transform of the current tile
|
|
619
|
+
* @param level - tree level
|
|
620
|
+
*/
|
|
621
|
+
// eslint-disable-next-line max-statements
|
|
622
|
+
async _createNode(parentNode, sourceTile, transformationMatrix) {
|
|
623
|
+
this._checkAddRefinementTypeForTile(sourceTile);
|
|
624
|
+
await this._updateTilesetOptions();
|
|
625
|
+
let tileContent = null;
|
|
626
|
+
try {
|
|
627
|
+
tileContent = await loadTile3DContent(this.sourceTileset, sourceTile, this.loadOptions);
|
|
628
|
+
}
|
|
629
|
+
catch (error) {
|
|
630
|
+
// eslint-disable-next-line no-console
|
|
631
|
+
console.log(`[warning]: Failed to load ${sourceTile.contentUrl}`);
|
|
632
|
+
}
|
|
633
|
+
const sourceBoundingVolume = createBoundingVolume(sourceTile.boundingVolume, transformationMatrix, null);
|
|
634
|
+
const boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);
|
|
635
|
+
const propertyTable = getPropertyTable(tileContent, this.options.metadataClass);
|
|
636
|
+
this.createAttributeStorageInfo(tileContent, propertyTable);
|
|
637
|
+
this.conversionDump.attributeMetadataInfo = {
|
|
638
|
+
attributeStorageInfo: this.attributeMetadataInfo.attributeStorageInfo,
|
|
639
|
+
fields: this.attributeMetadataInfo.fields,
|
|
640
|
+
popupInfo: this.attributeMetadataInfo.popupInfo
|
|
641
|
+
};
|
|
642
|
+
const resourcesData = await this._convertResources({
|
|
643
|
+
sourceTile,
|
|
644
|
+
transformationMatrix,
|
|
645
|
+
boundingVolume: sourceBoundingVolume,
|
|
646
|
+
tileContent,
|
|
647
|
+
parentId: parentNode.inPageId,
|
|
648
|
+
propertyTable
|
|
649
|
+
});
|
|
650
|
+
const nodes = [];
|
|
651
|
+
const nodeIds = [];
|
|
652
|
+
const nodesInPage = [];
|
|
653
|
+
const emptyResources = {
|
|
654
|
+
geometry: null,
|
|
655
|
+
compressedGeometry: null,
|
|
656
|
+
texture: null,
|
|
657
|
+
hasUvRegions: false,
|
|
658
|
+
sharedResources: null,
|
|
659
|
+
meshMaterial: null,
|
|
660
|
+
vertexCount: null,
|
|
661
|
+
attributes: null,
|
|
662
|
+
featureCount: null,
|
|
663
|
+
boundingVolumes: null
|
|
664
|
+
};
|
|
665
|
+
for (const resources of resourcesData || [emptyResources]) {
|
|
666
|
+
const { node, nodeInPage, nodeData } = await this._generateNodeIndexDocument(boundingVolumes, resources, parentNode, sourceTile, false);
|
|
667
|
+
nodes.push(node);
|
|
668
|
+
if (nodeInPage.mesh) {
|
|
669
|
+
// update a record in a dump file
|
|
670
|
+
if (sourceTile.id) {
|
|
671
|
+
const dumpMetadata = {
|
|
672
|
+
boundingVolumes: resources.boundingVolumes,
|
|
673
|
+
attributesCount: resources.attributes?.length,
|
|
674
|
+
featureCount: resources.featureCount,
|
|
675
|
+
geometry: Boolean(resources.geometry),
|
|
676
|
+
hasUvRegions: resources.hasUvRegions,
|
|
677
|
+
materialId: nodeInPage.mesh.material.definition,
|
|
678
|
+
texelCountHint: nodeInPage.mesh.material.texelCountHint,
|
|
679
|
+
vertexCount: resources.vertexCount
|
|
680
|
+
};
|
|
681
|
+
this.conversionDump.setMaterialsDefinitions(this.materialDefinitions);
|
|
682
|
+
await this.conversionDump.addNode(sourceTile.id, nodeInPage.index, dumpMetadata);
|
|
683
|
+
}
|
|
684
|
+
// write resources
|
|
685
|
+
await this._writeResources(resources, node.id, sourceTile);
|
|
686
|
+
}
|
|
687
|
+
if (this.validate) {
|
|
688
|
+
this.boundingVolumeWarnings = validateNodeBoundingVolumes(nodeData);
|
|
689
|
+
if (this.boundingVolumeWarnings && this.boundingVolumeWarnings.length) {
|
|
690
|
+
console.warn('Bounding Volume Warnings: ', ...this.boundingVolumeWarnings); //eslint-disable-line
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
nodeIds.push(nodeInPage.index);
|
|
694
|
+
nodesInPage.push(nodeInPage);
|
|
695
|
+
}
|
|
696
|
+
return nodes;
|
|
656
697
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
698
|
+
/**
|
|
699
|
+
* Convert tile to one or more I3S nodes
|
|
700
|
+
* @param sourceTile - source tile (3DTile)
|
|
701
|
+
* @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying
|
|
702
|
+
* transform of all parent tiles and transform of the current tile
|
|
703
|
+
* @param boundingVolume - initialized bounding volume of the source tile
|
|
704
|
+
* @param tileContent - content of the source tile
|
|
705
|
+
* @param parentId - id of parent node in node pages
|
|
706
|
+
* @param propertyTable - batch table from b3dm / feature properties from EXT_FEATURE_METADATA, EXT_MESH_FEATURES or EXT_STRUCTURAL_METADATA
|
|
707
|
+
* @returns - converted node resources
|
|
708
|
+
*/
|
|
709
|
+
async _convertResources({ sourceTile, transformationMatrix, boundingVolume, tileContent, parentId, propertyTable }) {
|
|
710
|
+
if (!this.isContentSupported(sourceTile) || !tileContent) {
|
|
711
|
+
return null;
|
|
712
|
+
}
|
|
713
|
+
const draftObb = {
|
|
714
|
+
center: [],
|
|
715
|
+
halfSize: [],
|
|
716
|
+
quaternion: []
|
|
717
|
+
};
|
|
718
|
+
const resourcesData = await convertB3dmToI3sGeometry({
|
|
719
|
+
tileContent,
|
|
720
|
+
tileTransform: transformationMatrix,
|
|
721
|
+
tileBoundingVolume: boundingVolume,
|
|
722
|
+
addNodeToNodePage: async () => (await this.nodePages.push({ index: 0, obb: draftObb }, parentId)).index,
|
|
723
|
+
propertyTable,
|
|
724
|
+
featuresHashArray: this.featuresHashArray,
|
|
725
|
+
attributeStorageInfo: this.attributeMetadataInfo.attributeStorageInfo,
|
|
726
|
+
draco: this.options.draco,
|
|
727
|
+
generateBoundingVolumes: this.generateBoundingVolumes,
|
|
728
|
+
shouldMergeMaterials: this.options.mergeMaterials,
|
|
729
|
+
geoidHeightModel: this.geoidHeightModel,
|
|
730
|
+
libraries: this.loadOptions.modules,
|
|
731
|
+
metadataClass: this.options.metadataClass
|
|
732
|
+
});
|
|
733
|
+
return resourcesData;
|
|
660
734
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
735
|
+
/**
|
|
736
|
+
* Update node object (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/node.cmn.md)
|
|
737
|
+
* in node pages (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/nodePage.cmn.md)
|
|
738
|
+
* @param maxScreenThresholdSQ - Level of Details (LOD) metric
|
|
739
|
+
* @param boundingVolumes - Bounding volumes
|
|
740
|
+
* @param sourceTile - source tile (3DTile)
|
|
741
|
+
* @param parentId - id of parent node in node pages
|
|
742
|
+
* @param resources - the node resources data
|
|
743
|
+
* @param resources.meshMaterial - PBR-like material object
|
|
744
|
+
* @param resources.texture - texture image
|
|
745
|
+
* @param resources.vertexCount - number of vertices in geometry
|
|
746
|
+
* @param resources.featureCount - number of features
|
|
747
|
+
* @param resources.geometry - Uint8Array with geometry attributes
|
|
748
|
+
* @return the node object in node pages
|
|
749
|
+
*/
|
|
750
|
+
// eslint-disable-next-line max-statements, complexity
|
|
751
|
+
async _updateNodeInNodePages(maxScreenThresholdSQ, boundingVolumes, sourceTile, parentId, resources) {
|
|
752
|
+
const { vertexCount, featureCount, geometry, hasUvRegions } = resources;
|
|
753
|
+
const nodeInPage = {
|
|
754
|
+
index: 0,
|
|
755
|
+
lodThreshold: maxScreenThresholdSQ.maxError,
|
|
756
|
+
obb: boundingVolumes.obb,
|
|
757
|
+
children: []
|
|
758
|
+
};
|
|
759
|
+
if (geometry && this.isContentSupported(sourceTile)) {
|
|
760
|
+
nodeInPage.mesh = {
|
|
761
|
+
geometry: {
|
|
762
|
+
definition: this.findOrCreateGeometryDefinition(Boolean(('texture' in resources && resources.texture) ||
|
|
763
|
+
('texelCountHint' in resources && resources.texelCountHint)), hasUvRegions),
|
|
764
|
+
resource: 0
|
|
765
|
+
},
|
|
766
|
+
attribute: {
|
|
767
|
+
resource: 0
|
|
768
|
+
},
|
|
769
|
+
material: {
|
|
770
|
+
definition: 0
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
const nodeId = 'nodeId' in resources ? resources.nodeId : undefined;
|
|
775
|
+
let node;
|
|
776
|
+
if (!nodeId) {
|
|
777
|
+
node = await this.nodePages.push(nodeInPage, parentId);
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
node = await this.nodePages.getNodeById(nodeId);
|
|
781
|
+
}
|
|
782
|
+
if (!nodeInPage.mesh) {
|
|
783
|
+
// eslint-disable-next-line no-console
|
|
784
|
+
console.log(`[warning]: node ${node.index} is created with empty content`);
|
|
785
|
+
}
|
|
786
|
+
NodePages.updateAll(node, nodeInPage);
|
|
787
|
+
if ('meshMaterial' in resources && resources.meshMaterial) {
|
|
788
|
+
NodePages.updateMaterialByNodeId(node, this._findOrCreateMaterial(resources.meshMaterial));
|
|
789
|
+
}
|
|
790
|
+
else if ('materialId' in resources && resources.materialId !== null) {
|
|
791
|
+
NodePages.updateMaterialByNodeId(node, resources.materialId);
|
|
792
|
+
}
|
|
793
|
+
if ('texture' in resources && resources.texture) {
|
|
794
|
+
const texelCountHint = resources.texture.image.height * resources.texture.image.width;
|
|
795
|
+
NodePages.updateTexelCountHintByNodeId(node, texelCountHint);
|
|
796
|
+
}
|
|
797
|
+
else if ('texelCountHint' in resources && resources.texelCountHint) {
|
|
798
|
+
NodePages.updateTexelCountHintByNodeId(node, resources.texelCountHint);
|
|
799
|
+
}
|
|
800
|
+
if (vertexCount) {
|
|
801
|
+
this.vertexCounter += vertexCount;
|
|
802
|
+
NodePages.updateVertexCountByNodeId(node, vertexCount);
|
|
803
|
+
}
|
|
804
|
+
NodePages.updateNodeAttributeByNodeId(node);
|
|
805
|
+
if (featureCount) {
|
|
806
|
+
NodePages.updateFeatureCountByNodeId(node, featureCount);
|
|
807
|
+
}
|
|
808
|
+
this.nodePages.saveNode(node);
|
|
809
|
+
return node;
|
|
698
810
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
811
|
+
/**
|
|
812
|
+
* Write node resources in files
|
|
813
|
+
* @param resources - source tile (3DTile)
|
|
814
|
+
* @param resources.geometry - Uint8Array with geometry attributes
|
|
815
|
+
* @param resources.compressedGeometry - Uint8Array with compressed (draco) geometry
|
|
816
|
+
* @param resources.texture - texture image
|
|
817
|
+
* @param resources.sharedResources - shared resource data object
|
|
818
|
+
* @param resources.attributes - feature attributes
|
|
819
|
+
* @param nodePath - node path
|
|
820
|
+
* @param sourceTile - source tile (3DTile)
|
|
821
|
+
* @return {Promise<void>}
|
|
822
|
+
*/
|
|
823
|
+
async _writeResources(resources, nodePath, sourceTile) {
|
|
824
|
+
const { geometry: geometryBuffer, compressedGeometry, texture, sharedResources, attributes } = resources;
|
|
825
|
+
const childPath = join(this.layers0Path, 'nodes', nodePath);
|
|
826
|
+
const slpkChildPath = join('nodes', nodePath);
|
|
827
|
+
await this._writeGeometries({
|
|
828
|
+
geometryBuffer,
|
|
829
|
+
compressedGeometry,
|
|
830
|
+
childPath,
|
|
831
|
+
slpkChildPath,
|
|
832
|
+
sourceId: sourceTile.id || '',
|
|
833
|
+
nodeId: parseInt(nodePath)
|
|
709
834
|
});
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
835
|
+
await this._writeShared({
|
|
836
|
+
sharedResources,
|
|
837
|
+
childPath,
|
|
838
|
+
slpkChildPath,
|
|
839
|
+
nodePath,
|
|
840
|
+
sourceId: sourceTile.id || '',
|
|
841
|
+
nodeId: parseInt(nodePath)
|
|
717
842
|
});
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
}
|
|
721
|
-
async _writeShared(sharedResources, childPath, slpkChildPath, nodePath, sourceId, nodeId) {
|
|
722
|
-
if (!sharedResources) {
|
|
723
|
-
return;
|
|
843
|
+
await this._writeTexture(texture, childPath, slpkChildPath, sourceTile.id || '', parseInt(nodePath));
|
|
844
|
+
await this._writeAttributes(attributes, childPath, slpkChildPath, sourceTile.id || '', parseInt(nodePath));
|
|
724
845
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
}
|
|
748
|
-
async _writeTexture(texture, childPath, slpkChildPath, sourceId, nodeId) {
|
|
749
|
-
if (texture) {
|
|
750
|
-
const format = this._getFormatByMimeType(texture === null || texture === void 0 ? void 0 : texture.mimeType);
|
|
751
|
-
const formats = [];
|
|
752
|
-
const textureData = texture.bufferView.data;
|
|
753
|
-
switch (format) {
|
|
754
|
-
case 'jpg':
|
|
755
|
-
case 'png':
|
|
756
|
-
{
|
|
757
|
-
formats.push({
|
|
758
|
-
name: '0',
|
|
759
|
-
format
|
|
846
|
+
/**
|
|
847
|
+
* Write non-compressed and compressed geometries in files
|
|
848
|
+
* @param geometryBuffer - Uint8Array with geometry attributes
|
|
849
|
+
* @param compressedGeometry - Uint8Array with compressed (draco) geometry
|
|
850
|
+
* @param childPath - a child path to write resources
|
|
851
|
+
* @param slpkChildPath - resource path inside *slpk file
|
|
852
|
+
* @param sourceId - source filename
|
|
853
|
+
* @param nodeId - nodeId of a converted node for the writing
|
|
854
|
+
*/
|
|
855
|
+
async _writeGeometries({ geometryBuffer, compressedGeometry, childPath, slpkChildPath, sourceId, nodeId }) {
|
|
856
|
+
if (!geometryBuffer) {
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.GEOMETRY, false);
|
|
860
|
+
if (this.options.slpk) {
|
|
861
|
+
const slpkGeometryPath = join(childPath, 'geometries');
|
|
862
|
+
await this.writeQueue.enqueue({
|
|
863
|
+
archiveKey: `${slpkChildPath}/geometries/0.bin.gz`,
|
|
864
|
+
sourceId,
|
|
865
|
+
outputId: nodeId,
|
|
866
|
+
resourceType: ResourceType.GEOMETRY,
|
|
867
|
+
writePromise: () => writeFileForSlpk(slpkGeometryPath, geometryBuffer, '0.bin')
|
|
760
868
|
});
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
const arrayToEncode = new Uint8Array(copyArrayBuffer);
|
|
770
|
-
const ktx2TextureData = encode({
|
|
771
|
-
...texture.image,
|
|
772
|
-
data: arrayToEncode
|
|
773
|
-
}, KTX2BasisWriterWorker, {
|
|
774
|
-
...KTX2BasisWriterWorker.options,
|
|
775
|
-
['ktx2-basis-writer']: {
|
|
776
|
-
workerUrl: './modules/textures/dist/ktx2-basis-writer-worker-node.js'
|
|
777
|
-
},
|
|
778
|
-
reuseWorkers: true,
|
|
779
|
-
_nodeWorkers: true,
|
|
780
|
-
useLocalLibraries: true
|
|
781
|
-
});
|
|
782
|
-
this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/ktx2`, false);
|
|
783
|
-
await this.writeTextureFile(ktx2TextureData, '1', 'ktx2', childPath, slpkChildPath, sourceId, nodeId);
|
|
784
|
-
}
|
|
785
|
-
break;
|
|
786
|
-
}
|
|
787
|
-
case 'ktx2':
|
|
788
|
-
{
|
|
789
|
-
formats.push({
|
|
790
|
-
name: '1',
|
|
791
|
-
format
|
|
869
|
+
}
|
|
870
|
+
else {
|
|
871
|
+
const geometryPath = join(childPath, 'geometries/0/');
|
|
872
|
+
await this.writeQueue.enqueue({
|
|
873
|
+
sourceId,
|
|
874
|
+
outputId: nodeId,
|
|
875
|
+
resourceType: ResourceType.GEOMETRY,
|
|
876
|
+
writePromise: () => writeFile(geometryPath, geometryBuffer, 'index.bin')
|
|
792
877
|
});
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
878
|
+
}
|
|
879
|
+
if (this.options.draco && compressedGeometry) {
|
|
880
|
+
this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.DRACO_GEOMETRY, false);
|
|
881
|
+
if (this.options.slpk) {
|
|
882
|
+
const slpkCompressedGeometryPath = join(childPath, 'geometries');
|
|
883
|
+
await this.writeQueue.enqueue({
|
|
884
|
+
archiveKey: `${slpkChildPath}/geometries/1.bin.gz`,
|
|
885
|
+
sourceId,
|
|
886
|
+
outputId: nodeId,
|
|
887
|
+
resourceType: ResourceType.DRACO_GEOMETRY,
|
|
888
|
+
writePromise: () => writeFileForSlpk(slpkCompressedGeometryPath, compressedGeometry, '1.bin')
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
const compressedGeometryPath = join(childPath, 'geometries/1/');
|
|
893
|
+
await this.writeQueue.enqueue({
|
|
894
|
+
sourceId,
|
|
895
|
+
outputId: nodeId,
|
|
896
|
+
resourceType: ResourceType.DRACO_GEOMETRY,
|
|
897
|
+
writePromise: () => writeFile(compressedGeometryPath, compressedGeometry, 'index.bin')
|
|
898
|
+
});
|
|
803
899
|
}
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
if (!this.layers0.textureSetDefinitions.length) {
|
|
807
|
-
this.layers0.textureSetDefinitions.push({
|
|
808
|
-
formats
|
|
809
|
-
});
|
|
810
|
-
this.layers0.textureSetDefinitions.push({
|
|
811
|
-
formats,
|
|
812
|
-
atlas: true
|
|
813
|
-
});
|
|
814
|
-
if (this.layers0.textureSetDefinitions) {
|
|
815
|
-
this.conversionDump.addTexturesDefinitions(this.layers0.textureSetDefinitions);
|
|
816
900
|
}
|
|
817
|
-
}
|
|
818
901
|
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
902
|
+
/**
|
|
903
|
+
* Write shared resources in a file
|
|
904
|
+
* @param sharedResources - shared resource data object
|
|
905
|
+
* @param childPath - a child path to write resources
|
|
906
|
+
* @param slpkChildPath - resource path inside *slpk file
|
|
907
|
+
* @param nodePath - a node path
|
|
908
|
+
* @param sourceId - source filename
|
|
909
|
+
* @param nodeId - nodeId of a converted node for the writing
|
|
910
|
+
*/
|
|
911
|
+
async _writeShared({ sharedResources, childPath, slpkChildPath, nodePath, sourceId, nodeId }) {
|
|
912
|
+
if (!sharedResources) {
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
sharedResources.nodePath = nodePath;
|
|
916
|
+
const sharedData = transform(sharedResources, sharedResourcesTemplate());
|
|
917
|
+
const sharedDataStr = JSON.stringify(sharedData);
|
|
918
|
+
this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.SHARED, false);
|
|
919
|
+
if (this.options.slpk) {
|
|
920
|
+
const slpkSharedPath = join(childPath, 'shared');
|
|
921
|
+
await this.writeQueue.enqueue({
|
|
922
|
+
archiveKey: `${slpkChildPath}/shared/sharedResource.json.gz`,
|
|
923
|
+
sourceId,
|
|
924
|
+
outputId: nodeId,
|
|
925
|
+
resourceType: ResourceType.SHARED,
|
|
926
|
+
writePromise: () => writeFileForSlpk(slpkSharedPath, sharedDataStr, 'sharedResource.json')
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
else {
|
|
930
|
+
const sharedPath = join(childPath, 'shared/');
|
|
931
|
+
await this.writeQueue.enqueue({
|
|
932
|
+
sourceId,
|
|
933
|
+
outputId: nodeId,
|
|
934
|
+
resourceType: ResourceType.SHARED,
|
|
935
|
+
writePromise: () => writeFile(sharedPath, sharedDataStr)
|
|
936
|
+
});
|
|
937
|
+
}
|
|
839
938
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
939
|
+
/**
|
|
940
|
+
* Generates textures based on texture mime type and fill in textureSetDefinitions data.
|
|
941
|
+
* @param texture - the texture image
|
|
942
|
+
* @param childPath - a child path to write resources
|
|
943
|
+
* @param slpkChildPath - the resource path inside *slpk file
|
|
944
|
+
* @param sourceId - source filename
|
|
945
|
+
* @param nodeId - nodeId of a converted node for the writing
|
|
946
|
+
*/
|
|
947
|
+
// eslint-disable-next-line max-statements
|
|
948
|
+
async _writeTexture(texture, childPath, slpkChildPath, sourceId, nodeId) {
|
|
949
|
+
if (texture) {
|
|
950
|
+
const format = this._getFormatByMimeType(texture?.mimeType);
|
|
951
|
+
const formats = [];
|
|
952
|
+
const textureData = texture.bufferView.data;
|
|
953
|
+
switch (format) {
|
|
954
|
+
case 'jpg':
|
|
955
|
+
case 'png': {
|
|
956
|
+
formats.push({ name: '0', format });
|
|
957
|
+
this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/${format}`, false);
|
|
958
|
+
await this.writeTextureFile({
|
|
959
|
+
textureData,
|
|
960
|
+
name: '0',
|
|
961
|
+
format,
|
|
962
|
+
childPath,
|
|
963
|
+
slpkChildPath,
|
|
964
|
+
sourceId,
|
|
965
|
+
nodeId
|
|
966
|
+
});
|
|
967
|
+
if (this.generateTextures) {
|
|
968
|
+
formats.push({ name: '1', format: 'ktx2' });
|
|
969
|
+
// For Node.js texture.image.data is type of Buffer
|
|
970
|
+
const copyArrayBuffer = texture.image.data.subarray();
|
|
971
|
+
const arrayToEncode = new Uint8Array(copyArrayBuffer);
|
|
972
|
+
const ktx2TextureData = encode({ ...texture.image, data: arrayToEncode },
|
|
973
|
+
// @ts-expect-error - Worker encoder typing is still WIP
|
|
974
|
+
KTX2BasisWriterWorker, {
|
|
975
|
+
...KTX2BasisWriterWorker.options,
|
|
976
|
+
['ktx2-basis-writer']: {
|
|
977
|
+
// We need to load local fs workers because nodejs can't load workers from the Internet
|
|
978
|
+
workerUrl: './modules/textures/dist/ktx2-basis-writer-worker-node.js'
|
|
979
|
+
},
|
|
980
|
+
reuseWorkers: true,
|
|
981
|
+
_nodeWorkers: true,
|
|
982
|
+
useLocalLibraries: true
|
|
983
|
+
});
|
|
984
|
+
this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/ktx2`, false);
|
|
985
|
+
await this.writeTextureFile({
|
|
986
|
+
textureData: ktx2TextureData,
|
|
987
|
+
name: '1',
|
|
988
|
+
format: 'ktx2',
|
|
989
|
+
childPath,
|
|
990
|
+
slpkChildPath,
|
|
991
|
+
sourceId,
|
|
992
|
+
nodeId
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
break;
|
|
996
|
+
}
|
|
997
|
+
case 'ktx2': {
|
|
998
|
+
formats.push({ name: '1', format });
|
|
999
|
+
this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/${format}`, false);
|
|
1000
|
+
await this.writeTextureFile({
|
|
1001
|
+
textureData,
|
|
1002
|
+
name: '1',
|
|
1003
|
+
format,
|
|
1004
|
+
childPath,
|
|
1005
|
+
slpkChildPath,
|
|
1006
|
+
sourceId,
|
|
1007
|
+
nodeId
|
|
1008
|
+
});
|
|
1009
|
+
if (this.generateTextures) {
|
|
1010
|
+
formats.push({ name: '0', format: 'jpg' });
|
|
1011
|
+
const decodedFromKTX2TextureData = encode(texture.image.data[0], ImageWriter);
|
|
1012
|
+
this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.TEXTURE}/jpg`, false);
|
|
1013
|
+
await this.writeTextureFile({
|
|
1014
|
+
textureData: decodedFromKTX2TextureData,
|
|
1015
|
+
name: '0',
|
|
1016
|
+
format: 'jpg',
|
|
1017
|
+
childPath,
|
|
1018
|
+
slpkChildPath,
|
|
1019
|
+
sourceId,
|
|
1020
|
+
nodeId
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
break;
|
|
1024
|
+
}
|
|
1025
|
+
default:
|
|
1026
|
+
}
|
|
1027
|
+
if (!this.layers0.textureSetDefinitions.length) {
|
|
1028
|
+
this.layers0.textureSetDefinitions.push({ formats });
|
|
1029
|
+
this.layers0.textureSetDefinitions.push({ formats, atlas: true });
|
|
1030
|
+
if (this.layers0.textureSetDefinitions) {
|
|
1031
|
+
this.conversionDump.addTexturesDefinitions(this.layers0.textureSetDefinitions);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Write the texture image in a file
|
|
1038
|
+
* @param textureData
|
|
1039
|
+
* @param name
|
|
1040
|
+
* @param format
|
|
1041
|
+
* @param childPath
|
|
1042
|
+
* @param slpkChildPath
|
|
1043
|
+
* @param sourceId
|
|
1044
|
+
* @param nodeId
|
|
1045
|
+
*/
|
|
1046
|
+
async writeTextureFile({ textureData, name, format, childPath, slpkChildPath, sourceId, nodeId }) {
|
|
853
1047
|
if (this.options.slpk) {
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
1048
|
+
const slpkTexturePath = join(childPath, 'textures');
|
|
1049
|
+
const compress = false;
|
|
1050
|
+
await this.writeQueue.enqueue({
|
|
1051
|
+
archiveKey: `${slpkChildPath}/textures/${name}.${format}`,
|
|
1052
|
+
sourceId,
|
|
1053
|
+
outputId: nodeId,
|
|
1054
|
+
resourceType: `${ResourceType.TEXTURE}/${format}`,
|
|
1055
|
+
writePromise: () => writeFileForSlpk(slpkTexturePath, textureData, `${name}.${format}`, compress)
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
else {
|
|
1059
|
+
const texturePath = join(childPath, `textures/${name}/`);
|
|
1060
|
+
await this.writeQueue.enqueue({
|
|
1061
|
+
sourceId,
|
|
1062
|
+
outputId: nodeId,
|
|
1063
|
+
resourceType: `${ResourceType.TEXTURE}/${format}`,
|
|
1064
|
+
writePromise: () => writeFile(texturePath, textureData, `index.${format}`)
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
872
1067
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
1068
|
+
/**
|
|
1069
|
+
* Write feature attributes in files
|
|
1070
|
+
* @param attributes - feature attributes
|
|
1071
|
+
* @param childPath - a child path to write resources
|
|
1072
|
+
* @param slpkChildPath - the resource path inside *slpk file
|
|
1073
|
+
* @param sourceId - source filename
|
|
1074
|
+
* @param nodeId - nodeId of a converted node for the writing
|
|
1075
|
+
*/
|
|
1076
|
+
async _writeAttributes(attributes = [], childPath, slpkChildPath, sourceId, nodeId) {
|
|
1077
|
+
if (attributes?.length && this.attributeMetadataInfo.attributeStorageInfo.length) {
|
|
1078
|
+
const minimumLength = attributes.length < this.attributeMetadataInfo.attributeStorageInfo.length
|
|
1079
|
+
? attributes.length
|
|
1080
|
+
: this.attributeMetadataInfo.attributeStorageInfo.length;
|
|
1081
|
+
for (let index = 0; index < minimumLength; index++) {
|
|
1082
|
+
const folderName = this.attributeMetadataInfo.attributeStorageInfo[index].key;
|
|
1083
|
+
const fileBuffer = new Uint8Array(attributes[index]);
|
|
1084
|
+
this.conversionDump.updateDoneStatus(sourceId, nodeId, `${ResourceType.ATTRIBUTES}/${folderName}`, false);
|
|
1085
|
+
if (this.options.slpk) {
|
|
1086
|
+
const slpkAttributesPath = join(childPath, 'attributes', folderName);
|
|
1087
|
+
await this.writeQueue.enqueue({
|
|
1088
|
+
archiveKey: `${slpkChildPath}/attributes/${folderName}.bin.gz`,
|
|
1089
|
+
sourceId,
|
|
1090
|
+
outputId: nodeId,
|
|
1091
|
+
resourceType: `${ResourceType.ATTRIBUTES}/${folderName}`,
|
|
1092
|
+
writePromise: () => writeFileForSlpk(slpkAttributesPath, fileBuffer, '0.bin')
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
else {
|
|
1096
|
+
const attributesPath = join(childPath, `attributes/${folderName}/0`);
|
|
1097
|
+
await this.writeQueue.enqueue({
|
|
1098
|
+
sourceId,
|
|
1099
|
+
outputId: nodeId,
|
|
1100
|
+
resourceType: `${ResourceType.ATTRIBUTES}/${folderName}`,
|
|
1101
|
+
writePromise: () => writeFile(attributesPath, fileBuffer, 'index.bin')
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
884
1106
|
}
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
1107
|
+
/**
|
|
1108
|
+
* Return file format by its MIME type
|
|
1109
|
+
* @param mimeType - feature attributes
|
|
1110
|
+
*/
|
|
1111
|
+
_getFormatByMimeType(mimeType) {
|
|
1112
|
+
switch (mimeType) {
|
|
1113
|
+
case 'image/jpeg':
|
|
1114
|
+
return 'jpg';
|
|
1115
|
+
case 'image/png':
|
|
1116
|
+
return 'png';
|
|
1117
|
+
case 'image/ktx2':
|
|
1118
|
+
return 'ktx2';
|
|
1119
|
+
default:
|
|
1120
|
+
return 'jpg';
|
|
1121
|
+
}
|
|
890
1122
|
}
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1123
|
+
/**
|
|
1124
|
+
* Find or create material in materialDefinitions array
|
|
1125
|
+
* @param material - end-to-end index of the node
|
|
1126
|
+
* @return material id
|
|
1127
|
+
*/
|
|
1128
|
+
_findOrCreateMaterial(material) {
|
|
1129
|
+
const hash = md5(JSON.stringify(material));
|
|
1130
|
+
if (this.materialMap.has(hash)) {
|
|
1131
|
+
return this.materialMap.get(hash) || 0;
|
|
1132
|
+
}
|
|
1133
|
+
const newMaterialId = this.materialDefinitions.push(material) - 1;
|
|
1134
|
+
this.materialMap.set(hash, newMaterialId);
|
|
1135
|
+
return newMaterialId;
|
|
903
1136
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1137
|
+
/**
|
|
1138
|
+
* Get unique geometry configuration index
|
|
1139
|
+
* In the end of conversion configurations will be transformed to geometryDefinitions array
|
|
1140
|
+
* @param hasTexture
|
|
1141
|
+
* @param hasUvRegions
|
|
1142
|
+
* @returns
|
|
1143
|
+
*/
|
|
1144
|
+
findOrCreateGeometryDefinition(hasTexture, hasUvRegions) {
|
|
1145
|
+
const geometryConfig = { hasTexture, hasUvRegions };
|
|
1146
|
+
const hash = md5(JSON.stringify(geometryConfig));
|
|
1147
|
+
if (this.geometryMap.has(hash)) {
|
|
1148
|
+
return this.geometryMap.get(hash) || 0;
|
|
1149
|
+
}
|
|
1150
|
+
const newGeometryId = this.geometryConfigs.push(geometryConfig) - 1;
|
|
1151
|
+
this.geometryMap.set(hash, newGeometryId);
|
|
1152
|
+
return newGeometryId;
|
|
916
1153
|
}
|
|
917
|
-
|
|
918
|
-
|
|
1154
|
+
/**
|
|
1155
|
+
* Creates attribute storage info based on either extension schema or property table.
|
|
1156
|
+
* @param tileContent - content of the source tile
|
|
1157
|
+
* @param propertyTable - feature properties from EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA
|
|
1158
|
+
*/
|
|
1159
|
+
createAttributeStorageInfo(tileContent, propertyTable) {
|
|
1160
|
+
/*
|
|
1161
|
+
In case the tileset doesn't have either EXT_structural_metadata or EXT_feature_metadata
|
|
1162
|
+
that can be a source of attribute information so metadataClass is not specified
|
|
1163
|
+
we will collect attribute information for node attributes from the property table
|
|
1164
|
+
taken from each tile.
|
|
1165
|
+
*/
|
|
1166
|
+
let attributeTypesMap = null;
|
|
1167
|
+
if (this.options.metadataClass) {
|
|
1168
|
+
if (!this.attributeMetadataInfo.attributeStorageInfo.length && tileContent?.gltf) {
|
|
1169
|
+
attributeTypesMap = getAttributeTypesMapFromSchema(tileContent.gltf, this.options.metadataClass);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
else if (propertyTable) {
|
|
1173
|
+
attributeTypesMap = getAttributeTypesMapFromPropertyTable(propertyTable);
|
|
1174
|
+
}
|
|
1175
|
+
if (attributeTypesMap) {
|
|
1176
|
+
// Add new storage attributes, fields and create popupInfo
|
|
1177
|
+
this.attributeMetadataInfo.addMetadataInfo(attributeTypesMap);
|
|
1178
|
+
}
|
|
919
1179
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
if (!this.Loader.preload) {
|
|
940
|
-
return {};
|
|
1180
|
+
/**
|
|
1181
|
+
* Print statistics in the end of conversion
|
|
1182
|
+
* @param params - output files data
|
|
1183
|
+
*/
|
|
1184
|
+
async _finishConversion(params) {
|
|
1185
|
+
const { tilesCount, tilesWithAddRefineCount } = this.refinementCounter;
|
|
1186
|
+
const addRefinementPercentage = tilesWithAddRefineCount
|
|
1187
|
+
? (tilesWithAddRefineCount / tilesCount) * 100
|
|
1188
|
+
: 0;
|
|
1189
|
+
const filesSize = await calculateFilesSize(params);
|
|
1190
|
+
const diff = process.hrtime(this.conversionStartTime);
|
|
1191
|
+
const conversionTime = timeConverter(diff);
|
|
1192
|
+
console.log('------------------------------------------------'); // eslint-disable-line no-undef, no-console
|
|
1193
|
+
console.log(`Finishing conversion of ${_3D_TILES}`); // eslint-disable-line no-undef, no-console
|
|
1194
|
+
console.log(`Total conversion time: ${conversionTime}`); // eslint-disable-line no-undef, no-console
|
|
1195
|
+
console.log('Vertex count: ', this.vertexCounter); // eslint-disable-line no-undef, no-console
|
|
1196
|
+
console.log('File(s) size: ', filesSize, ' bytes'); // eslint-disable-line no-undef, no-console
|
|
1197
|
+
console.log('Percentage of tiles with "ADD" refinement type:', addRefinementPercentage, '%'); // eslint-disable-line no-undef, no-console
|
|
1198
|
+
console.log('------------------------------------------------'); // eslint-disable-line no-undef, no-console
|
|
941
1199
|
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
const diff = process.hrtime(this.refreshTokenTime);
|
|
956
|
-
if (diff[0] < REFRESH_TOKEN_TIMEOUT) {
|
|
957
|
-
return;
|
|
1200
|
+
/**
|
|
1201
|
+
* Fetch preload options for ION tileset
|
|
1202
|
+
*/
|
|
1203
|
+
async _fetchPreloadOptions() {
|
|
1204
|
+
if (!this.Loader.preload) {
|
|
1205
|
+
return {};
|
|
1206
|
+
}
|
|
1207
|
+
const options = {
|
|
1208
|
+
'cesium-ion': { accessToken: this.options.token || ION_DEFAULT_TOKEN }
|
|
1209
|
+
};
|
|
1210
|
+
const preloadOptions = await this.Loader.preload(this.options.inputUrl, options);
|
|
1211
|
+
this.refreshTokenTime = process.hrtime();
|
|
1212
|
+
return { ...options, ...preloadOptions };
|
|
958
1213
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1214
|
+
/**
|
|
1215
|
+
* Update options of source tileset
|
|
1216
|
+
*/
|
|
1217
|
+
async _updateTilesetOptions() {
|
|
1218
|
+
const diff = process.hrtime(this.refreshTokenTime);
|
|
1219
|
+
if (diff[0] < REFRESH_TOKEN_TIMEOUT) {
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
this.refreshTokenTime = process.hrtime();
|
|
1223
|
+
const preloadOptions = await this._fetchPreloadOptions();
|
|
1224
|
+
if (preloadOptions.headers) {
|
|
1225
|
+
this.loadOptions.fetch = {
|
|
1226
|
+
...this.loadOptions.fetch,
|
|
1227
|
+
headers: preloadOptions.headers
|
|
1228
|
+
};
|
|
1229
|
+
console.log('Authorization Bearer token has been updated'); // eslint-disable-line no-undef, no-console
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
/** Do calculations of all tiles and tiles with "ADD" type of refinement.
|
|
1233
|
+
* @param tile
|
|
1234
|
+
*/
|
|
1235
|
+
_checkAddRefinementTypeForTile(tile) {
|
|
1236
|
+
const ADD_TILE_REFINEMENT = TILE_REFINEMENT.ADD;
|
|
1237
|
+
if (tile.refine === ADD_TILE_REFINEMENT) {
|
|
1238
|
+
this.refinementCounter.tilesWithAddRefineCount += 1;
|
|
1239
|
+
console.warn('This tile uses "ADD" type of refinement'); // eslint-disable-line
|
|
1240
|
+
}
|
|
1241
|
+
this.refinementCounter.tilesCount += 1;
|
|
967
1242
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1243
|
+
/**
|
|
1244
|
+
* Check if the tile's content format is supported by the converter
|
|
1245
|
+
* @param sourceTile
|
|
1246
|
+
* @returns
|
|
1247
|
+
*/
|
|
1248
|
+
isContentSupported(sourceTile) {
|
|
1249
|
+
return ['b3dm', 'glTF', 'scenegraph'].includes(sourceTile.type || '');
|
|
974
1250
|
}
|
|
975
|
-
this.refinementCounter.tilesCount += 1;
|
|
976
|
-
}
|
|
977
|
-
isContentSupported(sourceTile) {
|
|
978
|
-
return ['b3dm', 'glTF', 'scenegraph'].includes(sourceTile.type || '');
|
|
979
|
-
}
|
|
980
1251
|
}
|
|
981
|
-
//# sourceMappingURL=i3s-converter.js.map
|