@loaders.gl/tile-converter 4.0.0-alpha.22 → 4.0.0-alpha.24

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 (137) hide show
  1. package/dist/3d-tiles-converter/helpers/load-i3s.d.ts.map +1 -1
  2. package/dist/constants.d.ts +0 -2
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/converter.min.js +106 -106
  5. package/dist/dist.min.js +1883 -1241
  6. package/dist/es5/3d-tiles-converter/helpers/load-i3s.js.map +1 -1
  7. package/dist/es5/constants.js +1 -5
  8. package/dist/es5/constants.js.map +1 -1
  9. package/dist/es5/deps-installer/deps-installer.js +1 -1
  10. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js +26 -11
  11. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
  12. package/dist/es5/i3s-converter/helpers/feature-attributes.js +7 -17
  13. package/dist/es5/i3s-converter/helpers/feature-attributes.js.map +1 -1
  14. package/dist/es5/i3s-converter/helpers/geometry-attributes.js +83 -44
  15. package/dist/es5/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  16. package/dist/es5/i3s-converter/helpers/geometry-converter.js +70 -17
  17. package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
  18. package/dist/es5/i3s-converter/helpers/node-index-document.js +3 -2
  19. package/dist/es5/i3s-converter/helpers/node-index-document.js.map +1 -1
  20. package/dist/es5/i3s-converter/helpers/preprocess-3d-tiles.js +1 -2
  21. package/dist/es5/i3s-converter/helpers/preprocess-3d-tiles.js.map +1 -1
  22. package/dist/es5/i3s-converter/i3s-converter.js +36 -26
  23. package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
  24. package/dist/es5/i3s-converter/types.js.map +1 -1
  25. package/dist/es5/i3s-server/controllers/slpk-controller.js +2 -2
  26. package/dist/es5/i3s-server/controllers/slpk-controller.js.map +1 -1
  27. package/dist/es5/pgm-loader.js +11 -3
  28. package/dist/es5/pgm-loader.js.map +1 -1
  29. package/dist/es5/slpk-extractor/slpk-extractor.js +1 -1
  30. package/dist/es5/slpk-extractor/slpk-extractor.js.map +1 -1
  31. package/dist/esm/3d-tiles-converter/helpers/load-i3s.js.map +1 -1
  32. package/dist/esm/constants.js +0 -2
  33. package/dist/esm/constants.js.map +1 -1
  34. package/dist/esm/deps-installer/deps-installer.js +1 -1
  35. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js +21 -6
  36. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
  37. package/dist/esm/i3s-converter/helpers/feature-attributes.js +9 -7
  38. package/dist/esm/i3s-converter/helpers/feature-attributes.js.map +1 -1
  39. package/dist/esm/i3s-converter/helpers/geometry-attributes.js +76 -34
  40. package/dist/esm/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  41. package/dist/esm/i3s-converter/helpers/geometry-converter.js +66 -13
  42. package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
  43. package/dist/esm/i3s-converter/helpers/node-index-document.js +2 -1
  44. package/dist/esm/i3s-converter/helpers/node-index-document.js.map +1 -1
  45. package/dist/esm/i3s-converter/helpers/preprocess-3d-tiles.js +1 -1
  46. package/dist/esm/i3s-converter/helpers/preprocess-3d-tiles.js.map +1 -1
  47. package/dist/esm/i3s-converter/i3s-converter.js +20 -17
  48. package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
  49. package/dist/esm/i3s-converter/types.js.map +1 -1
  50. package/dist/esm/i3s-server/bin/i3s-server.min.js +71 -71
  51. package/dist/esm/i3s-server/controllers/slpk-controller.js +1 -1
  52. package/dist/esm/i3s-server/controllers/slpk-controller.js.map +1 -1
  53. package/dist/esm/pgm-loader.js +7 -4
  54. package/dist/esm/pgm-loader.js.map +1 -1
  55. package/dist/esm/slpk-extractor/slpk-extractor.js +2 -1
  56. package/dist/esm/slpk-extractor/slpk-extractor.js.map +1 -1
  57. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts.map +1 -1
  58. package/dist/i3s-converter/helpers/feature-attributes.d.ts +6 -6
  59. package/dist/i3s-converter/helpers/feature-attributes.d.ts.map +1 -1
  60. package/dist/i3s-converter/helpers/geometry-attributes.d.ts.map +1 -1
  61. package/dist/i3s-converter/helpers/geometry-converter.d.ts +2 -2
  62. package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -1
  63. package/dist/i3s-converter/helpers/node-index-document.d.ts.map +1 -1
  64. package/dist/i3s-converter/i3s-converter.d.ts +1 -1
  65. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
  66. package/dist/i3s-converter/types.d.ts +7 -4
  67. package/dist/i3s-converter/types.d.ts.map +1 -1
  68. package/dist/pgm-loader.d.ts +9 -2
  69. package/dist/pgm-loader.d.ts.map +1 -1
  70. package/dist/slpk-extractor/slpk-extractor.d.ts.map +1 -1
  71. package/dist/slpk-extractor.min.js +38 -38
  72. package/package.json +14 -14
  73. package/src/3d-tiles-converter/helpers/load-i3s.ts +1 -0
  74. package/src/constants.ts +0 -3
  75. package/src/i3s-converter/helpers/batch-ids-extensions.ts +53 -14
  76. package/src/i3s-converter/helpers/feature-attributes.ts +20 -15
  77. package/src/i3s-converter/helpers/geometry-attributes.ts +80 -50
  78. package/src/i3s-converter/helpers/geometry-converter.ts +153 -21
  79. package/src/i3s-converter/helpers/node-index-document.ts +5 -1
  80. package/src/i3s-converter/helpers/preprocess-3d-tiles.ts +1 -1
  81. package/src/i3s-converter/i3s-converter.ts +42 -17
  82. package/src/i3s-converter/types.ts +8 -4
  83. package/src/i3s-server/controllers/slpk-controller.ts +1 -1
  84. package/src/pgm-loader.ts +15 -7
  85. package/src/slpk-extractor/slpk-extractor.ts +2 -1
  86. package/dist/3d-tiles-converter/3d-tiles-converter.js +0 -279
  87. package/dist/3d-tiles-converter/helpers/b3dm-converter.js +0 -271
  88. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +0 -23
  89. package/dist/3d-tiles-converter/helpers/load-i3s.js +0 -42
  90. package/dist/3d-tiles-converter/helpers/texture-atlas.js +0 -54
  91. package/dist/3d-tiles-converter/json-templates/tileset.js +0 -43
  92. package/dist/bundle.js +0 -5
  93. package/dist/constants.js +0 -6
  94. package/dist/converter-cli.js +0 -222
  95. package/dist/deps-installer/deps-installer.js +0 -89
  96. package/dist/i3s-converter/helpers/batch-ids-extensions.js +0 -158
  97. package/dist/i3s-converter/helpers/coordinate-converter.js +0 -122
  98. package/dist/i3s-converter/helpers/create-scene-server-path.js +0 -28
  99. package/dist/i3s-converter/helpers/feature-attributes.js +0 -216
  100. package/dist/i3s-converter/helpers/geometry-attributes.js +0 -203
  101. package/dist/i3s-converter/helpers/geometry-converter.js +0 -1240
  102. package/dist/i3s-converter/helpers/gltf-attributes.js +0 -129
  103. package/dist/i3s-converter/helpers/load-3d-tiles.js +0 -99
  104. package/dist/i3s-converter/helpers/node-debug.js +0 -120
  105. package/dist/i3s-converter/helpers/node-index-document.js +0 -268
  106. package/dist/i3s-converter/helpers/node-pages.js +0 -316
  107. package/dist/i3s-converter/helpers/preprocess-3d-tiles.js +0 -100
  108. package/dist/i3s-converter/helpers/tileset-traversal.js +0 -29
  109. package/dist/i3s-converter/i3s-converter.js +0 -945
  110. package/dist/i3s-converter/json-templates/geometry-definitions.js +0 -87
  111. package/dist/i3s-converter/json-templates/layers.js +0 -139
  112. package/dist/i3s-converter/json-templates/metadata.js +0 -25
  113. package/dist/i3s-converter/json-templates/node.js +0 -89
  114. package/dist/i3s-converter/json-templates/scene-server.js +0 -31
  115. package/dist/i3s-converter/json-templates/shared-resources.js +0 -129
  116. package/dist/i3s-converter/json-templates/store.js +0 -103
  117. package/dist/i3s-converter/types.js +0 -17
  118. package/dist/i3s-server/app.js +0 -29
  119. package/dist/i3s-server/bin/www.js +0 -37
  120. package/dist/i3s-server/controllers/index-controller.js +0 -31
  121. package/dist/i3s-server/controllers/slpk-controller.js +0 -33
  122. package/dist/i3s-server/routes/index.js +0 -20
  123. package/dist/i3s-server/routes/slpk-router.js +0 -34
  124. package/dist/i3s-server/utils/create-scene-server.js +0 -22
  125. package/dist/i3s-server/utils/server-utils.js +0 -66
  126. package/dist/index.js +0 -10
  127. package/dist/lib/utils/cli-utils.js +0 -82
  128. package/dist/lib/utils/compress-util.js +0 -257
  129. package/dist/lib/utils/file-utils.js +0 -139
  130. package/dist/lib/utils/geometry-utils.js +0 -18
  131. package/dist/lib/utils/lod-conversion-utils.js +0 -76
  132. package/dist/lib/utils/queue.js +0 -18
  133. package/dist/lib/utils/statistic-utills.js +0 -64
  134. package/dist/lib/utils/write-queue.js +0 -80
  135. package/dist/pgm-loader.js +0 -24
  136. package/dist/slpk-extractor/slpk-extractor.js +0 -74
  137. package/dist/slpk-extractor-cli.js +0 -102
