@loaders.gl/tile-converter 4.0.0-alpha.4 → 4.0.0-alpha.5

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 (134) hide show
  1. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts +78 -0
  2. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts.map +1 -0
  3. package/dist/3d-tiles-converter/3d-tiles-converter.js +9 -7
  4. package/dist/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  5. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts +78 -18
  6. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts.map +1 -0
  7. package/dist/3d-tiles-converter/helpers/b3dm-converter.js +19 -9
  8. package/dist/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  9. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.d.ts +4 -7
  10. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.d.ts.map +1 -0
  11. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js.map +1 -1
  12. package/dist/3d-tiles-converter/helpers/texture-atlas.d.ts +9 -0
  13. package/dist/3d-tiles-converter/helpers/texture-atlas.d.ts.map +1 -0
  14. package/dist/3d-tiles-converter/helpers/texture-atlas.js +1 -1
  15. package/dist/3d-tiles-converter/helpers/texture-atlas.js.map +1 -1
  16. package/dist/3d-tiles-converter/json-templates/tileset.d.ts +15 -0
  17. package/dist/3d-tiles-converter/json-templates/tileset.d.ts.map +1 -0
  18. package/dist/3d-tiles-converter/json-templates/tileset.js +12 -9
  19. package/dist/3d-tiles-converter/json-templates/tileset.js.map +1 -1
  20. package/dist/bundle.d.ts +2 -0
  21. package/dist/bundle.d.ts.map +1 -0
  22. package/dist/converter.min.js +22 -22
  23. package/dist/deps-installer/deps-installer.d.ts.map +1 -0
  24. package/dist/deps-installer/deps-installer.js +2 -6
  25. package/dist/deps-installer/deps-installer.js.map +1 -1
  26. package/dist/dist.min.js +86527 -0
  27. package/dist/i3s-converter/helpers/coordinate-converter.d.ts +41 -0
  28. package/dist/i3s-converter/helpers/coordinate-converter.d.ts.map +1 -0
  29. package/dist/i3s-converter/helpers/coordinate-converter.js +35 -3
  30. package/dist/i3s-converter/helpers/coordinate-converter.js.map +1 -1
  31. package/dist/i3s-converter/helpers/create-scene-server-path.d.ts +9 -0
  32. package/dist/i3s-converter/helpers/create-scene-server-path.d.ts.map +1 -0
  33. package/dist/i3s-converter/helpers/create-scene-server-path.js +2 -2
  34. package/dist/i3s-converter/helpers/create-scene-server-path.js.map +1 -1
  35. package/dist/i3s-converter/helpers/geometry-attributes.d.ts +23 -0
  36. package/dist/i3s-converter/helpers/geometry-attributes.d.ts.map +1 -0
  37. package/dist/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  38. package/dist/i3s-converter/helpers/geometry-converter.d.ts +5 -1
  39. package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -0
  40. package/dist/i3s-converter/helpers/geometry-converter.js +88 -42
  41. package/dist/i3s-converter/helpers/geometry-converter.js.map +1 -1
  42. package/dist/i3s-converter/helpers/node-debug.d.ts +2 -0
  43. package/dist/i3s-converter/helpers/node-debug.d.ts.map +1 -0
  44. package/dist/i3s-converter/helpers/node-debug.js +2 -4
  45. package/dist/i3s-converter/helpers/node-debug.js.map +1 -1
  46. package/dist/i3s-converter/helpers/node-pages.d.ts +83 -111
  47. package/dist/i3s-converter/helpers/node-pages.d.ts.map +1 -0
  48. package/dist/i3s-converter/helpers/node-pages.js +15 -4
  49. package/dist/i3s-converter/helpers/node-pages.js.map +1 -1
  50. package/dist/i3s-converter/i3s-converter.d.ts +320 -0
  51. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -0
  52. package/dist/i3s-converter/i3s-converter.js +158 -65
  53. package/dist/i3s-converter/i3s-converter.js.map +1 -1
  54. package/dist/i3s-converter/json-templates/layers.d.ts +95 -0
  55. package/dist/i3s-converter/json-templates/layers.d.ts.map +1 -0
  56. package/dist/i3s-converter/json-templates/layers.js +37 -27
  57. package/dist/i3s-converter/json-templates/layers.js.map +1 -1
  58. package/dist/i3s-converter/json-templates/metadata.d.ts +22 -0
  59. package/dist/i3s-converter/json-templates/metadata.d.ts.map +1 -0
  60. package/dist/i3s-converter/json-templates/metadata.js +2 -2
  61. package/dist/i3s-converter/json-templates/metadata.js.map +1 -1
  62. package/dist/i3s-converter/json-templates/node.d.ts +61 -0
  63. package/dist/i3s-converter/json-templates/node.d.ts.map +1 -0
  64. package/dist/i3s-converter/json-templates/node.js +16 -12
  65. package/dist/i3s-converter/json-templates/node.js.map +1 -1
  66. package/dist/i3s-converter/json-templates/scene-server.d.ts +28 -0
  67. package/dist/i3s-converter/json-templates/scene-server.d.ts.map +1 -0
  68. package/dist/i3s-converter/json-templates/scene-server.js +2 -2
  69. package/dist/i3s-converter/json-templates/scene-server.js.map +1 -1
  70. package/dist/i3s-converter/json-templates/shared-resources.d.ts +14 -0
  71. package/dist/i3s-converter/json-templates/shared-resources.d.ts.map +1 -0
  72. package/dist/i3s-converter/json-templates/shared-resources.js +19 -14
  73. package/dist/i3s-converter/json-templates/shared-resources.js.map +1 -1
  74. package/dist/i3s-converter/json-templates/store.d.ts +95 -0
  75. package/dist/i3s-converter/json-templates/store.d.ts.map +1 -0
  76. package/dist/i3s-converter/json-templates/store.js.map +1 -1
  77. package/dist/i3s-converter/types.d.ts +14 -0
  78. package/dist/i3s-converter/types.d.ts.map +1 -0
  79. package/dist/i3s-converter/types.js +2 -0
  80. package/dist/i3s-converter/types.js.map +1 -0
  81. package/dist/i3s-server/app.d.ts +3 -0
  82. package/dist/i3s-server/app.d.ts.map +1 -0
  83. package/dist/i3s-server/controllers/index-controller.d.ts +2 -0
  84. package/dist/i3s-server/controllers/index-controller.d.ts.map +1 -0
  85. package/dist/i3s-server/routes/index.d.ts +3 -0
  86. package/dist/i3s-server/routes/index.d.ts.map +1 -0
  87. package/dist/index.d.ts +5 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/lib/utils/{compress-utils.d.ts → compress-util.d.ts} +0 -0
  90. package/dist/lib/utils/compress-util.d.ts.map +1 -0
  91. package/dist/lib/utils/file-utils.d.ts.map +1 -0
  92. package/dist/lib/utils/lod-conversion-utils.d.ts.map +1 -0
  93. package/dist/lib/utils/statistic-utills.d.ts.map +1 -0
  94. package/dist/pgm-loader.d.ts +6 -0
  95. package/dist/pgm-loader.d.ts.map +1 -0
  96. package/dist/pgm-loader.js +3 -3
  97. package/dist/pgm-loader.js.map +1 -1
  98. package/package.json +21 -19
  99. package/src/3d-tiles-converter/3d-tiles-converter.ts +25 -21
  100. package/src/3d-tiles-converter/helpers/{b3dm-converter.js → b3dm-converter.ts} +35 -11
  101. package/src/3d-tiles-converter/helpers/{i3s-obb-to-3d-tiles-obb.js → i3s-obb-to-3d-tiles-obb.ts} +16 -1
  102. package/src/3d-tiles-converter/helpers/texture-atlas.ts +4 -4
  103. package/src/3d-tiles-converter/json-templates/{tileset.js → tileset.ts} +9 -9
  104. package/src/deps-installer/deps-installer.js +2 -2
  105. package/src/i3s-converter/helpers/coordinate-converter.ts +62 -9
  106. package/src/i3s-converter/helpers/{create-scene-server-path.js → create-scene-server-path.ts} +2 -2
  107. package/src/i3s-converter/helpers/{geometry-attributes.js → geometry-attributes.ts} +4 -4
  108. package/src/i3s-converter/helpers/geometry-converter.d.ts +5 -1
  109. package/src/i3s-converter/helpers/geometry-converter.js +110 -33
  110. package/src/i3s-converter/helpers/{node-debug.js → node-debug.ts} +3 -2
  111. package/src/i3s-converter/helpers/{node-pages.js → node-pages.ts} +41 -26
  112. package/src/i3s-converter/i3s-converter.ts +214 -136
  113. package/src/i3s-converter/json-templates/{layers.js → layers.ts} +29 -27
  114. package/src/i3s-converter/json-templates/{metadata.js → metadata.ts} +2 -2
  115. package/src/i3s-converter/json-templates/{node.js → node.ts} +12 -12
  116. package/src/i3s-converter/json-templates/{scene-server.js → scene-server.ts} +2 -2
  117. package/src/i3s-converter/json-templates/{shared-resources.js → shared-resources.ts} +14 -14
  118. package/src/i3s-converter/json-templates/{store.js → store.ts} +0 -0
  119. package/src/i3s-converter/types.ts +14 -0
  120. package/src/lib/utils/{compress-utils.d.ts → compress-util.d.ts} +0 -0
  121. package/src/pgm-loader.ts +2 -2
  122. package/dist/lib/geoid-height-model.d.ts +0 -41
  123. package/dist/lib/geoid-height-model.js +0 -140
  124. package/dist/lib/geoid-height-model.js.map +0 -1
  125. package/dist/lib/pgm-parser.d.ts +0 -14
  126. package/dist/lib/pgm-parser.js +0 -183
  127. package/dist/lib/pgm-parser.js.map +0 -1
  128. package/src/3d-tiles-converter/helpers/b3dm-converter.d.ts +0 -23
  129. package/src/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.d.ts +0 -16
  130. package/src/i3s-converter/helpers/node-pages.d.ts +0 -144
  131. package/src/lib/geoid-height-model.d.ts +0 -41
  132. package/src/lib/geoid-height-model.js +0 -239
  133. package/src/lib/pgm-parser.d.ts +0 -14
  134. 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
