@loaders.gl/tile-converter 4.0.0-alpha.18 → 4.0.0-alpha.20

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 (107) hide show
  1. package/bin/converter.js +1 -1
  2. package/dist/constants.d.ts +2 -0
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/constants.js +3 -1
  5. package/dist/converter-cli.js +10 -2
  6. package/dist/converter.min.js +172 -103
  7. package/dist/deps-installer/deps-installer.d.ts +3 -2
  8. package/dist/deps-installer/deps-installer.d.ts.map +1 -1
  9. package/dist/deps-installer/deps-installer.js +36 -10
  10. package/dist/dist.min.js +226 -151
  11. package/dist/es5/constants.js +5 -1
  12. package/dist/es5/constants.js.map +1 -1
  13. package/dist/es5/converter-cli.js +7 -2
  14. package/dist/es5/converter-cli.js.map +1 -1
  15. package/dist/es5/deps-installer/deps-installer.js +112 -38
  16. package/dist/es5/deps-installer/deps-installer.js.map +1 -1
  17. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js +21 -8
  18. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
  19. package/dist/es5/i3s-converter/helpers/geometry-attributes.js +7 -6
  20. package/dist/es5/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  21. package/dist/es5/i3s-converter/helpers/geometry-converter.js +78 -67
  22. package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
  23. package/dist/es5/i3s-converter/helpers/preprocess-3d-tiles.js +38 -9
  24. package/dist/es5/i3s-converter/helpers/preprocess-3d-tiles.js.map +1 -1
  25. package/dist/es5/i3s-converter/i3s-converter.js +86 -99
  26. package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
  27. package/dist/es5/i3s-converter/types.js +11 -11
  28. package/dist/es5/i3s-converter/types.js.map +1 -1
  29. package/dist/es5/i3s-server/controllers/slpk-controller.js +1 -1
  30. package/dist/es5/i3s-server/controllers/slpk-controller.js.map +1 -1
  31. package/dist/es5/index.js +3 -3
  32. package/dist/es5/index.js.map +1 -1
  33. package/dist/es5/pgm-loader.js +1 -1
  34. package/dist/es5/slpk-extractor/helpers/{file-handle-provider.js → file-handle-file.js} +9 -9
  35. package/dist/es5/slpk-extractor/helpers/file-handle-file.js.map +1 -0
  36. package/dist/es5/slpk-extractor/slpk-extractor.js +5 -5
  37. package/dist/es5/slpk-extractor/slpk-extractor.js.map +1 -1
  38. package/dist/esm/constants.js +2 -0
  39. package/dist/esm/constants.js.map +1 -1
  40. package/dist/esm/converter-cli.js +7 -2
  41. package/dist/esm/converter-cli.js.map +1 -1
  42. package/dist/esm/deps-installer/deps-installer.js +37 -11
  43. package/dist/esm/deps-installer/deps-installer.js.map +1 -1
  44. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js +18 -6
  45. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
  46. package/dist/esm/i3s-converter/helpers/geometry-attributes.js +7 -6
  47. package/dist/esm/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  48. package/dist/esm/i3s-converter/helpers/geometry-converter.js +37 -25
  49. package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
  50. package/dist/esm/i3s-converter/helpers/preprocess-3d-tiles.js +28 -9
  51. package/dist/esm/i3s-converter/helpers/preprocess-3d-tiles.js.map +1 -1
  52. package/dist/esm/i3s-converter/i3s-converter.js +49 -36
  53. package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
  54. package/dist/esm/i3s-converter/types.js +9 -9
  55. package/dist/esm/i3s-converter/types.js.map +1 -1
  56. package/dist/esm/i3s-server/bin/i3s-server.min.js +71 -71
  57. package/dist/esm/i3s-server/controllers/slpk-controller.js +2 -2
  58. package/dist/esm/i3s-server/controllers/slpk-controller.js.map +1 -1
  59. package/dist/esm/index.js +1 -1
  60. package/dist/esm/index.js.map +1 -1
  61. package/dist/esm/pgm-loader.js +1 -1
  62. package/dist/esm/slpk-extractor/helpers/{file-handle-provider.js → file-handle-file.js} +3 -3
  63. package/dist/esm/slpk-extractor/helpers/file-handle-file.js.map +1 -0
  64. package/dist/esm/slpk-extractor/slpk-extractor.js +3 -3
  65. package/dist/esm/slpk-extractor/slpk-extractor.js.map +1 -1
  66. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts +11 -1
  67. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts.map +1 -1
  68. package/dist/i3s-converter/helpers/batch-ids-extensions.js +33 -13
  69. package/dist/i3s-converter/helpers/geometry-attributes.js +7 -6
  70. package/dist/i3s-converter/helpers/geometry-converter.d.ts +7 -6
  71. package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -1
  72. package/dist/i3s-converter/helpers/geometry-converter.js +59 -47
  73. package/dist/i3s-converter/helpers/preprocess-3d-tiles.d.ts +2 -2
  74. package/dist/i3s-converter/helpers/preprocess-3d-tiles.d.ts.map +1 -1
  75. package/dist/i3s-converter/helpers/preprocess-3d-tiles.js +39 -14
  76. package/dist/i3s-converter/i3s-converter.d.ts +2 -1
  77. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
  78. package/dist/i3s-converter/i3s-converter.js +49 -31
  79. package/dist/i3s-converter/types.d.ts +4 -2
  80. package/dist/i3s-converter/types.d.ts.map +1 -1
  81. package/dist/i3s-converter/types.js +11 -11
  82. package/dist/i3s-server/controllers/slpk-controller.js +1 -1
  83. package/dist/index.d.ts +1 -1
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +3 -3
  86. package/dist/slpk-extractor/helpers/{file-handle-provider.d.ts → file-handle-file.d.ts} +5 -5
  87. package/dist/slpk-extractor/helpers/file-handle-file.d.ts.map +1 -0
  88. package/dist/slpk-extractor/helpers/{file-handle-provider.js → file-handle-file.js} +5 -5
  89. package/dist/slpk-extractor/slpk-extractor.js +5 -5
  90. package/dist/slpk-extractor.min.js +32 -32
  91. package/package.json +15 -14
  92. package/src/constants.ts +3 -0
  93. package/src/converter-cli.ts +9 -2
  94. package/src/deps-installer/deps-installer.ts +55 -10
  95. package/src/i3s-converter/helpers/batch-ids-extensions.ts +39 -12
  96. package/src/i3s-converter/helpers/geometry-attributes.ts +15 -8
  97. package/src/i3s-converter/helpers/geometry-converter.ts +84 -48
  98. package/src/i3s-converter/helpers/preprocess-3d-tiles.ts +48 -18
  99. package/src/i3s-converter/i3s-converter.ts +65 -39
  100. package/src/i3s-converter/types.ts +4 -2
  101. package/src/i3s-server/controllers/slpk-controller.ts +2 -2
  102. package/src/index.ts +1 -1
  103. package/src/slpk-extractor/helpers/{file-handle-provider.ts → file-handle-file.ts} +5 -5
  104. package/src/slpk-extractor/slpk-extractor.ts +3 -3
  105. package/dist/es5/slpk-extractor/helpers/file-handle-provider.js.map +0 -1
  106. package/dist/esm/slpk-extractor/helpers/file-handle-provider.js.map +0 -1
  107. package/dist/slpk-extractor/helpers/file-handle-provider.d.ts.map +0 -1