@@ -1,5 +1,7 @@
1
1
  import type {FeatureTableJson, Tiles3DTileContent} from '@loaders.gl/3d-tiles';
2
2
  import type {
3
+ GLTF_EXT_mesh_features,
4
+ GLTF_EXT_structural_metadata,
3
5
  GLTFAccessorPostprocessed,
4
6
  GLTFMaterialPostprocessed,
5
7
  GLTFNodePostprocessed,
@@ -47,7 +49,8 @@ import {GL} from '@loaders.gl/math';
47
49
  import type {GLTFAttributesData, TextureImageProperties, TypedArrayConstructor} from '../types';
48
50
  import {generateSyntheticIndices} from '../../lib/utils/geometry-utils';
49
51
  import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
50
- import {EXT_FEATURE_METADATA, EXT_MESH_FEATURES} from '../../constants';
52
+
53
+ import {EXT_MESH_FEATURES, EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA} from '@loaders.gl/gltf';
51
54
 
52
55
  // Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md
53
56
  const DEFAULT_ROUGHNESS_FACTOR = 1;
@@ -241,12 +244,18 @@ async function _makeNodeResources({
241
244
  const {faceRange, featureIds, positions, normals, colors, uvRegions, texCoords, featureCount} =
242
245
  generateAttributes(convertedAttributes);
243
246
 
244
- if (tileContent.batchTableJson) {
245
- makeFeatureIdsUnique(
247
+ let featureIdsMap: Record<string, number> = {};
248
+ if (propertyTable) {
249
+ /**
250
+ * 3DTiles has featureIndices unique only for one tile.
251
+ * In I3S featureIds are unique layer-wide. We create featureIds from all feature properties.
252
+ * If 3DTiles features has equal set of properties they are considered as same feature in I3S.
253
+ */
254
+ featureIdsMap = makeFeatureIdsUnique(
246
255
  featureIds,
247
256
  convertedAttributes.featureIndices,
248
257
  featuresHashArray,
249
- tileContent.batchTableJson
258
+ propertyTable
250
259
  );
251
260
  }
252
261
 
@@ -288,6 +297,7 @@ async function _makeNodeResources({
288
297
  if (attributeStorageInfo && propertyTable) {
289
298
  attributes = convertPropertyTableToAttributeBuffers(
290
299
  featureIds,
300
+ featureIdsMap,
291
301
  propertyTable,
292
302
  attributeStorageInfo
293
303
  );
@@ -1249,17 +1259,18 @@ function generateImageId(texture: GLTFTexturePostprocessed, nodeId: number) {
1249
1259
  * @param featureIndices
1250
1260
  * @param featuresHashArray
1251
1261
  * @param batchTable
1252
- * @returns {void}
1262
+ * @returns propertyTable indices to map featureIds
1253
1263
  */
1254
1264
  function makeFeatureIdsUnique(
1255
1265
  featureIds: number[],
1256
1266
  featureIndices: number[],
1257
1267
  featuresHashArray: string[],
1258
1268
  batchTable: {[key: string]: any}
1259
- ) {
1269
+ ): Record<string, number> {
1260
1270
  const replaceMap = getFeaturesReplaceMap(featureIds, batchTable, featuresHashArray);
1261
1271
  replaceIndicesByUnique(featureIndices, replaceMap);
1262
1272
  replaceIndicesByUnique(featureIds, replaceMap);
1273
+ return replaceMap;
1263
1274
  }
1264
1275
 
1265
1276
  /**
@@ -1273,8 +1284,8 @@ function getFeaturesReplaceMap(
1273
1284
  featureIds: any[],
1274
1285
  batchTable: object,
1275
1286
  featuresHashArray: any[]
1276
- ): Record<string, any> {
1277
- const featureMap: Record<string, any> = {};
1287
+ ): Record<string, number> {
1288
+ const featureMap: Record<string, number> = {};
1278
1289
 
1279
1290
  for (let index = 0; index < featureIds.length; index++) {
1280
1291
  const oldFeatureId = featureIds[index];
@@ -1326,7 +1337,7 @@ function getOrCreateUniqueFeatureId(
1326
1337
  * @param featureMap
1327
1338
  * @returns
1328
1339
  */
1329
- function replaceIndicesByUnique(indicesArray: any[], featureMap: Record<string, []>) {
1340
+ function replaceIndicesByUnique(indicesArray: number[], featureMap: Record<string, number>) {
1330
1341
  for (let index = 0; index < indicesArray.length; index++) {
1331
1342
  indicesArray[index] = featureMap[indicesArray[index]];
1332
1343
  }
@@ -1341,6 +1352,7 @@ function replaceIndicesByUnique(indicesArray: any[], featureMap: Record<string,
1341
1352
  */
1342
1353
  function convertPropertyTableToAttributeBuffers(
1343
1354
  featureIds: number[],
1355
+ featureIdsMap: Record<string, number>,
1344
1356
  propertyTable: FeatureTableJson,
1345
1357
  attributeStorageInfo: AttributeStorageInfo[]
1346
1358
  ): any[] {
@@ -1348,7 +1360,7 @@ function convertPropertyTableToAttributeBuffers(
1348
1360
 
1349
1361
  const needFlattenPropertyTable = checkPropertiesLength(featureIds, propertyTable);
1350
1362
  const properties = needFlattenPropertyTable
1351
- ? flattenPropertyTableByFeatureIds(featureIds, propertyTable)
1363
+ ? flattenPropertyTableByFeatureIds(featureIdsMap, propertyTable)
1352
1364
  : propertyTable;
1353
1365
 
1354
1366
  const propertyTableWithObjectIds = {
@@ -1358,10 +1370,12 @@ function convertPropertyTableToAttributeBuffers(
1358
1370
 
1359
1371
  for (const propertyName in propertyTableWithObjectIds) {
1360
1372
  const type = getAttributeType(propertyName, attributeStorageInfo);
1361
- const value = propertyTableWithObjectIds[propertyName];
1362
- const attributeBuffer = generateAttributeBuffer(type, value);
1373
+ if (type) {
1374
+ const value = propertyTableWithObjectIds[propertyName];
1375
+ const attributeBuffer = generateAttributeBuffer(type, value);
1363
1376
 
1364
- attributeBuffers.push(attributeBuffer);
1377
+ attributeBuffers.push(attributeBuffer);
1378
+ }
1365
1379
  }
1366
1380
 
1367
1381
  return attributeBuffers;
@@ -1401,6 +1415,20 @@ function generateAttributeBuffer(type: string, value: any): ArrayBuffer {
1401
1415
  */
1402
1416
  function getAttributeType(key: string, attributeStorageInfo: any[]): string {
1403
1417
  const attribute = attributeStorageInfo.find((attr) => attr.name === key);
1418
+ if (!attribute) {
1419
+ console.error(
1420
+ `attribute is null, key=${key}, attributeStorageInfo=${JSON.stringify(
1421
+ attributeStorageInfo,
1422
+ null,
1423
+ 2
1424
+ )}`
1425
+ );
1426
+ return '';
1427
+ }
1428
+ if (!attribute.attributeValues) {
1429
+ console.error(`attributeValues is null, attribute=${attribute}`);
1430
+ return '';
1431
+ }
1404
1432
  return attribute.attributeValues.valueType;
1405
1433
  }
1406
1434
 
@@ -1577,8 +1605,8 @@ function generateFeatureIndexAttribute(
1577
1605
  * Find property table in tile
1578
1606
  * For example it can be batchTable for b3dm files or property table in gLTF extension.
1579
1607
  * @param tileContent - 3DTiles tile content
1580
- * @param metadataClass - - user selected feature metadata class name
1581
- * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA
1608
+ * @param metadataClass - user selected feature metadata class name
1609
+ * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA, EXT_MESH_FEATURES or EXT_STRUCTURAL_METADATA
1582
1610
  */
1583
1611
  export function getPropertyTable(
1584
1612
  tileContent: Tiles3DTileContent | null,
@@ -1587,7 +1615,7 @@ export function getPropertyTable(
1587
1615
  if (!tileContent) {
1588
1616
  return null;
1589
1617
  }
1590
-
1618
+ let propertyTable: FeatureTableJson | null;
1591
1619
  const batchTableJson = tileContent?.batchTableJson;
1592
1620
 
1593
1621
  if (batchTableJson) {
@@ -1598,14 +1626,25 @@ export function getPropertyTable(
1598
1626
 
1599
1627
  switch (extensionName) {
1600
1628
  case EXT_MESH_FEATURES: {
1601
- console.warn('The I3S converter does not yet support the EXT_mesh_features extension');
1602
- return null;
1629
+ propertyTable = getPropertyTableFromExtMeshFeatures(
1630
+ extension as GLTF_EXT_mesh_features,
1631
+ metadataClass
1632
+ );
1633
+ return propertyTable;
1634
+ }
1635
+ case EXT_STRUCTURAL_METADATA: {
1636
+ propertyTable = getPropertyTableFromExtStructuralMetadata(
1637
+ extension as GLTF_EXT_structural_metadata,
1638
+ metadataClass
1639
+ );
1640
+ return propertyTable;
1603
1641
  }
1604
1642
  case EXT_FEATURE_METADATA: {
1605
- return getPropertyTableFromExtFeatureMetadata(
1643
+ propertyTable = getPropertyTableFromExtFeatureMetadata(
1606
1644
  extension as GLTF_EXT_feature_metadata_GLTF,
1607
1645
  metadataClass
1608
1646
  );
1647
+ return propertyTable;
1609
1648
  }
1610
1649
  default:
1611
1650
  return null;
@@ -1618,9 +1657,18 @@ export function getPropertyTable(
1618
1657
  */
1619
1658
  function getPropertyTableExtension(tileContent: Tiles3DTileContent): {
1620
1659
  extensionName: null | string;
1621
- extension: string | GLTF_EXT_feature_metadata_GLTF | null;
1660
+ extension:
1661
+ | string
1662
+ | GLTF_EXT_feature_metadata_GLTF
1663
+ | GLTF_EXT_structural_metadata
1664
+ | GLTF_EXT_mesh_features
1665
+ | null;
1622
1666
  } {
1623
- const extensionsWithPropertyTables = [EXT_FEATURE_METADATA, EXT_MESH_FEATURES];
1667
+ const extensionsWithPropertyTables = [
1668
+ EXT_FEATURE_METADATA,
1669
+ EXT_STRUCTURAL_METADATA,
1670
+ EXT_MESH_FEATURES
1671
+ ];
1624
1672
  const extensionsUsed = tileContent?.gltf?.extensionsUsed;
1625
1673
 
1626
1674
  if (!extensionsUsed) {
@@ -1649,6 +1697,8 @@ function getPropertyTableExtension(tileContent: Tiles3DTileContent): {
1649
1697
  /**
1650
1698
  * Handle EXT_feature_metadata to get property table
1651
1699
  * @param extension - global level of EXT_FEATURE_METADATA extension
1700
+ * @param metadataClass - user selected feature metadata class name
1701
+ * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
1652
1702
  */
1653
1703
  function getPropertyTableFromExtFeatureMetadata(
1654
1704
  extension: GLTF_EXT_feature_metadata_GLTF,
@@ -1701,3 +1751,85 @@ function getPropertyTableFromExtFeatureMetadata(
1701
1751
  );
1702
1752
  return null;
1703
1753
  }
1754
+
1755
+ /**
1756
+ * Handle EXT_structural_metadata to get property table
1757
+ * @param extension - global level of EXT_STRUCTURAL_METADATA extension
1758
+ * @param metadataClass - user selected feature metadata class name
1759
+ * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
1760
+ */
1761
+ function getPropertyTableFromExtStructuralMetadata(
1762
+ extension: GLTF_EXT_structural_metadata,
1763
+ metadataClass?: string
1764
+ ): FeatureTableJson | null {
1765
+ if (extension?.propertyTables) {
1766
+ /**
1767
+ * Take only first feature table to generate attributes storage info object.
1768
+ * TODO: Think about getting data from all feature tables?
1769
+ * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables.
1770
+ * In I3S we should decide which featureIds attribute will be passed to geometry data.
1771
+ */
1772
+ const firstPropertyTable = extension?.propertyTables[0];
1773
+ const propertyTableWithData = {};
1774
+
1775
+ for (const propertyName in firstPropertyTable.properties) {
1776
+ propertyTableWithData[propertyName] = firstPropertyTable.properties[propertyName].data;
1777
+ }
1778
+
1779
+ return propertyTableWithData;
1780
+ }
1781
+
1782
+ if (extension?.propertyTextures) {
1783
+ /**
1784
+ * Take only first feature table to generate attributes storage info object.
1785
+ * TODO: Think about getting data from all feature tables?
1786
+ * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables.
1787
+ * In I3S we should decide which featureIds attribute will be passed to geometry data.
1788
+ */
1789
+ if (extension?.propertyTextures) {
1790
+ const firstPropertyTexture = extension?.propertyTextures[0];
1791
+ const propertyTableWithData = {};
1792
+
1793
+ for (const propertyName in firstPropertyTexture.properties) {
1794
+ propertyTableWithData[propertyName] = firstPropertyTexture.properties[propertyName].data;
1795
+ }
1796
+
1797
+ return propertyTableWithData;
1798
+ }
1799
+ }
1800
+
1801
+ console.warn(
1802
+ "The I3S converter couldn't handle EXT_structural_metadata extension: There is neither propertyTables, no propertyTextures in the extension."
1803
+ );
1804
+ return null;
1805
+ }
1806
+
1807
+ /**
1808
+ * Handle EXT_mesh_features to get property table
1809
+ * @param extension - global level of EXT_MESH_FEATURES extension
1810
+ * @param metadataClass - user selected feature metadata class name
1811
+ * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
1812
+ */
1813
+ function getPropertyTableFromExtMeshFeatures(
1814
+ extension: GLTF_EXT_mesh_features,
1815
+ metadataClass?: string
1816
+ ): FeatureTableJson | null {
1817
+ if (extension?.featureIds) {
1818
+ const firstFeatureId = extension?.featureIds[0];
1819
+ const propertyTableWithData = {};
1820
+
1821
+ // When firstFeatureId.propertyTable is defined, the property data will be taken from EXT_structural_metadata extension
1822
+ if (!firstFeatureId.propertyTable) {
1823
+ console.warn(
1824
+ 'Should be implemented as we have the tileset with Ext_mesh_features not linked with EXT_structural_metadata extension'
1825
+ );
1826
+ }
1827
+
1828
+ return propertyTableWithData;
1829
+ }
1830
+
1831
+ console.warn(
1832
+ "The I3S converter couldn't handle EXT_mesh_features extension: There is no featureIds in the extension."
1833
+ );
1834
+ return null;
1835
+ }
@@ -323,7 +323,11 @@ export class NodeIndexDocument {
323
323
  parentNode.converter.layers0?.attributeStorageInfo?.length
324
324
  ) {
325
325
  node.attributeData = [];
326
- for (let index = 0; index < attributes.length; index++) {
326
+ const minimumLength =
327
+ attributes.length < parentNode.converter.layers0.attributeStorageInfo.length
328
+ ? attributes.length
329
+ : parentNode.converter.layers0.attributeStorageInfo.length;
330
+ for (let index = 0; index < minimumLength; index++) {
327
331
  const folderName = parentNode.converter.layers0.attributeStorageInfo[index].key;
328
332
  node.attributeData.push({href: `./attributes/${folderName}/0`});
329
333
  }
@@ -2,7 +2,7 @@ import {Tiles3DTileContent} from '@loaders.gl/3d-tiles';
2
2
  import {GLTFPrimitiveModeString, PreprocessData} from '../types';
3
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
+ import {EXT_FEATURE_METADATA} from '@loaders.gl/gltf';
6
6
 
7
7
  /**
8
8
  * glTF primitive modes
@@ -12,7 +12,8 @@ import type {
12
12
  SceneLayer3D,
13
13
  BoundingVolumes,
14
14
  MaxScreenThresholdSQ,
15
- NodeInPage
15
+ NodeInPage,
16
+ AttributeStorageInfo
16
17
  } from '@loaders.gl/i3s';
17
18
  import {load, encode, isBrowser} from '@loaders.gl/core';
18
19
  import {CesiumIonLoader, Tiles3DLoader} from '@loaders.gl/3d-tiles';
@@ -649,7 +650,14 @@ export default class I3SConverter {
649
650
 
650
651
  const propertyTable = getPropertyTable(tileContent, this.options.metadataClass);
651
652
 
652
- if (propertyTable && !this.layers0?.attributeStorageInfo?.length) {
653
+ if (propertyTable) {
654
+ /*
655
+ Call the convertion procedure even if the node attributes have been already created.
656
+ We will append new attributes only in case the property table is updated.
657
+ According to ver 1.9 (see https://github.com/Esri/i3s-spec/blob/master/docs/1.9/attributeStorageInfo.cmn.md):
658
+ "The attributeStorageInfo object describes the structure of the binary attribute data resource of a layer, which is the same for every node in the layer."
659
+ But the specification of ver 2.1 doesn't have such a requirement ("...the same for every node...")
660
+ */
653
661
  this._convertPropertyTableToNodeAttributes(propertyTable);
654
662
  }
655
663
 
@@ -735,7 +743,7 @@ export default class I3SConverter {
735
743
  * @param boundingVolume - initialized bounding volume of the source tile
736
744
  * @param tileContent - content of the source tile
737
745
  * @param parentId - id of parent node in node pages
738
- * @param propertyTable - batch table from b3dm / feature properties from EXT_FEATURE_METADATA
746
+ * @param propertyTable - batch table from b3dm / feature properties from EXT_FEATURE_METADATA, EXT_MESH_FEATURES or EXT_STRUCTURAL_METADATA
739
747
  * @returns - converted node resources
740
748
  */
741
749
  private async _convertResources(
@@ -1068,7 +1076,12 @@ export default class I3SConverter {
1068
1076
  slpkChildPath: string
1069
1077
  ): Promise<void> {
1070
1078
  if (attributes?.length && this.layers0?.attributeStorageInfo?.length) {
1071
- for (let index = 0; index < attributes.length; index++) {
1079
+ const minimumLength =
1080
+ attributes.length < this.layers0.attributeStorageInfo.length
1081
+ ? attributes.length
1082
+ : this.layers0.attributeStorageInfo.length;
1083
+
1084
+ for (let index = 0; index < minimumLength; index++) {
1072
1085
  const folderName = this.layers0.attributeStorageInfo[index].key;
1073
1086
  const fileBuffer = new Uint8Array(attributes[index]);
1074
1087
 
@@ -1150,19 +1163,31 @@ export default class I3SConverter {
1150
1163
  };
1151
1164
 
1152
1165
  for (const key in propertyTableWithObjectId) {
1153
- const firstAttribute = propertyTableWithObjectId[key][0];
1154
- const attributeType = getAttributeType(key, firstAttribute);
1155
-
1156
- const storageAttribute = createdStorageAttribute(attributeIndex, key, attributeType);
1157
- const fieldAttributeType = getFieldAttributeType(attributeType);
1158
- const fieldAttribute = createFieldAttribute(key, fieldAttributeType);
1159
- const popupInfo = createPopupInfo(propertyTableWithObjectId);
1160
-
1161
- this.layers0!.attributeStorageInfo!.push(storageAttribute);
1162
- this.layers0!.fields!.push(fieldAttribute);
1163
- this.layers0!.popupInfo = popupInfo;
1164
- this.layers0!.layerType = _3D_OBJECT_LAYER_TYPE;
1165
-
1166
+ /*
1167
+ We will append new attributes only in case the property table is updated.
1168
+ According to ver 1.9 (see https://github.com/Esri/i3s-spec/blob/master/docs/1.9/attributeStorageInfo.cmn.md):
1169
+ "The attributeStorageInfo object describes the structure of the binary attribute data resource of a layer, which is the same for every node in the layer."
1170
+ But the specification of ver 2.1 doesn't have such a requirement ("...the same for every node...")
1171
+ */
1172
+ const found = this.layers0!.attributeStorageInfo!.find((element) => element.name === key);
1173
+ if (!found) {
1174
+ const firstAttribute = propertyTableWithObjectId[key][0];
1175
+ const attributeType = getAttributeType(key, firstAttribute);
1176
+
1177
+ const storageAttribute: AttributeStorageInfo = createdStorageAttribute(
1178
+ attributeIndex,
1179
+ key,
1180
+ attributeType
1181
+ );
1182
+ const fieldAttributeType = getFieldAttributeType(attributeType);
1183
+ const fieldAttribute = createFieldAttribute(key, fieldAttributeType);
1184
+ const popupInfo = createPopupInfo(propertyTableWithObjectId);
1185
+
1186
+ this.layers0!.attributeStorageInfo!.push(storageAttribute);
1187
+ this.layers0!.fields!.push(fieldAttribute);
1188
+ this.layers0!.popupInfo = popupInfo;
1189
+ this.layers0!.layerType = _3D_OBJECT_LAYER_TYPE;
1190
+ }
1166
1191
  attributeIndex += 1;
1167
1192
  }
1168
1193
  }
@@ -106,10 +106,8 @@ export type GeometryAttributes = {
106
106
  featureCount: number;
107
107
  };
108
108
 
109
- /** Geometry attributes specific for the particular feature */
110
- export type GroupedByFeatureIdAttributes = {
111
- /** Feature Id */
112
- featureId: number;
109
+ /** Geometry attributes applicable for reordering by featureId */
110
+ export type GroupedAttributes = {
113
111
  /** POSITION attribute value */
114
112
  positions: Float32Array;
115
113
  /** NORMAL attribute value */
@@ -122,6 +120,12 @@ export type GroupedByFeatureIdAttributes = {
122
120
  texCoords: Float32Array;
123
121
  };
124
122
 
123
+ /** Geometry attributes specific for the particular feature */
124
+ export type GroupedByFeatureIdAttributes = GroupedAttributes & {
125
+ /** Feature Id */
126
+ featureId: number;
127
+ };
128
+
125
129
  /** Shared resources made from GLTF material */
126
130
  export type SharedResourcesArrays = {
127
131
  /** material definitions list https://github.com/Esri/i3s-spec/blob/master/docs/1.8/materialDefinitionInfo.cmn.md */
@@ -1,6 +1,6 @@
1
1
  import '@loaders.gl/polyfills';
2
2
  import {parseSLPK} from '@loaders.gl/i3s';
3
- import {FileHandleFile} from '@loaders.gl/zip';
3
+ import {FileHandleFile} from '@loaders.gl/loader-utils';
4
4
 
5
5
  let slpkArchive;
6
6
 
package/src/pgm-loader.ts CHANGED
@@ -1,24 +1,32 @@
1
- import type {LoaderWithParser} from '@loaders.gl/loader-utils';
2
- import {parsePGM} from '@math.gl/geoid';
1
+ import type {LoaderWithParser, LoaderOptions} from '@loaders.gl/loader-utils';
2
+ import {Geoid, parsePGM} from '@math.gl/geoid';
3
3
 
4
4
  // __VERSION__ is injected by babel-plugin-version-inline
5
5
  // @ts-ignore TS2304: Cannot find name '__VERSION__'.
6
6
  const VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';
7
7
 
8
+ export {Geoid};
9
+
10
+ export type PGMLoaderOptions = LoaderOptions & {
11
+ pgm?: {
12
+ cubic?: boolean;
13
+ };
14
+ };
15
+
8
16
  /**
9
17
  * Loader for PGM - Netpbm grayscale image format
10
18
  */
11
- export const PGMLoader: LoaderWithParser = {
19
+ export const PGMLoader: LoaderWithParser<Geoid, never, PGMLoaderOptions> = {
12
20
  name: 'PGM - Netpbm grayscale image format',
13
21
  id: 'pgm',
14
22
  module: 'tile-converter',
15
23
  version: VERSION,
16
24
  mimeTypes: ['image/x-portable-graymap'],
17
- // @ts-expect-error LoaderOptions does not have cubic parameter
18
- parse: async (arrayBuffer, options) => parsePGM(new Uint8Array(arrayBuffer), options),
25
+ parse: async (arrayBuffer, options) => parsePGM(new Uint8Array(arrayBuffer), options?.pgm || {}),
19
26
  extensions: ['pgm'],
20
27
  options: {
21
- // TODO - use pgm namespace
22
- cubic: false
28
+ pgm: {
29
+ cubic: false
30
+ }
23
31
  }
24
32
  };
@@ -2,7 +2,8 @@ import {isBrowser} from '@loaders.gl/core';
2
2
 
3
3
  import {BROWSER_ERROR_MESSAGE} from '../constants';
4
4
  import {path} from '@loaders.gl/loader-utils';
5
- import {FileHandleFile, parseZipLocalFileHeader} from '@loaders.gl/zip';
5
+ import {FileHandleFile} from '@loaders.gl/loader-utils';
6
+ import {parseZipLocalFileHeader} from '@loaders.gl/zip';
6
7
  import {GZipCompression} from '@loaders.gl/compression';
7
8
  import {writeFile} from '../lib/utils/file-utils';
8
9