- import {CesiumIonLoader} from '@loaders.gl/3d-tiles';
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,11 +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';
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';
55
58
 
56
59
  const ION_DEFAULT_TOKEN =
57
60
  process.env.IonToken || // eslint-disable-line
@@ -64,6 +67,7 @@ const SHORT_INT_TYPE = 'Int32';
64
67
  const DOUBLE_TYPE = 'double';
65
68
  const OBJECT_ID_TYPE = 'OBJECTID';
66
69
  const REFRESH_TOKEN_TIMEOUT = 1800; // 30 minutes in seconds
70
+ const CESIUM_DATASET_PREFIX = 'https://';
67
71
  // const FS_FILE_TOO_LARGE = 'ERR_FS_FILE_TOO_LARGE';
68
72
 
69
73
  /**
@@ -75,20 +79,23 @@ export default class I3SConverter {
75
79
  options: any;
76
80
  layers0Path: string;
77
81
  materialMap: Map<any, any>;
78
- materialDefinitions: GLTFMaterial[];
82
+ materialDefinitions: I3SMaterialDefinition[];
79
83
  vertexCounter: number;
80
- layers0: SceneLayer3D;
84
+ layers0: SceneLayer3D | null;
81
85
  featuresHashArray: string[];
82
86
  refinementCounter: {
83
87
  tilesCount: number;
84
88
  tilesWithAddRefineCount: number;
85
89
  };
86
90
  validate: boolean;
87
- boundingVolumeWarnings?: string[];
88
- conversionStartTime: [number, number];
89
- refreshTokenTime: [number, number];
90
- sourceTileset: Tileset3D | null;
91
- 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;
96
+ Loader: LoaderWithParser = Tiles3DLoader;
97
+ generateTextures: boolean;
98
+ generateBoundingVolumes: boolean;
92
99
 
93
100
  constructor() {
94
101
  this.nodePages = new NodePages(writeFile, HARDCODED_NODES_PER_PAGE);
@@ -105,7 +112,8 @@ export default class I3SConverter {
105
112
  tilesWithAddRefineCount: 0
106
113
  };
107
114
  this.validate = false;
108
- this.boundingVolumeWarnings = null;
115
+ this.generateTextures = false;
116
+ this.generateBoundingVolumes = false;
109
117
  }
110
118
 
111
119
  /**
@@ -127,12 +135,16 @@ export default class I3SConverter {
127
135
  outputPath: string;
128
136
  tilesetName: string;
129
137
  sevenZipExe: string;
130
- egmFilePath?: string;
138
+ egmFilePath: string;
131
139
  maxDepth?: number;
132
140
  slpk?: boolean;
133
141
  token?: string;
134
142
  draco?: boolean;
135
143
  validate?: boolean;
144
+ generateTextures?: boolean;
145
+ generateBoundingVolumes?: boolean;
146
+ /** @deprecated */
147
+ inputType?: string;
136
148
  }): Promise<any> {
137
149
  this.conversionStartTime = process.hrtime();
138
150
  const {
@@ -145,10 +157,15 @@ export default class I3SConverter {
145
157
  draco,
146
158
  sevenZipExe,
147
159
  maxDepth,
148
- token
160
+ token,
161
+ generateTextures,
162
+ generateBoundingVolumes
149
163
  } = options;
150
164
  this.options = {maxDepth, slpk, sevenZipExe, egmFilePath, draco, token, inputUrl};
151
- this.validate = validate;
165
+ this.validate = Boolean(validate);
166
+ this.Loader = inputUrl.indexOf(CESIUM_DATASET_PREFIX) !== -1 ? CesiumIonLoader : Tiles3DLoader;
167
+ this.generateTextures = Boolean(generateTextures);
168
+ this.generateBoundingVolumes = Boolean(generateBoundingVolumes);
152
169
 
153
170
  console.log('Loading egm file...'); // eslint-disable-line
154
171
  this.geoidHeightModel = await load(egmFilePath, PGMLoader);
@@ -159,17 +176,17 @@ export default class I3SConverter {
159
176
  }
160
177
 
161
178
  const preloadOptions = await this._fetchPreloadOptions();
162
- const tilesetOptions: Tileset3DProps = {loadOptions: {}};
179
+ const tilesetOptions: Tileset3DProps = {loadOptions: {basis: {format: 'rgba32'}}};
163
180
  if (preloadOptions.headers) {
164
- tilesetOptions.loadOptions.fetch = {headers: preloadOptions.headers};
181
+ tilesetOptions.loadOptions!.fetch = {headers: preloadOptions.headers};
165
182
  }
166
183
  Object.assign(tilesetOptions, preloadOptions);
167
- const sourceTilesetJson = await load(inputUrl, CesiumIonLoader, tilesetOptions.loadOptions);
184
+ const sourceTilesetJson = await load(inputUrl, this.Loader, tilesetOptions.loadOptions);
168
185
  // console.log(tilesetJson); // eslint-disable-line
169
186
  this.sourceTileset = new Tileset3D(sourceTilesetJson, tilesetOptions);
170
187
 
171
188
  await this._createAndSaveTileset(outputPath, tilesetName);
172
- await this._finishConversion({slpk, outputPath, tilesetName});
189
+ await this._finishConversion({slpk: Boolean(slpk), outputPath, tilesetName});
173
190
  return sourceTilesetJson;
174
191
  }
175
192
 
@@ -194,9 +211,10 @@ export default class I3SConverter {
194
211
  this.materialDefinitions = [];
195
212
  this.materialMap = new Map();
196
213
 
197
- const sourceRootTile = this.sourceTileset.root;
198
- const boundingVolumes = createBoundingVolumes(sourceRootTile, this.geoidHeightModel);
214
+ const sourceRootTile: TileHeader = this.sourceTileset!.root!;
215
+ const boundingVolumes = createBoundingVolumes(sourceRootTile, this.geoidHeightModel!);
199
216
  const parentId = this.nodePages.push({
217
+ index: 0,
200
218
  lodThreshold: 0,
201
219
  obb: boundingVolumes.obb,
202
220
  children: []
@@ -207,7 +225,7 @@ export default class I3SConverter {
207
225
 
208
226
  await this._convertNodesTree(root0, sourceRootTile, parentId, boundingVolumes);
209
227
 
210
- this.layers0.materialDefinitions = this.materialDefinitions;
228
+ this.layers0!.materialDefinitions = this.materialDefinitions;
211
229
  await this._writeLayers0();
212
230
  createSceneServerPath(tilesetName, this.layers0, tilesetPath);
213
231
  await this._writeNodeIndexDocument(root0, 'root', join(this.layers0Path, 'nodes', 'root'));
@@ -236,7 +254,7 @@ export default class I3SConverter {
236
254
  compressGeometry: this.options.draco
237
255
  };
238
256
 
239
- this.layers0 = transform(layers0data, layersTemplate);
257
+ this.layers0 = transform(layers0data, layersTemplate());
240
258
  }
241
259
 
242
260
  /**
@@ -262,7 +280,7 @@ export default class I3SConverter {
262
280
  ...boundingVolumes,
263
281
  children: []
264
282
  };
265
- return transform(root0data, nodeTemplate);
283
+ return transform(root0data, nodeTemplate());
266
284
  }
267
285
 
268
286
  /**
@@ -278,15 +296,16 @@ export default class I3SConverter {
278
296
  parentId: number,
279
297
  boundingVolumes: BoundingVolumes
280
298
  ): Promise<void> {
281
- await this.sourceTileset._loadTile(sourceRootTile);
282
- if (sourceRootTile.content && sourceRootTile.content.type === 'b3dm') {
299
+ await this.sourceTileset!._loadTile(sourceRootTile);
300
+ if (this.isContentSupported(sourceRootTile)) {
301
+ root0.children = root0.children || [];
283
302
  root0.children.push({
284
303
  id: '1',
285
304
  href: './1',
286
305
  ...boundingVolumes
287
306
  });
288
307
  const [child] = await this._createNode(root0, sourceRootTile, parentId, 0);
289
- const childPath = join(this.layers0Path, 'nodes', child.path);
308
+ const childPath = join(this.layers0Path, 'nodes', child.path!);
290
309
 
291
310
  if (this.options.slpk) {
292
311
  this.fileMap['nodes/1/3dNodeIndexDocument.json.gz'] = await writeFileForSlpk(
@@ -355,6 +374,7 @@ export default class I3SConverter {
355
374
  slpkFileName,
356
375
  0,
357
376
  '.',
377
+ // @ts-expect-error
358
378
  this.options.sevenZipExe
359
379
  );
360
380
 
@@ -425,7 +445,7 @@ export default class I3SConverter {
425
445
  }
426
446
  for (const sourceTile of sourceTiles) {
427
447
  if (sourceTile.type === 'json') {
428
- await this.sourceTileset._loadTile(sourceTile);
448
+ await this.sourceTileset!._loadTile(sourceTile);
429
449
  await this._addChildren({
430
450
  parentNode,
431
451
  sourceTiles: sourceTile.children,
@@ -435,13 +455,14 @@ export default class I3SConverter {
435
455
  });
436
456
  await sourceTile.unloadContent();
437
457
  } else {
438
- const boundingVolumes = createBoundingVolumes(sourceTile, this.geoidHeightModel);
439
458
  const children = await this._createNode(parentNode, sourceTile, parentId, level);
459
+ parentNode.children = parentNode.children || [];
440
460
  for (const child of children) {
441
461
  parentNode.children.push({
442
462
  id: child.id,
443
463
  href: `../${child.path}`,
444
- ...boundingVolumes
464
+ obb: child.obb,
465
+ mbs: child.mbs
445
466
  });
446
467
  childNodes.push(child);
447
468
  }
@@ -462,19 +483,21 @@ export default class I3SConverter {
462
483
  childNodes: Node3DIndexDocument[]
463
484
  ): Promise<void> {
464
485
  for (const node of childNodes) {
465
- const childPath = join(this.layers0Path, 'nodes', node.path);
486
+ const childPath = join(this.layers0Path, 'nodes', node.path!);
466
487
  const nodePath = node.path;
467
488
  delete node.path;
468
489
 
469
490
  // Don't do large amount of "neightbors" to avoid big memory consumption
470
- if (parentNode.children.length < 1000) {
471
- for (const neighbor of parentNode.children) {
491
+ if (Number(parentNode?.children?.length) < 1000) {
492
+ for (const neighbor of parentNode.children || []) {
472
493
  // eslint-disable-next-line max-depth
473
494
  if (node.id === neighbor.id) {
474
495
  continue; // eslint-disable-line
475
496
  }
476
497
 
477
- node.neighbors.push({...neighbor});
498
+ if (node.neighbors) {
499
+ node.neighbors.push({...neighbor});
500
+ }
478
501
  }
479
502
  } else {
480
503
  // eslint-disable-next-line no-console, no-undef
@@ -483,7 +506,7 @@ export default class I3SConverter {
483
506
  );
484
507
  delete node.neighbors;
485
508
  }
486
- await this._writeNodeIndexDocument(node, nodePath, childPath);
509
+ await this._writeNodeIndexDocument(node, nodePath!, childPath);
487
510
  node.neighbors = [];
488
511
  }
489
512
  }
@@ -506,13 +529,9 @@ export default class I3SConverter {
506
529
  }
507
530
 
508
531
  await this._updateTilesetOptions();
509
- await this.sourceTileset._loadTile(sourceTile);
510
- const boundingVolumes = createBoundingVolumes(sourceTile, this.geoidHeightModel);
532
+ await this.sourceTileset!._loadTile(sourceTile);
511
533
 
512
- const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);
513
- const maxScreenThresholdSQ = lodSelection.find(
514
- (val) => val.metricType === 'maxScreenThresholdSQ'
515
- ) || {maxError: 0};
534
+ let boundingVolumes = createBoundingVolumes(sourceTile, this.geoidHeightModel!);
516
535
 
517
536
  const batchTable = sourceTile?.content?.batchTableJson;
518
537
 
@@ -522,7 +541,8 @@ export default class I3SConverter {
522
541
 
523
542
  const resourcesData = await this._convertResources(sourceTile);
524
543
 
525
- const nodes = [];
544
+ const nodes: Node3DIndexDocument[] = [];
545
+ const nodesInPage: NodeInPage[] = [];
526
546
  const emptyResources = {
527
547
  geometry: null,
528
548
  compressedGeometry: null,
@@ -531,9 +551,20 @@ export default class I3SConverter {
531
551
  meshMaterial: null,
532
552
  vertexCount: null,
533
553
  attributes: null,
534
- featureCount: null
554
+ featureCount: null,
555
+ boundingVolumes: null
535
556
  };
557
+
536
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
+
537
568
  const nodeInPage = this._createNodeInNodePages(
538
569
  maxScreenThresholdSQ,
539
570
  boundingVolumes,
@@ -550,7 +581,7 @@ export default class I3SConverter {
550
581
  );
551
582
 
552
583
  if (nodeInPage.mesh) {
553
- await this._writeResources(resources, node.path);
584
+ await this._writeResources(resources, node.path!);
554
585
  }
555
586
 
556
587
  if (this.validate) {
@@ -562,15 +593,15 @@ export default class I3SConverter {
562
593
  }
563
594
 
564
595
  nodes.push(node);
596
+ nodesInPage.push(nodeInPage);
565
597
  }
566
598
 
567
599
  sourceTile.unloadContent();
568
600
 
569
- const firstNode = nodes[0];
570
601
  await this._addChildrenWithNeighborsAndWriteFile({
571
- parentNode: firstNode,
602
+ parentNode: nodes[0],
572
603
  sourceTiles: sourceTile.children,
573
- parentId: firstNode.id,
604
+ parentId: nodesInPage[0].index!,
574
605
  level: level + 1
575
606
  });
576
607
  return nodes;
@@ -585,7 +616,7 @@ export default class I3SConverter {
585
616
  private _convertAttributeStorageInfo(sourceTileContent: B3DMContent): void {
586
617
  // In legacy b3dm files sometimes sourceTileContent is null.
587
618
  const batchTable = sourceTileContent && sourceTileContent.batchTableJson;
588
- if (batchTable && !this.layers0.attributeStorageInfo.length) {
619
+ if (batchTable && !this.layers0?.attributeStorageInfo?.length) {
589
620
  this._convertBatchTableInfoToNodeAttributes(batchTable);
590
621
  }
591
622
  }
@@ -602,16 +633,18 @@ export default class I3SConverter {
602
633
  * result.attributes - feature attributes
603
634
  * result.featureCount - number of features
604
635
  */
605
- private async _convertResources(sourceTile: TileHeader): Promise<I3SGeometry[]> {
606
- if (!sourceTile.content || sourceTile.content.type !== 'b3dm') {
636
+ private async _convertResources(sourceTile: TileHeader): Promise<I3SConvertedResources[] | null> {
637
+ if (!this.isContentSupported(sourceTile)) {
607
638
  return null;
608
639
  }
609
640
  const resourcesData = await convertB3dmToI3sGeometry(
610
641
  sourceTile.content,
611
642
  Number(this.nodePages.nodesCounter),
612
643
  this.featuresHashArray,
613
- this.layers0.attributeStorageInfo,
614
- this.options.draco
644
+ this.layers0?.attributeStorageInfo,
645
+ this.options.draco,
646
+ this.generateBoundingVolumes,
647
+ this.geoidHeightModel!
615
648
  );
616
649
  return resourcesData;
617
650
  }
@@ -635,21 +668,27 @@ export default class I3SConverter {
635
668
  boundingVolumes: BoundingVolumes,
636
669
  sourceTile: TileHeader,
637
670
  parentId: number,
638
- resources: I3SGeometry
671
+ resources: I3SConvertedResources
639
672
  ): NodeInPage {
640
673
  const {meshMaterial, texture, vertexCount, featureCount, geometry} = resources;
641
- const nodeInPage = {
674
+ const nodeInPage: NodeInPage = {
675
+ index: 0,
642
676
  lodThreshold: maxScreenThresholdSQ.maxError,
643
677
  obb: boundingVolumes.obb,
644
- children: [],
645
- mesh: null
678
+ children: []
646
679
  };
647
- if (geometry && sourceTile.content && sourceTile.content.type === 'b3dm') {
680
+ if (geometry && this.isContentSupported(sourceTile)) {
648
681
  nodeInPage.mesh = {
649
682
  geometry: {
650
- definition: texture ? 0 : 1
683
+ definition: texture ? 0 : 1,
684
+ resource: 0
685
+ },
686
+ attribute: {
687
+ resource: 0
651
688
  },
652
- attribute: {}
689
+ material: {
690
+ definition: 0
691
+ }
653
692
  };
654
693
  }
655
694
  const nodeId = this.nodePages.push(nodeInPage, parentId);
@@ -691,15 +730,15 @@ export default class I3SConverter {
691
730
  boundingVolumes: BoundingVolumes,
692
731
  lodSelection: LodSelection[],
693
732
  nodeInPage: NodeInPage,
694
- resources: I3SGeometry
733
+ resources: I3SConvertedResources
695
734
  ): Node3DIndexDocument {
696
735
  const {texture, attributes} = resources;
697
- const nodeId = nodeInPage.index;
736
+ const nodeId = nodeInPage.index!;
698
737
  const nodeData = {
699
738
  version: parentNode.version,
700
739
  id: nodeId.toString(),
701
740
  path: nodeId.toString(),
702
- level: parentNode.level + 1,
741
+ level: parentNode.level! + 1,
703
742
  ...boundingVolumes,
704
743
  lodSelection,
705
744
  parentNode: {
@@ -711,7 +750,7 @@ export default class I3SConverter {
711
750
  children: [],
712
751
  neighbors: []
713
752
  };
714
- const node = transform(nodeData, nodeTemplate);
753
+ const node = transform(nodeData, nodeTemplate());
715
754
 
716
755
  if (nodeInPage.mesh) {
717
756
  node.geometryData = [{href: './geometries/0'}];
@@ -721,12 +760,7 @@ export default class I3SConverter {
721
760
  node.textureData = [{href: './textures/0'}, {href: './textures/1'}];
722
761
  }
723
762
 
724
- if (
725
- attributes &&
726
- attributes.length &&
727
- this.layers0.attributeStorageInfo &&
728
- this.layers0.attributeStorageInfo.length
729
- ) {
763
+ if (attributes && attributes.length && this.layers0?.attributeStorageInfo?.length) {
730
764
  node.attributeData = [];
731
765
  for (let index = 0; index < attributes.length; index++) {
732
766
  const folderName = this.layers0.attributeStorageInfo[index].key;
@@ -748,7 +782,7 @@ export default class I3SConverter {
748
782
  * @param resources.attributes - feature attributes
749
783
  * @return {Promise<void>}
750
784
  */
751
- private async _writeResources(resources: I3SGeometry, nodePath: string): Promise<void> {
785
+ private async _writeResources(resources: I3SConvertedResources, nodePath: string): Promise<void> {
752
786
  const {
753
787
  geometry: geometryBuffer,
754
788
  compressedGeometry,
@@ -759,8 +793,8 @@ export default class I3SConverter {
759
793
  const childPath = join(this.layers0Path, 'nodes', nodePath);
760
794
  const slpkChildPath = join('nodes', nodePath);
761
795
 
762
- await this._writeGeometries(geometryBuffer, compressedGeometry, childPath, slpkChildPath);
763
- await this._writeShared(sharedResources, childPath, slpkChildPath, nodePath);
796
+ await this._writeGeometries(geometryBuffer!, compressedGeometry!, childPath, slpkChildPath);
797
+ await this._writeShared(sharedResources!, childPath, slpkChildPath, nodePath);
764
798
  await this._writeTexture(texture, childPath, slpkChildPath);
765
799
  await this._writeAttributes(attributes, childPath, slpkChildPath);
766
800
  }
@@ -819,7 +853,7 @@ export default class I3SConverter {
819
853
  nodePath: string
820
854
  ): Promise<void> {
821
855
  sharedResources.nodePath = nodePath;
822
- const sharedData = transform(sharedResources, SHARED_RESOURCES_TEMPLATE);
856
+ const sharedData = transform(sharedResources, sharedResourcesTemplate());
823
857
  const sharedDataStr = JSON.stringify(sharedData);
824
858
  if (this.options.slpk) {
825
859
  const slpkSharedPath = join(childPath, 'shared');
@@ -835,63 +869,95 @@ export default class I3SConverter {
835
869
  }
836
870
 
837
871
  /**
838
- * Write the texture image in a file
872
+ * Generates textures based on texture mime type and fill in textureSetDefinitions data.
839
873
  * @param texture - the texture image
840
874
  * @param childPath - a child path to write resources
841
875
  * @param slpkChildPath - the resource path inside *slpk file
842
876
  */
843
877
  private async _writeTexture(
844
- texture: TextureImage,
878
+ texture: GLTFImagePostprocessed,
845
879
  childPath: string,
846
880
  slpkChildPath: string
847
881
  ): Promise<void> {
848
882
  if (texture) {
849
- const format = this._getFormatByMimeType(texture.mimeType);
850
- if (!this.layers0.textureSetDefinitions.length) {
851
- this.layers0.textureSetDefinitions.push({
852
- formats: [
853
- {
854
- name: '0',
855
- format
856
- },
857
- {
858
- name: '1',
859
- format: 'ktx2'
860
- }
861
- ]
862
- });
863
- }
864
-
865
- const textureData = texture.bufferView.data;
866
- 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
+ }
867
900
 
868
- if (this.options.slpk) {
869
- const slpkTexturePath = join(childPath, 'textures');
870
- const compress = false;
871
-
872
- this.fileMap[`${slpkChildPath}/textures/0.${format}`] = await writeFileForSlpk(
873
- slpkTexturePath,
874
- textureData,
875
- `0.${format}`,
876
- compress
877
- );
901
+ break;
902
+ }
878
903
 
879
- this.fileMap[`${slpkChildPath}/textures/1.ktx2`] = await writeFileForSlpk(
880
- slpkTexturePath,
881
- ktx2TextureData,
882
- `1.ktx2`,
883
- compress
884
- );
885
- } else {
886
- const texturePath = join(childPath, 'textures/0/');
887
- 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
+ }
888
923
 
889
- const ktx2TexturePath = join(childPath, 'textures/1/');
890
- await writeFile(ktx2TexturePath, ktx2TextureData, `index.ktx2`);
924
+ if (!this.layers0!.textureSetDefinitions!.length) {
925
+ this.layers0!.textureSetDefinitions!.push({formats});
891
926
  }
892
927
  }
893
928
  }
894
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
+
895
961
  /**
896
962
  * Write feature attributes in files
897
963
  * @param attributes - feature attributes
@@ -903,11 +969,7 @@ export default class I3SConverter {
903
969
  childPath: string,
904
970
  slpkChildPath: string
905
971
  ): Promise<void> {
906
- if (
907
- attributes.length &&
908
- this.layers0.attributeStorageInfo &&
909
- this.layers0.attributeStorageInfo.length
910
- ) {
972
+ if (attributes.length && this.layers0?.attributeStorageInfo?.length) {
911
973
  for (let index = 0; index < attributes.length; index++) {
912
974
  const folderName = this.layers0.attributeStorageInfo[index].key;
913
975
  const fileBuffer = new Uint8Array(attributes[index]);
@@ -931,12 +993,14 @@ export default class I3SConverter {
931
993
  * Return file format by its MIME type
932
994
  * @param mimeType - feature attributes
933
995
  */
934
- private _getFormatByMimeType(mimeType: string): string {
996
+ private _getFormatByMimeType(mimeType: string | undefined): 'jpg' | 'png' | 'ktx2' {
935
997
  switch (mimeType) {
936
998
  case 'image/jpeg':
937
999
  return 'jpg';
938
1000
  case 'image/png':
939
1001
  return 'png';
1002
+ case 'image/ktx2':
1003
+ return 'ktx2';
940
1004
  default:
941
1005
  return 'jpg';
942
1006
  }
@@ -947,7 +1011,7 @@ export default class I3SConverter {
947
1011
  * @param material - end-to-end index of the node
948
1012
  * @return material id
949
1013
  */
950
- private _findOrCreateMaterial(material: GLTFMaterial): number {
1014
+ private _findOrCreateMaterial(material: I3SMaterialDefinition): number {
951
1015
  const hash = md5(JSON.stringify(material));
952
1016
  if (this.materialMap.has(hash)) {
953
1017
  return this.materialMap.get(hash);
@@ -1018,7 +1082,7 @@ export default class I3SConverter {
1018
1082
  * @param storageAttribute - attribute for map segmentation.
1019
1083
  */
1020
1084
  private _setupStringAttribute(storageAttribute: AttributeStorageInfo): void {
1021
- storageAttribute.ordering.unshift('attributeByteCounts');
1085
+ storageAttribute.ordering!.unshift('attributeByteCounts');
1022
1086
  storageAttribute.header.push({property: 'attributeValuesByteCount', valueType: 'UInt32'});
1023
1087
  storageAttribute.attributeValues = {
1024
1088
  valueType: 'String',
@@ -1086,10 +1150,10 @@ export default class I3SConverter {
1086
1150
  const fieldAttribute = this._createFieldAttribute(key, fieldAttributeType);
1087
1151
  const popupInfo = this._createPopupInfo(batchTableWithObjectId);
1088
1152
 
1089
- this.layers0.attributeStorageInfo.push(storageAttribute);
1090
- this.layers0.fields.push(fieldAttribute);
1091
- this.layers0.popupInfo = popupInfo;
1092
- 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;
1093
1157
 
1094
1158
  attributeIndex += 1;
1095
1159
  }
@@ -1122,8 +1186,11 @@ export default class I3SConverter {
1122
1186
  private _createPopupInfo(batchTable: BatchTableJson): PopupInfo {
1123
1187
  const title = '{OBJECTID}';
1124
1188
  const mediaInfos = [];
1125
- const fieldInfos = [];
1126
- const popupElements = [];
1189
+ const fieldInfos: FieldInfo[] = [];
1190
+ const popupElements: {
1191
+ fieldInfos: FieldInfo[];
1192
+ type: string;
1193
+ }[] = [];
1127
1194
  const expressionInfos = [];
1128
1195
 
1129
1196
  for (const key in batchTable) {
@@ -1177,10 +1244,13 @@ export default class I3SConverter {
1177
1244
  * Fetch preload options for ION tileset
1178
1245
  */
1179
1246
  private async _fetchPreloadOptions(): Promise<any> {
1247
+ if (!this.Loader.preload) {
1248
+ return {};
1249
+ }
1180
1250
  const options = {
1181
1251
  'cesium-ion': {accessToken: this.options.token || ION_DEFAULT_TOKEN}
1182
1252
  };
1183
- const preloadOptions = await CesiumIonLoader.preload(this.options.inputUrl, options);
1253
+ const preloadOptions = await this.Loader.preload(this.options.inputUrl, options);
1184
1254
  this.refreshTokenTime = process.hrtime();
1185
1255
  return {...options, ...preloadOptions};
1186
1256
  }
@@ -1196,10 +1266,10 @@ export default class I3SConverter {
1196
1266
  this.refreshTokenTime = process.hrtime();
1197
1267
 
1198
1268
  const preloadOptions = await this._fetchPreloadOptions();
1199
- this.sourceTileset.options = {...this.sourceTileset.options, ...preloadOptions};
1269
+ this.sourceTileset!.options = {...this.sourceTileset!.options, ...preloadOptions};
1200
1270
  if (preloadOptions.headers) {
1201
- this.sourceTileset.loadOptions.fetch = {
1202
- ...this.sourceTileset.loadOptions.fetch,
1271
+ this.sourceTileset!.loadOptions.fetch = {
1272
+ ...this.sourceTileset!.loadOptions.fetch,
1203
1273
  headers: preloadOptions.headers
1204
1274
  };
1205
1275
  console.log('Authorization Bearer token has been updated'); // eslint-disable-line no-undef, no-console
@@ -1219,4 +1289,12 @@ export default class I3SConverter {
1219
1289
 
1220
1290
  this.refinementCounter.tilesCount += 1;
1221
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
+ }
1222
1300
  }