@@ -35,7 +35,7 @@ import {
35
35
  import {NumberArray, TypedArray} from '@loaders.gl/loader-utils';
36
36
  import {Geoid} from '@math.gl/geoid';
37
37
  import {prepareDataForAttributesConversion} from './gltf-attributes';
38
- import {handleBatchIdsExtensions} from './batch-ids-extensions';
38
+ import {getTextureByMetadataClass, handleBatchIdsExtensions} from './batch-ids-extensions';
39
39
  import {checkPropertiesLength, flattenPropertyTableByFeatureIds} from './feature-attributes';
40
40
  import {GL} from '@loaders.gl/math';
41
41
 
@@ -47,6 +47,7 @@ import {GL} from '@loaders.gl/math';
47
47
  import type {GLTFAttributesData, TextureImageProperties, TypedArrayConstructor} from '../types';
48
48
  import {generateSyntheticIndices} from '../../lib/utils/geometry-utils';
49
49
  import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
50
+ import {EXT_FEATURE_METADATA, EXT_MESH_FEATURES} from '../../constants';
50
51
 
51
52
  // Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md
52
53
  const DEFAULT_ROUGHNESS_FACTOR = 1;
@@ -67,9 +68,6 @@ const OBJECT_ID_TYPE = 'Oid32';
67
68
  */
68
69
  const BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES = ['CUSTOM_ATTRIBUTE_2', '_BATCHID', 'BATCHID'];
69
70
 
70
- const EXT_FEATURE_METADATA = 'EXT_feature_metadata';
71
- const EXT_MESH_FEATURES = 'EXT_mesh_features';
72
-
73
71
  let scratchVector = new Vector3();
74
72
 
75
73
  /**
@@ -87,7 +85,8 @@ let scratchVector = new Vector3();
87
85
  * @param generateBoundingVolumes - is converter should create accurate bounding voulmes from geometry attributes
88
86
  * @param shouldMergeMaterials - Try to merge similar materials to be able to merge meshes into one node
89
87
  * @param geoidHeightModel - model to convert elevation from elipsoidal to geoid
90
- * @param workerSource - source code of used workers
88
+ * @param libraries - dynamicaly loaded 3rd-party libraries
89
+ * @param metadataClass `- user selected feature metadata class name`
91
90
  * @returns Array of node resources to create one or more i3s nodes
92
91
  */
93
92
  export default async function convertB3dmToI3sGeometry(
@@ -102,7 +101,8 @@ export default async function convertB3dmToI3sGeometry(
102
101
  generateBoundingVolumes: boolean,
103
102
  shouldMergeMaterials: boolean,
104
103
  geoidHeightModel: Geoid,
105
- workerSource: {[key: string]: string}
104
+ libraries: Record<string, string>,
105
+ metadataClass?: string
106
106
  ): Promise<I3SConvertedResources[] | null> {
107
107
  const useCartesianPositions = generateBoundingVolumes;
108
108
  const materialAndTextureList: I3SMaterialWithTexture[] = await convertMaterials(
@@ -115,10 +115,12 @@ export default async function convertB3dmToI3sGeometry(
115
115
  tileTransform,
116
116
  tileBoundingVolume
117
117
  );
118
+ const featureTexture = getTextureByMetadataClass(tileContent, metadataClass);
118
119
  const convertedAttributesMap: Map<string, ConvertedAttributes> = await convertAttributes(
119
120
  dataForAttributesConversion,
120
121
  materialAndTextureList,
121
- useCartesianPositions
122
+ useCartesianPositions,
123
+ featureTexture
122
124
  );
123
125
  /** Usage of worker here brings more overhead than advantage */
124
126
  // const convertedAttributesMap: Map<string, ConvertedAttributes> =
@@ -156,7 +158,7 @@ export default async function convertB3dmToI3sGeometry(
156
158
  propertyTable,
157
159
  attributeStorageInfo,
158
160
  draco,
159
- workerSource
161
+ libraries
160
162
  })
161
163
  );
162
164
  }
@@ -208,7 +210,7 @@ function _generateBoundingVolumesFromGeometry(
208
210
  * @param params.propertyTable - batch table (corresponding to feature attributes data)
209
211
  * @param params.attributeStorageInfo - attributes metadata from 3DSceneLayer json
210
212
  * @param params.draco - is converter should create draco compressed geometry
211
- * @param params.workerSource - source code of used workers
213
+ * @param libraries - dynamicaly loaded 3rd-party libraries
212
214
  * @returns Array of I3S node resources
213
215
  */
214
216
  async function _makeNodeResources({
@@ -221,7 +223,7 @@ async function _makeNodeResources({
221
223
  propertyTable,
222
224
  attributeStorageInfo,
223
225
  draco,
224
- workerSource
226
+ libraries
225
227
  }: {
226
228
  convertedAttributes: ConvertedAttributes;
227
229
  material: I3SMaterialDefinition;
@@ -232,7 +234,7 @@ async function _makeNodeResources({
232
234
  propertyTable: FeatureTableJson | null;
233
235
  attributeStorageInfo?: AttributeStorageInfo[];
234
236
  draco: boolean;
235
- workerSource: {[key: string]: string};
237
+ libraries: Record<string, string>;
236
238
  }): Promise<I3SConvertedResources> {
237
239
  const boundingVolumes = convertedAttributes.boundingVolumes;
238
240
  const vertexCount = convertedAttributes.positions.length / VALUES_PER_VERTEX;
@@ -277,7 +279,7 @@ async function _makeNodeResources({
277
279
  featureIds,
278
280
  faceRange
279
281
  },
280
- workerSource.draco
282
+ libraries
281
283
  )
282
284
  : null;
283
285
 
@@ -312,12 +314,14 @@ async function _makeNodeResources({
312
314
  * @param materialAndTextureList - array of data about materials and textures of the content
313
315
  * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
314
316
  * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
317
+ * @param featureTexture - feature texture key
315
318
  * @returns map of converted geometry attributes
316
319
  */
317
320
  export async function convertAttributes(
318
321
  attributesData: GLTFAttributesData,
319
322
  materialAndTextureList: I3SMaterialWithTexture[],
320
- useCartesianPositions: boolean
323
+ useCartesianPositions: boolean,
324
+ featureTexture: string | null
321
325
  ): Promise<Map<string, ConvertedAttributes>> {
322
326
  const {nodes, images, cartographicOrigin, cartesianModelMatrix} = attributesData;
323
327
  const attributesMap = new Map<string, ConvertedAttributes>();
@@ -345,7 +349,9 @@ export async function convertAttributes(
345
349
  cartographicOrigin,
346
350
  cartesianModelMatrix,
347
351
  attributesMap,
348
- useCartesianPositions
352
+ useCartesianPositions,
353
+ undefined,
354
+ featureTexture
349
355
  );
350
356
 
351
357
  for (const attrKey of attributesMap.keys()) {
@@ -379,6 +385,7 @@ export async function convertAttributes(
379
385
  * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
380
386
  * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
381
387
  * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
388
+ * @param featureTexture - feature texture key
382
389
  * @returns {void}
383
390
  */
384
391
  function convertNodes(
@@ -388,7 +395,8 @@ function convertNodes(
388
395
  cartesianModelMatrix: Matrix4,
389
396
  attributesMap: Map<string, ConvertedAttributes>,
390
397
  useCartesianPositions: boolean,
391
- matrix: Matrix4 = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
398
+ matrix: Matrix4 = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
399
+ featureTexture: string | null
392
400
  ) {
393
401
  if (nodes) {
394
402
  for (const node of nodes) {
@@ -399,7 +407,8 @@ function convertNodes(
399
407
  cartesianModelMatrix,
400
408
  attributesMap,
401
409
  useCartesianPositions,
402
- matrix
410
+ matrix,
411
+ featureTexture
403
412
  );
404
413
  }
405
414
  }
@@ -441,11 +450,12 @@ function getCompositeTransformationMatrix(node: GLTFNodePostprocessed, matrix: M
441
450
  * @param images - gltf images array
442
451
  * @param cartographicOrigin - cartographic origin of bounding volume
443
452
  * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic
444
- * @param {Map} attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
453
+ * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
445
454
  * attributes
446
455
  * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
447
456
  * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
448
- * @param {Matrix4} matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
457
+ * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
458
+ * @param featureTexture - feature texture key
449
459
  */
450
460
  function convertNode(
451
461
  node: GLTFNodePostprocessed,
@@ -454,7 +464,8 @@ function convertNode(
454
464
  cartesianModelMatrix: Matrix4,
455
465
  attributesMap: Map<string, ConvertedAttributes>,
456
466
  useCartesianPositions,
457
- matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
467
+ matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
468
+ featureTexture: string | null
458
469
  ) {
459
470
  const transformationMatrix = getCompositeTransformationMatrix(node, matrix);
460
471
 
@@ -468,7 +479,8 @@ function convertNode(
468
479
  cartesianModelMatrix,
469
480
  attributesMap,
470
481
  useCartesianPositions,
471
- transformationMatrix
482
+ transformationMatrix,
483
+ featureTexture
472
484
  );
473
485
  }
474
486
 
@@ -479,7 +491,8 @@ function convertNode(
479
491
  cartesianModelMatrix,
480
492
  attributesMap,
481
493
  useCartesianPositions,
482
- transformationMatrix
494
+ transformationMatrix,
495
+ featureTexture
483
496
  );
484
497
  }
485
498
 
@@ -491,12 +504,12 @@ function convertNode(
491
504
  * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic
492
505
  * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
493
506
  * attributes
494
- * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
507
+ * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
495
508
  * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
496
509
  * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
497
510
  * attributes
498
-
499
- * @param {Matrix4} matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
511
+ * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
512
+ * @param featureTexture - feature texture key
500
513
  */
501
514
  function convertMesh(
502
515
  mesh: GLTFMeshPostprocessed,
@@ -505,7 +518,8 @@ function convertMesh(
505
518
  cartesianModelMatrix: Matrix4,
506
519
  attributesMap: Map<string, ConvertedAttributes>,
507
520
  useCartesianPositions = false,
508
- matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
521
+ matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
522
+ featureTexture: string | null
509
523
  ) {
510
524
  for (const primitive of mesh.primitives) {
511
525
  let outputAttributes: ConvertedAttributes | null | undefined = null;
@@ -576,7 +590,7 @@ function convertMesh(
576
590
 
577
591
  outputAttributes.featureIndicesGroups = outputAttributes.featureIndicesGroups || [];
578
592
  outputAttributes.featureIndicesGroups.push(
579
- flattenBatchIds(getBatchIds(attributes, primitive, images), indices)
593
+ flattenBatchIds(getBatchIds(attributes, primitive, images, featureTexture), indices)
580
594
  );
581
595
  }
582
596
  }
@@ -803,15 +817,23 @@ function flattenBatchIds(batchedIds: NumberArray, indices: TypedArray): number[]
803
817
  * @param attributes - gltf accessors
804
818
  * @param primitive - gltf primitive data
805
819
  * @param images - gltf texture images
820
+ * @param featureTexture - feature texture key
821
+ * @return batch IDs
806
822
  */
807
823
  function getBatchIds(
808
824
  attributes: {
809
825
  [key: string]: GLTFAccessorPostprocessed;
810
826
  },
811
827
  primitive: GLTFMeshPrimitivePostprocessed,
812
- images: (TextureImageProperties | null)[]
828
+ images: (TextureImageProperties | null)[],
829
+ featureTexture: string | null
813
830
  ): NumberArray {
814
- const batchIds: NumberArray = handleBatchIdsExtensions(attributes, primitive, images);
831
+ const batchIds: NumberArray = handleBatchIdsExtensions(
832
+ attributes,
833
+ primitive,
834
+ images,
835
+ featureTexture
836
+ );
815
837
 
816
838
  if (batchIds.length) {
817
839
  return batchIds;
@@ -1451,17 +1473,17 @@ function generateBigUint64Array(featureIds: any[]): BigUint64Array {
1451
1473
 
1452
1474
  /**
1453
1475
  * Generates draco compressed geometry
1454
- * @param {Number} vertexCount
1455
- * @param {Object} convertedAttributes - get rid of this argument here
1456
- * @param {Object} attributes - geometry attributes to compress
1457
- * @param {string} dracoWorkerSoure - draco worker source code
1458
- * @returns {Promise<object>} - COmpressed geometry.
1476
+ * @param vertexCount
1477
+ * @param convertedAttributes - get rid of this argument here
1478
+ * @param attributes - geometry attributes to compress
1479
+ * @param libraries - dynamicaly loaded 3rd-party libraries
1480
+ * @returns - Compressed geometry.
1459
1481
  */
1460
1482
  async function generateCompressedGeometry(
1461
1483
  vertexCount: number,
1462
1484
  convertedAttributes: Record<string, any>,
1463
1485
  attributes: Record<string, any>,
1464
- dracoWorkerSoure: string
1486
+ libraries: Record<string, string>
1465
1487
  ): Promise<ArrayBuffer> {
1466
1488
  const {positions, normals, texCoords, colors, uvRegions, featureIds, faceRange} = attributes;
1467
1489
  const indices = new Uint32Array(vertexCount);
@@ -1510,12 +1532,17 @@ async function generateCompressedGeometry(
1510
1532
 
1511
1533
  return encode({attributes: compressedAttributes, indices}, DracoWriterWorker, {
1512
1534
  ...DracoWriterWorker.options,
1513
- source: dracoWorkerSoure,
1514
1535
  reuseWorkers: true,
1515
1536
  _nodeWorkers: true,
1537
+ modules: libraries,
1538
+ useLocalLibraries: true,
1516
1539
  draco: {
1517
1540
  method: 'MESH_SEQUENTIAL_ENCODING',
1518
1541
  attributesMetadata
1542
+ },
1543
+ ['draco-writer']: {
1544
+ // We need to load local fs workers because nodejs can't load workers from the Internet
1545
+ workerUrl: './modules/draco/dist/draco-writer-worker-node.js'
1519
1546
  }
1520
1547
  });
1521
1548
  }
@@ -1550,9 +1577,13 @@ function generateFeatureIndexAttribute(
1550
1577
  * Find property table in tile
1551
1578
  * For example it can be batchTable for b3dm files or property table in gLTF extension.
1552
1579
  * @param tileContent - 3DTiles tile content
1580
+ * @param metadataClass - - user selected feature metadata class name
1553
1581
  * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA
1554
1582
  */
1555
- export function getPropertyTable(tileContent: Tiles3DTileContent | null): FeatureTableJson | null {
1583
+ export function getPropertyTable(
1584
+ tileContent: Tiles3DTileContent | null,
1585
+ metadataClass?: string
1586
+ ): FeatureTableJson | null {
1556
1587
  if (!tileContent) {
1557
1588
  return null;
1558
1589
  }
@@ -1571,7 +1602,10 @@ export function getPropertyTable(tileContent: Tiles3DTileContent | null): Featur
1571
1602
  return null;
1572
1603
  }
1573
1604
  case EXT_FEATURE_METADATA: {
1574
- return getPropertyTableFromExtFeatureMetadata(extension as GLTF_EXT_feature_metadata_GLTF);
1605
+ return getPropertyTableFromExtFeatureMetadata(
1606
+ extension as GLTF_EXT_feature_metadata_GLTF,
1607
+ metadataClass
1608
+ );
1575
1609
  }
1576
1610
  default:
1577
1611
  return null;
@@ -1614,10 +1648,11 @@ function getPropertyTableExtension(tileContent: Tiles3DTileContent): {
1614
1648
 
1615
1649
  /**
1616
1650
  * Handle EXT_feature_metadata to get property table
1617
- * @param extension
1651
+ * @param extension - global level of EXT_FEATURE_METADATA extension
1618
1652
  */
1619
1653
  function getPropertyTableFromExtFeatureMetadata(
1620
- extension: GLTF_EXT_feature_metadata_GLTF
1654
+ extension: GLTF_EXT_feature_metadata_GLTF,
1655
+ metadataClass?: string
1621
1656
  ): FeatureTableJson | null {
1622
1657
  if (extension?.featureTables) {
1623
1658
  /**
@@ -1641,15 +1676,16 @@ function getPropertyTableFromExtFeatureMetadata(
1641
1676
  }
1642
1677
 
1643
1678
  if (extension?.featureTextures) {
1644
- /**
1645
- * Take only first feature texture to generate attributes storage info object.
1646
- * TODO: Think about getting data from all feature textures?
1647
- * It can be tricky just because 3dTiles is able to have multiple featureTextures.
1648
- * In I3S we should decide which featureTextures will be passed to geometry data.
1649
- */
1650
- const firstTextureName = Object.keys(extension.featureTextures)?.[0];
1651
- if (firstTextureName) {
1652
- const featureTable = extension?.featureTextures[firstTextureName];
1679
+ let featureTexture: string | undefined;
1680
+ for (const textureKey in extension.featureTextures) {
1681
+ const texture = extension.featureTextures[textureKey];
1682
+ if (texture.class === metadataClass) {
1683
+ featureTexture = textureKey;
1684
+ }
1685
+ }
1686
+
1687
+ if (typeof featureTexture === 'string') {
1688
+ const featureTable = extension?.featureTextures[featureTexture];
1653
1689
  const propertyTable = {};
1654
1690
 
1655
1691
  for (const propertyName in featureTable.properties) {
@@ -1,20 +1,21 @@
1
1
  import {Tiles3DTileContent} from '@loaders.gl/3d-tiles';
2
- import {GltfPrimitiveModeString, PreprocessData} from '../types';
3
- import {GLTF, GLTFLoader} from '@loaders.gl/gltf';
2
+ import {GLTFPrimitiveModeString, PreprocessData} from '../types';
3
+ import {GLTF, GLTFLoader, GLTF_EXT_feature_metadata_GLTF} from '@loaders.gl/gltf';
4
4
  import {parse} from '@loaders.gl/core';
5
+ import {EXT_FEATURE_METADATA} from '../../constants';
5
6
 
6
7
  /**
7
8
  * glTF primitive modes
8
9
  * @see https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode
9
10
  */
10
11
  export const GLTF_PRIMITIVE_MODES = [
11
- GltfPrimitiveModeString.POINTS, // 0
12
- GltfPrimitiveModeString.LINES, // 1
13
- GltfPrimitiveModeString.LINE_LOOP, // 2
14
- GltfPrimitiveModeString.LINE_STRIP, // 3
15
- GltfPrimitiveModeString.TRIANGLES, // 4
16
- GltfPrimitiveModeString.TRIANGLE_STRIP, // 5
17
- GltfPrimitiveModeString.TRIANGLE_FAN // 6
12
+ GLTFPrimitiveModeString.POINTS, // 0
13
+ GLTFPrimitiveModeString.LINES, // 1
14
+ GLTFPrimitiveModeString.LINE_LOOP, // 2
15
+ GLTFPrimitiveModeString.LINE_STRIP, // 3
16
+ GLTFPrimitiveModeString.TRIANGLES, // 4
17
+ GLTFPrimitiveModeString.TRIANGLE_STRIP, // 5
18
+ GLTFPrimitiveModeString.TRIANGLE_FAN // 6
18
19
  ];
19
20
 
20
21
  /**
@@ -26,11 +27,12 @@ export const GLTF_PRIMITIVE_MODES = [
26
27
  export const analyzeTileContent = async (
27
28
  tileContent: Tiles3DTileContent | null
28
29
  ): Promise<PreprocessData> => {
29
- const result: PreprocessData = {
30
- meshTopologyTypes: new Set()
30
+ const defaultResult = {
31
+ meshTopologyTypes: new Set<GLTFPrimitiveModeString>(),
32
+ metadataClasses: new Set<string>()
31
33
  };
32
34
  if (!tileContent?.gltfArrayBuffer) {
33
- return result;
35
+ return defaultResult;
34
36
  }
35
37
 
36
38
  const gltfData = await parse(tileContent.gltfArrayBuffer, GLTFLoader, {
@@ -39,11 +41,14 @@ export const analyzeTileContent = async (
39
41
  const gltf = gltfData.json;
40
42
 
41
43
  if (!gltf) {
42
- return result;
44
+ return defaultResult;
43
45
  }
44
- const meshTypes = getMeshTypesFromGltf(gltf);
45
- result.meshTopologyTypes = meshTypes;
46
- return result;
46
+ const meshTopologyTypes = getMeshTypesFromGltf(gltf);
47
+ const metadataClasses = getMetadataClassesFromGltf(gltf);
48
+ return {
49
+ meshTopologyTypes,
50
+ metadataClasses
51
+ };
47
52
  };
48
53
 
49
54
  /**
@@ -51,8 +56,8 @@ export const analyzeTileContent = async (
51
56
  * @param gltfJson - JSON part of GLB content
52
57
  * @returns array of mesh types found
53
58
  */
54
- const getMeshTypesFromGltf = (gltfJson: GLTF): Set<GltfPrimitiveModeString> => {
55
- const result: Set<GltfPrimitiveModeString> = new Set();
59
+ const getMeshTypesFromGltf = (gltfJson: GLTF): Set<GLTFPrimitiveModeString> => {
60
+ const result: Set<GLTFPrimitiveModeString> = new Set();
56
61
  for (const mesh of gltfJson.meshes || []) {
57
62
  for (const primitive of mesh.primitives) {
58
63
  let {mode} = primitive;
@@ -65,6 +70,26 @@ const getMeshTypesFromGltf = (gltfJson: GLTF): Set<GltfPrimitiveModeString> => {
65
70
  return result;
66
71
  };
67
72
 
73
+ /**
74
+ * Get feature metadata classes from glTF
75
+ * @param gltfJson - JSON part of GLB content
76
+ * @returns array of classes
77
+ */
78
+ const getMetadataClassesFromGltf = (gltfJson: GLTF): Set<string> => {
79
+ const result: Set<string> = new Set();
80
+
81
+ const classes = (gltfJson.extensions?.[EXT_FEATURE_METADATA] as GLTF_EXT_feature_metadata_GLTF)
82
+ ?.schema?.classes;
83
+
84
+ if (classes) {
85
+ for (const classKey of Object.keys(classes)) {
86
+ result.add(classKey);
87
+ }
88
+ }
89
+
90
+ return result;
91
+ };
92
+
68
93
  /**
69
94
  * Merge object2 into object1
70
95
  * @param object1
@@ -76,4 +101,9 @@ export const mergePreprocessData = (object1: PreprocessData, object2: Preprocess
76
101
  for (const type of object2.meshTopologyTypes) {
77
102
  object1.meshTopologyTypes.add(type);
78
103
  }
104
+
105
+ // Merge feature metadata classes
106
+ for (const metadataClass of object2.metadataClasses) {
107
+ object1.metadataClasses.add(metadataClass);
108
+ }
79
109
  };