@loaders.gl/tile-converter 3.1.0-beta.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/dist/bundle.js +1455 -1296
  2. package/dist/converter.min.js +292 -0
  3. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js +429 -189
  4. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  5. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js +306 -209
  6. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  7. package/dist/es5/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +8 -4
  8. package/dist/es5/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js.map +1 -1
  9. package/dist/es5/3d-tiles-converter/helpers/texture-atlas.js +13 -13
  10. package/dist/es5/3d-tiles-converter/helpers/texture-atlas.js.map +1 -1
  11. package/dist/es5/3d-tiles-converter/json-templates/tileset.js +51 -32
  12. package/dist/es5/3d-tiles-converter/json-templates/tileset.js.map +1 -1
  13. package/dist/es5/bundle.js +1 -1
  14. package/dist/es5/bundle.js.map +1 -1
  15. package/dist/es5/deps-installer/deps-installer.js +61 -17
  16. package/dist/es5/deps-installer/deps-installer.js.map +1 -1
  17. package/dist/es5/i3s-converter/helpers/coordinate-converter.js +55 -16
  18. package/dist/es5/i3s-converter/helpers/coordinate-converter.js.map +1 -1
  19. package/dist/es5/i3s-converter/helpers/create-scene-server-path.js +33 -9
  20. package/dist/es5/i3s-converter/helpers/create-scene-server-path.js.map +1 -1
  21. package/dist/es5/i3s-converter/helpers/geometry-attributes.js +103 -93
  22. package/dist/es5/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  23. package/dist/es5/i3s-converter/helpers/geometry-converter.d.ts +5 -1
  24. package/dist/es5/i3s-converter/helpers/geometry-converter.js +546 -351
  25. package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
  26. package/dist/es5/i3s-converter/helpers/node-debug.js +27 -31
  27. package/dist/es5/i3s-converter/helpers/node-debug.js.map +1 -1
  28. package/dist/es5/i3s-converter/helpers/node-pages.js +209 -101
  29. package/dist/es5/i3s-converter/helpers/node-pages.js.map +1 -1
  30. package/dist/es5/i3s-converter/i3s-converter.js +1645 -700
  31. package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
  32. package/dist/es5/i3s-converter/json-templates/layers.js +213 -177
  33. package/dist/es5/i3s-converter/json-templates/layers.js.map +1 -1
  34. package/dist/es5/i3s-converter/json-templates/metadata.js +24 -20
  35. package/dist/es5/i3s-converter/json-templates/metadata.js.map +1 -1
  36. package/dist/es5/i3s-converter/json-templates/node.js +92 -74
  37. package/dist/es5/i3s-converter/json-templates/node.js.map +1 -1
  38. package/dist/es5/i3s-converter/json-templates/scene-server.js +34 -28
  39. package/dist/es5/i3s-converter/json-templates/scene-server.js.map +1 -1
  40. package/dist/es5/i3s-converter/json-templates/shared-resources.js +162 -107
  41. package/dist/es5/i3s-converter/json-templates/shared-resources.js.map +1 -1
  42. package/dist/es5/i3s-converter/json-templates/store.js +4 -2
  43. package/dist/es5/i3s-converter/json-templates/store.js.map +1 -1
  44. package/dist/es5/i3s-converter/types.js +2 -0
  45. package/dist/es5/i3s-converter/types.js.map +1 -0
  46. package/dist/es5/i3s-server/app.js +6 -6
  47. package/dist/es5/i3s-server/app.js.map +1 -1
  48. package/dist/es5/i3s-server/controllers/index-controller.js +60 -20
  49. package/dist/es5/i3s-server/controllers/index-controller.js.map +1 -1
  50. package/dist/es5/i3s-server/routes/index.js +41 -14
  51. package/dist/es5/i3s-server/routes/index.js.map +1 -1
  52. package/dist/es5/index.js +4 -4
  53. package/dist/es5/lib/utils/{compress-utils.d.ts → compress-util.d.ts} +0 -0
  54. package/dist/es5/lib/utils/compress-util.js +345 -123
  55. package/dist/es5/lib/utils/compress-util.js.map +1 -1
  56. package/dist/es5/lib/utils/file-utils.js +98 -20
  57. package/dist/es5/lib/utils/file-utils.js.map +1 -1
  58. package/dist/es5/lib/utils/lod-conversion-utils.js +9 -9
  59. package/dist/es5/lib/utils/lod-conversion-utils.js.map +1 -1
  60. package/dist/es5/lib/utils/statistic-utills.js +152 -41
  61. package/dist/es5/lib/utils/statistic-utills.js.map +1 -1
  62. package/dist/es5/pgm-loader.js +31 -4
  63. package/dist/es5/pgm-loader.js.map +1 -1
  64. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js +7 -6
  65. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  66. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js +7 -0
  67. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  68. package/dist/esm/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js.map +1 -1
  69. package/dist/esm/3d-tiles-converter/helpers/texture-atlas.js +1 -1
  70. package/dist/esm/3d-tiles-converter/helpers/texture-atlas.js.map +1 -1
  71. package/dist/esm/3d-tiles-converter/json-templates/tileset.js +12 -9
  72. package/dist/esm/3d-tiles-converter/json-templates/tileset.js.map +1 -1
  73. package/dist/esm/deps-installer/deps-installer.js +2 -6
  74. package/dist/esm/deps-installer/deps-installer.js.map +1 -1
  75. package/dist/esm/i3s-converter/helpers/coordinate-converter.js +35 -3
  76. package/dist/esm/i3s-converter/helpers/coordinate-converter.js.map +1 -1
  77. package/dist/esm/i3s-converter/helpers/create-scene-server-path.js +2 -2
  78. package/dist/esm/i3s-converter/helpers/create-scene-server-path.js.map +1 -1
  79. package/dist/esm/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  80. package/dist/esm/i3s-converter/helpers/geometry-converter.d.ts +5 -1
  81. package/dist/esm/i3s-converter/helpers/geometry-converter.js +52 -34
  82. package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
  83. package/dist/esm/i3s-converter/helpers/node-debug.js +2 -4
  84. package/dist/esm/i3s-converter/helpers/node-debug.js.map +1 -1
  85. package/dist/esm/i3s-converter/helpers/node-pages.js +15 -4
  86. package/dist/esm/i3s-converter/helpers/node-pages.js.map +1 -1
  87. package/dist/esm/i3s-converter/i3s-converter.js +147 -62
  88. package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
  89. package/dist/esm/i3s-converter/json-templates/layers.js +37 -27
  90. package/dist/esm/i3s-converter/json-templates/layers.js.map +1 -1
  91. package/dist/esm/i3s-converter/json-templates/metadata.js +2 -2
  92. package/dist/esm/i3s-converter/json-templates/metadata.js.map +1 -1
  93. package/dist/esm/i3s-converter/json-templates/node.js +16 -12
  94. package/dist/esm/i3s-converter/json-templates/node.js.map +1 -1
  95. package/dist/esm/i3s-converter/json-templates/scene-server.js +2 -2
  96. package/dist/esm/i3s-converter/json-templates/scene-server.js.map +1 -1
  97. package/dist/esm/i3s-converter/json-templates/shared-resources.js +19 -14
  98. package/dist/esm/i3s-converter/json-templates/shared-resources.js.map +1 -1
  99. package/dist/esm/i3s-converter/json-templates/store.js.map +1 -1
  100. package/dist/esm/i3s-converter/types.js +2 -0
  101. package/dist/esm/i3s-converter/types.js.map +1 -0
  102. package/dist/esm/lib/utils/{compress-utils.d.ts → compress-util.d.ts} +0 -0
  103. package/dist/esm/pgm-loader.js +3 -3
  104. package/dist/esm/pgm-loader.js.map +1 -1
  105. package/package.json +16 -14
  106. package/src/3d-tiles-converter/3d-tiles-converter.ts +21 -20
  107. package/src/3d-tiles-converter/helpers/{b3dm-converter.js → b3dm-converter.ts} +19 -2
  108. package/src/3d-tiles-converter/helpers/{i3s-obb-to-3d-tiles-obb.js → i3s-obb-to-3d-tiles-obb.ts} +16 -1
  109. package/src/3d-tiles-converter/helpers/texture-atlas.ts +4 -4
  110. package/src/3d-tiles-converter/json-templates/{tileset.js → tileset.ts} +9 -9
  111. package/src/deps-installer/deps-installer.js +2 -2
  112. package/src/i3s-converter/helpers/coordinate-converter.ts +62 -9
  113. package/src/i3s-converter/helpers/{create-scene-server-path.js → create-scene-server-path.ts} +2 -2
  114. package/src/i3s-converter/helpers/{geometry-attributes.js → geometry-attributes.ts} +4 -4
  115. package/src/i3s-converter/helpers/geometry-converter.d.ts +5 -1
  116. package/src/i3s-converter/helpers/geometry-converter.js +68 -26
  117. package/src/i3s-converter/helpers/{node-debug.js → node-debug.ts} +3 -2
  118. package/src/i3s-converter/helpers/{node-pages.js → node-pages.ts} +41 -26
  119. package/src/i3s-converter/i3s-converter.ts +204 -133
  120. package/src/i3s-converter/json-templates/{layers.js → layers.ts} +29 -27
  121. package/src/i3s-converter/json-templates/{metadata.js → metadata.ts} +2 -2
  122. package/src/i3s-converter/json-templates/{node.js → node.ts} +12 -12
  123. package/src/i3s-converter/json-templates/{scene-server.js → scene-server.ts} +2 -2
  124. package/src/i3s-converter/json-templates/{shared-resources.js → shared-resources.ts} +14 -14
  125. package/src/i3s-converter/json-templates/{store.js → store.ts} +0 -0
  126. package/src/i3s-converter/types.ts +14 -0
  127. package/src/lib/utils/{compress-utils.d.ts → compress-util.d.ts} +0 -0
  128. package/src/pgm-loader.ts +2 -2
  129. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.d.ts +0 -23
  130. package/dist/es5/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.d.ts +0 -16
  131. package/dist/es5/i3s-converter/helpers/node-pages.d.ts +0 -144
  132. package/dist/es5/lib/geoid-height-model.d.ts +0 -41
  133. package/dist/es5/lib/geoid-height-model.js +0 -149
  134. package/dist/es5/lib/geoid-height-model.js.map +0 -1
  135. package/dist/es5/lib/pgm-parser.d.ts +0 -14
  136. package/dist/es5/lib/pgm-parser.js +0 -192
  137. package/dist/es5/lib/pgm-parser.js.map +0 -1
  138. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.d.ts +0 -23
  139. package/dist/esm/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.d.ts +0 -16
  140. package/dist/esm/i3s-converter/helpers/node-pages.d.ts +0 -144
  141. package/dist/esm/lib/geoid-height-model.d.ts +0 -41
  142. package/dist/esm/lib/geoid-height-model.js +0 -140
  143. package/dist/esm/lib/geoid-height-model.js.map +0 -1
  144. package/dist/esm/lib/pgm-parser.d.ts +0 -14
  145. package/dist/esm/lib/pgm-parser.js +0 -183
  146. package/dist/esm/lib/pgm-parser.js.map +0 -1
  147. package/src/3d-tiles-converter/helpers/b3dm-converter.d.ts +0 -23
  148. package/src/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.d.ts +0 -16
  149. package/src/i3s-converter/helpers/node-pages.d.ts +0 -144
  150. package/src/lib/geoid-height-model.d.ts +0 -41
  151. package/src/lib/geoid-height-model.js +0 -239
  152. package/src/lib/pgm-parser.d.ts +0 -14
  153. package/src/lib/pgm-parser.js +0 -179
@@ -1,5 +1,4 @@
1
- import type {Tileset3DProps} from '@loaders.gl/tiles';
2
- import type {GLTFMaterial} from '@loaders.gl/gltf';
1
+ import type {Tile3D, Tileset3DProps} from '@loaders.gl/tiles';
3
2
  import type {BatchTableJson, B3DMContent} from '@loaders.gl/3d-tiles';
4
3
 
5
4
  import type {
@@ -8,20 +7,20 @@ import type {
8
7
  BoundingVolumes,
9
8
  Node3DIndexDocument,
10
9
  NodeReference,
11
- I3SGeometry,
12
10
  MaxScreenThresholdSQ,
13
11
  NodeInPage,
14
12
  LodSelection,
15
13
  SharedResources,
16
- TextureImage,
17
14
  Attribute,
18
15
  ESRIField,
19
16
  Field,
20
- PopupInfo
17
+ PopupInfo,
18
+ FieldInfo
21
19
  } from '@loaders.gl/i3s';
22
20
  import {load, encode} from '@loaders.gl/core';
23
21
  import {Tileset3D} from '@loaders.gl/tiles';
24
22
  import {CesiumIonLoader, Tiles3DLoader} from '@loaders.gl/3d-tiles';
23
+ import {Geoid} from '@math.gl/geoid';
25
24
  import {join} from 'path';
26
25
  import {v4 as uuidv4} from 'uuid';
27
26
  import process from 'process';
@@ -47,12 +46,15 @@ import {PGMLoader} from '../pgm-loader';
47
46
 
48
47
  import {LAYERS as layersTemplate} from './json-templates/layers';
49
48
  import {NODE as nodeTemplate} from './json-templates/node';
50
- import {SHARED_RESOURCES_TEMPLATE} from './json-templates/shared-resources';
49
+ import {SHARED_RESOURCES as sharedResourcesTemplate} from './json-templates/shared-resources';
51
50
  import {validateNodeBoundingVolumes} from './helpers/node-debug';
52
- import {GeoidHeightModel} from '../lib/geoid-height-model';
53
51
  import TileHeader from '@loaders.gl/tiles/src/tileset/tile-3d';
54
52
  import {KTX2BasisUniversalTextureWriter} from '@loaders.gl/textures';
55
53
  import {LoaderWithParser} from '@loaders.gl/loader-utils';
54
+ import {I3SMaterialDefinition, TextureSetDefinitionFormats} from '@loaders.gl/i3s/src/types';
55
+ import {ImageWriter} from '@loaders.gl/images';
56
+ import {GLTFImagePostprocessed} from '@loaders.gl/gltf';
57
+ import {I3SConvertedResources} from './types';
56
58
 
57
59
  const ION_DEFAULT_TOKEN =
58
60
  process.env.IonToken || // eslint-disable-line
@@ -77,21 +79,23 @@ export default class I3SConverter {
77
79
  options: any;
78
80
  layers0Path: string;
79
81
  materialMap: Map<any, any>;
80
- materialDefinitions: GLTFMaterial[];
82
+ materialDefinitions: I3SMaterialDefinition[];
81
83
  vertexCounter: number;
82
- layers0: SceneLayer3D;
84
+ layers0: SceneLayer3D | null;
83
85
  featuresHashArray: string[];
84
86
  refinementCounter: {
85
87
  tilesCount: number;
86
88
  tilesWithAddRefineCount: number;
87
89
  };
88
90
  validate: boolean;
89
- boundingVolumeWarnings?: string[];
90
- conversionStartTime: [number, number];
91
- refreshTokenTime: [number, number];
92
- sourceTileset: Tileset3D | null;
93
- geoidHeightModel: GeoidHeightModel | null;
91
+ boundingVolumeWarnings?: string[] = [];
92
+ conversionStartTime: [number, number] = [0, 0];
93
+ refreshTokenTime: [number, number] = [0, 0];
94
+ sourceTileset: Tileset3D | null = null;
95
+ geoidHeightModel: Geoid | null = null;
94
96
  Loader: LoaderWithParser = Tiles3DLoader;
97
+ generateTextures: boolean;
98
+ generateBoundingVolumes: boolean;
95
99
 
96
100
  constructor() {
97
101
  this.nodePages = new NodePages(writeFile, HARDCODED_NODES_PER_PAGE);
@@ -108,7 +112,8 @@ export default class I3SConverter {
108
112
  tilesWithAddRefineCount: 0
109
113
  };
110
114
  this.validate = false;
111
- this.boundingVolumeWarnings = null;
115
+ this.generateTextures = false;
116
+ this.generateBoundingVolumes = false;
112
117
  }
113
118
 
114
119
  /**
@@ -130,12 +135,16 @@ export default class I3SConverter {
130
135
  outputPath: string;
131
136
  tilesetName: string;
132
137
  sevenZipExe: string;
133
- egmFilePath?: string;
138
+ egmFilePath: string;
134
139
  maxDepth?: number;
135
140
  slpk?: boolean;
136
141
  token?: string;
137
142
  draco?: boolean;
138
143
  validate?: boolean;
144
+ generateTextures?: boolean;
145
+ generateBoundingVolumes?: boolean;
146
+ /** @deprecated */
147
+ inputType?: string;
139
148
  }): Promise<any> {
140
149
  this.conversionStartTime = process.hrtime();
141
150
  const {
@@ -148,11 +157,15 @@ export default class I3SConverter {
148
157
  draco,
149
158
  sevenZipExe,
150
159
  maxDepth,
151
- token
160
+ token,
161
+ generateTextures,
162
+ generateBoundingVolumes
152
163
  } = options;
153
164
  this.options = {maxDepth, slpk, sevenZipExe, egmFilePath, draco, token, inputUrl};
154
- this.validate = validate;
165
+ this.validate = Boolean(validate);
155
166
  this.Loader = inputUrl.indexOf(CESIUM_DATASET_PREFIX) !== -1 ? CesiumIonLoader : Tiles3DLoader;
167
+ this.generateTextures = Boolean(generateTextures);
168
+ this.generateBoundingVolumes = Boolean(generateBoundingVolumes);
156
169
 
157
170
  console.log('Loading egm file...'); // eslint-disable-line
158
171
  this.geoidHeightModel = await load(egmFilePath, PGMLoader);
@@ -163,9 +176,9 @@ export default class I3SConverter {
163
176
  }
164
177
 
165
178
  const preloadOptions = await this._fetchPreloadOptions();
166
- const tilesetOptions: Tileset3DProps = {loadOptions: {}};
179
+ const tilesetOptions: Tileset3DProps = {loadOptions: {basis: {format: 'rgba32'}}};
167
180
  if (preloadOptions.headers) {
168
- tilesetOptions.loadOptions.fetch = {headers: preloadOptions.headers};
181
+ tilesetOptions.loadOptions!.fetch = {headers: preloadOptions.headers};
169
182
  }
170
183
  Object.assign(tilesetOptions, preloadOptions);
171
184
  const sourceTilesetJson = await load(inputUrl, this.Loader, tilesetOptions.loadOptions);
@@ -173,7 +186,7 @@ export default class I3SConverter {
173
186
  this.sourceTileset = new Tileset3D(sourceTilesetJson, tilesetOptions);
174
187
 
175
188
  await this._createAndSaveTileset(outputPath, tilesetName);
176
- await this._finishConversion({slpk, outputPath, tilesetName});
189
+ await this._finishConversion({slpk: Boolean(slpk), outputPath, tilesetName});
177
190
  return sourceTilesetJson;
178
191
  }
179
192
 
@@ -198,9 +211,10 @@ export default class I3SConverter {
198
211
  this.materialDefinitions = [];
199
212
  this.materialMap = new Map();
200
213
 
201
- const sourceRootTile = this.sourceTileset.root;
202
- const boundingVolumes = createBoundingVolumes(sourceRootTile, this.geoidHeightModel);
214
+ const sourceRootTile: TileHeader = this.sourceTileset!.root!;
215
+ const boundingVolumes = createBoundingVolumes(sourceRootTile, this.geoidHeightModel!);
203
216
  const parentId = this.nodePages.push({
217
+ index: 0,
204
218
  lodThreshold: 0,
205
219
  obb: boundingVolumes.obb,
206
220
  children: []
@@ -211,7 +225,7 @@ export default class I3SConverter {
211
225
 
212
226
  await this._convertNodesTree(root0, sourceRootTile, parentId, boundingVolumes);
213
227
 
214
- this.layers0.materialDefinitions = this.materialDefinitions;
228
+ this.layers0!.materialDefinitions = this.materialDefinitions;
215
229
  await this._writeLayers0();
216
230
  createSceneServerPath(tilesetName, this.layers0, tilesetPath);
217
231
  await this._writeNodeIndexDocument(root0, 'root', join(this.layers0Path, 'nodes', 'root'));
@@ -240,7 +254,7 @@ export default class I3SConverter {
240
254
  compressGeometry: this.options.draco
241
255
  };
242
256
 
243
- this.layers0 = transform(layers0data, layersTemplate);
257
+ this.layers0 = transform(layers0data, layersTemplate());
244
258
  }
245
259
 
246
260
  /**
@@ -266,7 +280,7 @@ export default class I3SConverter {
266
280
  ...boundingVolumes,
267
281
  children: []
268
282
  };
269
- return transform(root0data, nodeTemplate);
283
+ return transform(root0data, nodeTemplate());
270
284
  }
271
285
 
272
286
  /**
@@ -282,15 +296,16 @@ export default class I3SConverter {
282
296
  parentId: number,
283
297
  boundingVolumes: BoundingVolumes
284
298
  ): Promise<void> {
285
- await this.sourceTileset._loadTile(sourceRootTile);
286
- if (sourceRootTile.content && sourceRootTile.content.type === 'b3dm') {
299
+ await this.sourceTileset!._loadTile(sourceRootTile);
300
+ if (this.isContentSupported(sourceRootTile)) {
301
+ root0.children = root0.children || [];
287
302
  root0.children.push({
288
303
  id: '1',
289
304
  href: './1',
290
305
  ...boundingVolumes
291
306
  });
292
307
  const [child] = await this._createNode(root0, sourceRootTile, parentId, 0);
293
- const childPath = join(this.layers0Path, 'nodes', child.path);
308
+ const childPath = join(this.layers0Path, 'nodes', child.path!);
294
309
 
295
310
  if (this.options.slpk) {
296
311
  this.fileMap['nodes/1/3dNodeIndexDocument.json.gz'] = await writeFileForSlpk(
@@ -359,6 +374,7 @@ export default class I3SConverter {
359
374
  slpkFileName,
360
375
  0,
361
376
  '.',
377
+ // @ts-expect-error
362
378
  this.options.sevenZipExe
363
379
  );
364
380
 
@@ -429,7 +445,7 @@ export default class I3SConverter {
429
445
  }
430
446
  for (const sourceTile of sourceTiles) {
431
447
  if (sourceTile.type === 'json') {
432
- await this.sourceTileset._loadTile(sourceTile);
448
+ await this.sourceTileset!._loadTile(sourceTile);
433
449
  await this._addChildren({
434
450
  parentNode,
435
451
  sourceTiles: sourceTile.children,
@@ -439,13 +455,14 @@ export default class I3SConverter {
439
455
  });
440
456
  await sourceTile.unloadContent();
441
457
  } else {
442
- const boundingVolumes = createBoundingVolumes(sourceTile, this.geoidHeightModel);
443
458
  const children = await this._createNode(parentNode, sourceTile, parentId, level);
459
+ parentNode.children = parentNode.children || [];
444
460
  for (const child of children) {
445
461
  parentNode.children.push({
446
462
  id: child.id,
447
463
  href: `../${child.path}`,
448
- ...boundingVolumes
464
+ obb: child.obb,
465
+ mbs: child.mbs
449
466
  });
450
467
  childNodes.push(child);
451
468
  }
@@ -466,19 +483,21 @@ export default class I3SConverter {
466
483
  childNodes: Node3DIndexDocument[]
467
484
  ): Promise<void> {
468
485
  for (const node of childNodes) {
469
- const childPath = join(this.layers0Path, 'nodes', node.path);
486
+ const childPath = join(this.layers0Path, 'nodes', node.path!);
470
487
  const nodePath = node.path;
471
488
  delete node.path;
472
489
 
473
490
  // Don't do large amount of "neightbors" to avoid big memory consumption
474
- if (parentNode.children.length < 1000) {
475
- for (const neighbor of parentNode.children) {
491
+ if (Number(parentNode?.children?.length) < 1000) {
492
+ for (const neighbor of parentNode.children || []) {
476
493
  // eslint-disable-next-line max-depth
477
494
  if (node.id === neighbor.id) {
478
495
  continue; // eslint-disable-line
479
496
  }
480
497
 
481
- node.neighbors.push({...neighbor});
498
+ if (node.neighbors) {
499
+ node.neighbors.push({...neighbor});
500
+ }
482
501
  }
483
502
  } else {
484
503
  // eslint-disable-next-line no-console, no-undef
@@ -487,7 +506,7 @@ export default class I3SConverter {
487
506
  );
488
507
  delete node.neighbors;
489
508
  }
490
- await this._writeNodeIndexDocument(node, nodePath, childPath);
509
+ await this._writeNodeIndexDocument(node, nodePath!, childPath);
491
510
  node.neighbors = [];
492
511
  }
493
512
  }
@@ -510,13 +529,9 @@ export default class I3SConverter {
510
529
  }
511
530
 
512
531
  await this._updateTilesetOptions();
513
- await this.sourceTileset._loadTile(sourceTile);
514
- const boundingVolumes = createBoundingVolumes(sourceTile, this.geoidHeightModel);
532
+ await this.sourceTileset!._loadTile(sourceTile);
515
533
 
516
- const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);
517
- const maxScreenThresholdSQ = lodSelection.find(
518
- (val) => val.metricType === 'maxScreenThresholdSQ'
519
- ) || {maxError: 0};
534
+ let boundingVolumes = createBoundingVolumes(sourceTile, this.geoidHeightModel!);
520
535
 
521
536
  const batchTable = sourceTile?.content?.batchTableJson;
522
537
 
@@ -526,7 +541,8 @@ export default class I3SConverter {
526
541
 
527
542
  const resourcesData = await this._convertResources(sourceTile);
528
543
 
529
- const nodes = [];
544
+ const nodes: Node3DIndexDocument[] = [];
545
+ const nodesInPage: NodeInPage[] = [];
530
546
  const emptyResources = {
531
547
  geometry: null,
532
548
  compressedGeometry: null,
@@ -535,9 +551,20 @@ export default class I3SConverter {
535
551
  meshMaterial: null,
536
552
  vertexCount: null,
537
553
  attributes: null,
538
- featureCount: null
554
+ featureCount: null,
555
+ boundingVolumes: null
539
556
  };
557
+
540
558
  for (const resources of resourcesData || [emptyResources]) {
559
+ if (this.generateBoundingVolumes && resources.boundingVolumes) {
560
+ boundingVolumes = resources.boundingVolumes;
561
+ }
562
+
563
+ const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);
564
+ const maxScreenThresholdSQ = lodSelection.find(
565
+ (val) => val.metricType === 'maxScreenThresholdSQ'
566
+ ) || {maxError: 0};
567
+
541
568
  const nodeInPage = this._createNodeInNodePages(
542
569
  maxScreenThresholdSQ,
543
570
  boundingVolumes,
@@ -554,7 +581,7 @@ export default class I3SConverter {
554
581
  );
555
582
 
556
583
  if (nodeInPage.mesh) {
557
- await this._writeResources(resources, node.path);
584
+ await this._writeResources(resources, node.path!);
558
585
  }
559
586
 
560
587
  if (this.validate) {
@@ -566,15 +593,15 @@ export default class I3SConverter {
566
593
  }
567
594
 
568
595
  nodes.push(node);
596
+ nodesInPage.push(nodeInPage);
569
597
  }
570
598
 
571
599
  sourceTile.unloadContent();
572
600
 
573
- const firstNode = nodes[0];
574
601
  await this._addChildrenWithNeighborsAndWriteFile({
575
- parentNode: firstNode,
602
+ parentNode: nodes[0],
576
603
  sourceTiles: sourceTile.children,
577
- parentId: firstNode.id,
604
+ parentId: nodesInPage[0].index!,
578
605
  level: level + 1
579
606
  });
580
607
  return nodes;
@@ -589,7 +616,7 @@ export default class I3SConverter {
589
616
  private _convertAttributeStorageInfo(sourceTileContent: B3DMContent): void {
590
617
  // In legacy b3dm files sometimes sourceTileContent is null.
591
618
  const batchTable = sourceTileContent && sourceTileContent.batchTableJson;
592
- if (batchTable && !this.layers0.attributeStorageInfo.length) {
619
+ if (batchTable && !this.layers0?.attributeStorageInfo?.length) {
593
620
  this._convertBatchTableInfoToNodeAttributes(batchTable);
594
621
  }
595
622
  }
@@ -606,16 +633,18 @@ export default class I3SConverter {
606
633
  * result.attributes - feature attributes
607
634
  * result.featureCount - number of features
608
635
  */
609
- private async _convertResources(sourceTile: TileHeader): Promise<I3SGeometry[]> {
610
- if (!sourceTile.content || sourceTile.content.type !== 'b3dm') {
636
+ private async _convertResources(sourceTile: TileHeader): Promise<I3SConvertedResources[] | null> {
637
+ if (!this.isContentSupported(sourceTile)) {
611
638
  return null;
612
639
  }
613
640
  const resourcesData = await convertB3dmToI3sGeometry(
614
641
  sourceTile.content,
615
642
  Number(this.nodePages.nodesCounter),
616
643
  this.featuresHashArray,
617
- this.layers0.attributeStorageInfo,
618
- this.options.draco
644
+ this.layers0?.attributeStorageInfo,
645
+ this.options.draco,
646
+ this.generateBoundingVolumes,
647
+ this.geoidHeightModel!
619
648
  );
620
649
  return resourcesData;
621
650
  }
@@ -639,21 +668,27 @@ export default class I3SConverter {
639
668
  boundingVolumes: BoundingVolumes,
640
669
  sourceTile: TileHeader,
641
670
  parentId: number,
642
- resources: I3SGeometry
671
+ resources: I3SConvertedResources
643
672
  ): NodeInPage {
644
673
  const {meshMaterial, texture, vertexCount, featureCount, geometry} = resources;
645
- const nodeInPage = {
674
+ const nodeInPage: NodeInPage = {
675
+ index: 0,
646
676
  lodThreshold: maxScreenThresholdSQ.maxError,
647
677
  obb: boundingVolumes.obb,
648
- children: [],
649
- mesh: null
678
+ children: []
650
679
  };
651
- if (geometry && sourceTile.content && sourceTile.content.type === 'b3dm') {
680
+ if (geometry && this.isContentSupported(sourceTile)) {
652
681
  nodeInPage.mesh = {
653
682
  geometry: {
654
- definition: texture ? 0 : 1
683
+ definition: texture ? 0 : 1,
684
+ resource: 0
685
+ },
686
+ attribute: {
687
+ resource: 0
655
688
  },
656
- attribute: {}
689
+ material: {
690
+ definition: 0
691
+ }
657
692
  };
658
693
  }
659
694
  const nodeId = this.nodePages.push(nodeInPage, parentId);
@@ -695,15 +730,15 @@ export default class I3SConverter {
695
730
  boundingVolumes: BoundingVolumes,
696
731
  lodSelection: LodSelection[],
697
732
  nodeInPage: NodeInPage,
698
- resources: I3SGeometry
733
+ resources: I3SConvertedResources
699
734
  ): Node3DIndexDocument {
700
735
  const {texture, attributes} = resources;
701
- const nodeId = nodeInPage.index;
736
+ const nodeId = nodeInPage.index!;
702
737
  const nodeData = {
703
738
  version: parentNode.version,
704
739
  id: nodeId.toString(),
705
740
  path: nodeId.toString(),
706
- level: parentNode.level + 1,
741
+ level: parentNode.level! + 1,
707
742
  ...boundingVolumes,
708
743
  lodSelection,
709
744
  parentNode: {
@@ -715,7 +750,7 @@ export default class I3SConverter {
715
750
  children: [],
716
751
  neighbors: []
717
752
  };
718
- const node = transform(nodeData, nodeTemplate);
753
+ const node = transform(nodeData, nodeTemplate());
719
754
 
720
755
  if (nodeInPage.mesh) {
721
756
  node.geometryData = [{href: './geometries/0'}];
@@ -725,12 +760,7 @@ export default class I3SConverter {
725
760
  node.textureData = [{href: './textures/0'}, {href: './textures/1'}];
726
761
  }
727
762
 
728
- if (
729
- attributes &&
730
- attributes.length &&
731
- this.layers0.attributeStorageInfo &&
732
- this.layers0.attributeStorageInfo.length
733
- ) {
763
+ if (attributes && attributes.length && this.layers0?.attributeStorageInfo?.length) {
734
764
  node.attributeData = [];
735
765
  for (let index = 0; index < attributes.length; index++) {
736
766
  const folderName = this.layers0.attributeStorageInfo[index].key;
@@ -752,7 +782,7 @@ export default class I3SConverter {
752
782
  * @param resources.attributes - feature attributes
753
783
  * @return {Promise<void>}
754
784
  */
755
- private async _writeResources(resources: I3SGeometry, nodePath: string): Promise<void> {
785
+ private async _writeResources(resources: I3SConvertedResources, nodePath: string): Promise<void> {
756
786
  const {
757
787
  geometry: geometryBuffer,
758
788
  compressedGeometry,
@@ -763,8 +793,8 @@ export default class I3SConverter {
763
793
  const childPath = join(this.layers0Path, 'nodes', nodePath);
764
794
  const slpkChildPath = join('nodes', nodePath);
765
795
 
766
- await this._writeGeometries(geometryBuffer, compressedGeometry, childPath, slpkChildPath);
767
- await this._writeShared(sharedResources, childPath, slpkChildPath, nodePath);
796
+ await this._writeGeometries(geometryBuffer!, compressedGeometry!, childPath, slpkChildPath);
797
+ await this._writeShared(sharedResources!, childPath, slpkChildPath, nodePath);
768
798
  await this._writeTexture(texture, childPath, slpkChildPath);
769
799
  await this._writeAttributes(attributes, childPath, slpkChildPath);
770
800
  }
@@ -823,7 +853,7 @@ export default class I3SConverter {
823
853
  nodePath: string
824
854
  ): Promise<void> {
825
855
  sharedResources.nodePath = nodePath;
826
- const sharedData = transform(sharedResources, SHARED_RESOURCES_TEMPLATE);
856
+ const sharedData = transform(sharedResources, sharedResourcesTemplate());
827
857
  const sharedDataStr = JSON.stringify(sharedData);
828
858
  if (this.options.slpk) {
829
859
  const slpkSharedPath = join(childPath, 'shared');
@@ -839,63 +869,95 @@ export default class I3SConverter {
839
869
  }
840
870
 
841
871
  /**
842
- * Write the texture image in a file
872
+ * Generates textures based on texture mime type and fill in textureSetDefinitions data.
843
873
  * @param texture - the texture image
844
874
  * @param childPath - a child path to write resources
845
875
  * @param slpkChildPath - the resource path inside *slpk file
846
876
  */
847
877
  private async _writeTexture(
848
- texture: TextureImage,
878
+ texture: GLTFImagePostprocessed,
849
879
  childPath: string,
850
880
  slpkChildPath: string
851
881
  ): Promise<void> {
852
882
  if (texture) {
853
- const format = this._getFormatByMimeType(texture.mimeType);
854
- if (!this.layers0.textureSetDefinitions.length) {
855
- this.layers0.textureSetDefinitions.push({
856
- formats: [
857
- {
858
- name: '0',
859
- format
860
- },
861
- {
862
- name: '1',
863
- format: 'ktx2'
864
- }
865
- ]
866
- });
867
- }
868
-
869
- const textureData = texture.bufferView.data;
870
- const ktx2TextureData = await encode(texture.image, KTX2BasisUniversalTextureWriter);
883
+ const format = this._getFormatByMimeType(texture?.mimeType);
884
+ const formats: TextureSetDefinitionFormats = [];
885
+ const textureData = texture.bufferView!.data;
886
+
887
+ switch (format) {
888
+ case 'jpg':
889
+ case 'png': {
890
+ formats.push({name: '0', format});
891
+ await this.writeTextureFile(textureData, '0', format, childPath, slpkChildPath);
892
+
893
+ if (this.generateTextures) {
894
+ formats.push({name: '1', format: 'ktx2'});
895
+ const ktx2TextureData = new Uint8Array(
896
+ await encode(texture.image, KTX2BasisUniversalTextureWriter)
897
+ );
898
+ await this.writeTextureFile(ktx2TextureData, '1', 'ktx2', childPath, slpkChildPath);
899
+ }
871
900
 
872
- if (this.options.slpk) {
873
- const slpkTexturePath = join(childPath, 'textures');
874
- const compress = false;
875
-
876
- this.fileMap[`${slpkChildPath}/textures/0.${format}`] = await writeFileForSlpk(
877
- slpkTexturePath,
878
- textureData,
879
- `0.${format}`,
880
- compress
881
- );
901
+ break;
902
+ }
882
903
 
883
- this.fileMap[`${slpkChildPath}/textures/1.ktx2`] = await writeFileForSlpk(
884
- slpkTexturePath,
885
- ktx2TextureData,
886
- `1.ktx2`,
887
- compress
888
- );
889
- } else {
890
- const texturePath = join(childPath, 'textures/0/');
891
- await writeFile(texturePath, textureData, `index.${format}`);
904
+ case 'ktx2': {
905
+ formats.push({name: '1', format});
906
+ await this.writeTextureFile(textureData, '1', format, childPath, slpkChildPath);
907
+
908
+ if (this.generateTextures) {
909
+ formats.push({name: '0', format: 'jpg'});
910
+ const decodedFromKTX2TextureData = new Uint8Array(
911
+ await encode(texture.image!.data[0], ImageWriter)
912
+ );
913
+ await this.writeTextureFile(
914
+ decodedFromKTX2TextureData,
915
+ '0',
916
+ 'jpg',
917
+ childPath,
918
+ slpkChildPath
919
+ );
920
+ }
921
+ }
922
+ }
892
923
 
893
- const ktx2TexturePath = join(childPath, 'textures/1/');
894
- await writeFile(ktx2TexturePath, ktx2TextureData, `index.ktx2`);
924
+ if (!this.layers0!.textureSetDefinitions!.length) {
925
+ this.layers0!.textureSetDefinitions!.push({formats});
895
926
  }
896
927
  }
897
928
  }
898
929
 
930
+ /**
931
+ * Write the texture image in a file
932
+ * @param textureData
933
+ * @param name
934
+ * @param format
935
+ * @param childPath
936
+ * @param slpkChildPath
937
+ */
938
+ private async writeTextureFile(
939
+ textureData: ArrayBuffer,
940
+ name: string,
941
+ format: 'jpg' | 'png' | 'ktx2',
942
+ childPath: string,
943
+ slpkChildPath: string
944
+ ): Promise<void> {
945
+ const texturePath = join(childPath, `textures/${name}/`);
946
+ await writeFile(texturePath, textureData, `index.${format}`);
947
+
948
+ if (this.options.slpk) {
949
+ const slpkTexturePath = join(childPath, 'textures');
950
+ const compress = false;
951
+
952
+ this.fileMap[`${slpkChildPath}/textures/${name}.${format}`] = await writeFileForSlpk(
953
+ slpkTexturePath,
954
+ textureData,
955
+ `${name}.${format}`,
956
+ compress
957
+ );
958
+ }
959
+ }
960
+
899
961
  /**
900
962
  * Write feature attributes in files
901
963
  * @param attributes - feature attributes
@@ -907,11 +969,7 @@ export default class I3SConverter {
907
969
  childPath: string,
908
970
  slpkChildPath: string
909
971
  ): Promise<void> {
910
- if (
911
- attributes.length &&
912
- this.layers0.attributeStorageInfo &&
913
- this.layers0.attributeStorageInfo.length
914
- ) {
972
+ if (attributes.length && this.layers0?.attributeStorageInfo?.length) {
915
973
  for (let index = 0; index < attributes.length; index++) {
916
974
  const folderName = this.layers0.attributeStorageInfo[index].key;
917
975
  const fileBuffer = new Uint8Array(attributes[index]);
@@ -935,12 +993,14 @@ export default class I3SConverter {
935
993
  * Return file format by its MIME type
936
994
  * @param mimeType - feature attributes
937
995
  */
938
- private _getFormatByMimeType(mimeType: string): string {
996
+ private _getFormatByMimeType(mimeType: string | undefined): 'jpg' | 'png' | 'ktx2' {
939
997
  switch (mimeType) {
940
998
  case 'image/jpeg':
941
999
  return 'jpg';
942
1000
  case 'image/png':
943
1001
  return 'png';
1002
+ case 'image/ktx2':
1003
+ return 'ktx2';
944
1004
  default:
945
1005
  return 'jpg';
946
1006
  }
@@ -951,7 +1011,7 @@ export default class I3SConverter {
951
1011
  * @param material - end-to-end index of the node
952
1012
  * @return material id
953
1013
  */
954
- private _findOrCreateMaterial(material: GLTFMaterial): number {
1014
+ private _findOrCreateMaterial(material: I3SMaterialDefinition): number {
955
1015
  const hash = md5(JSON.stringify(material));
956
1016
  if (this.materialMap.has(hash)) {
957
1017
  return this.materialMap.get(hash);
@@ -1022,7 +1082,7 @@ export default class I3SConverter {
1022
1082
  * @param storageAttribute - attribute for map segmentation.
1023
1083
  */
1024
1084
  private _setupStringAttribute(storageAttribute: AttributeStorageInfo): void {
1025
- storageAttribute.ordering.unshift('attributeByteCounts');
1085
+ storageAttribute.ordering!.unshift('attributeByteCounts');
1026
1086
  storageAttribute.header.push({property: 'attributeValuesByteCount', valueType: 'UInt32'});
1027
1087
  storageAttribute.attributeValues = {
1028
1088
  valueType: 'String',
@@ -1090,10 +1150,10 @@ export default class I3SConverter {
1090
1150
  const fieldAttribute = this._createFieldAttribute(key, fieldAttributeType);
1091
1151
  const popupInfo = this._createPopupInfo(batchTableWithObjectId);
1092
1152
 
1093
- this.layers0.attributeStorageInfo.push(storageAttribute);
1094
- this.layers0.fields.push(fieldAttribute);
1095
- this.layers0.popupInfo = popupInfo;
1096
- this.layers0.layerType = _3D_OBJECT_LAYER_TYPE;
1153
+ this.layers0!.attributeStorageInfo!.push(storageAttribute);
1154
+ this.layers0!.fields!.push(fieldAttribute);
1155
+ this.layers0!.popupInfo = popupInfo;
1156
+ this.layers0!.layerType = _3D_OBJECT_LAYER_TYPE;
1097
1157
 
1098
1158
  attributeIndex += 1;
1099
1159
  }
@@ -1126,8 +1186,11 @@ export default class I3SConverter {
1126
1186
  private _createPopupInfo(batchTable: BatchTableJson): PopupInfo {
1127
1187
  const title = '{OBJECTID}';
1128
1188
  const mediaInfos = [];
1129
- const fieldInfos = [];
1130
- const popupElements = [];
1189
+ const fieldInfos: FieldInfo[] = [];
1190
+ const popupElements: {
1191
+ fieldInfos: FieldInfo[];
1192
+ type: string;
1193
+ }[] = [];
1131
1194
  const expressionInfos = [];
1132
1195
 
1133
1196
  for (const key in batchTable) {
@@ -1203,10 +1266,10 @@ export default class I3SConverter {
1203
1266
  this.refreshTokenTime = process.hrtime();
1204
1267
 
1205
1268
  const preloadOptions = await this._fetchPreloadOptions();
1206
- this.sourceTileset.options = {...this.sourceTileset.options, ...preloadOptions};
1269
+ this.sourceTileset!.options = {...this.sourceTileset!.options, ...preloadOptions};
1207
1270
  if (preloadOptions.headers) {
1208
- this.sourceTileset.loadOptions.fetch = {
1209
- ...this.sourceTileset.loadOptions.fetch,
1271
+ this.sourceTileset!.loadOptions.fetch = {
1272
+ ...this.sourceTileset!.loadOptions.fetch,
1210
1273
  headers: preloadOptions.headers
1211
1274
  };
1212
1275
  console.log('Authorization Bearer token has been updated'); // eslint-disable-line no-undef, no-console
@@ -1226,4 +1289,12 @@ export default class I3SConverter {
1226
1289
 
1227
1290
  this.refinementCounter.tilesCount += 1;
1228
1291
  }
1292
+ /**
1293
+ * Check if the tile's content format is supported by the converter
1294
+ * @param sourceRootTile
1295
+ * @returns
1296
+ */
1297
+ private isContentSupported(sourceRootTile: Tile3D): boolean {
1298
+ return ['b3dm', 'glTF'].includes(sourceRootTile?.content?.type);
1299
+ }
1229
1300
  }