@loaders.gl/tile-converter 3.3.0-alpha.1 → 3.3.0-alpha.2

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 (67) hide show
  1. package/dist/3d-tiles-attributes-worker.js +3 -3
  2. package/dist/3d-tiles-attributes-worker.js.map +1 -1
  3. package/dist/converter.min.js +10 -10
  4. package/dist/dist.min.js +791 -554
  5. package/dist/es5/3d-tiles-attributes-worker.js +1 -1
  6. package/dist/es5/i3s-attributes-worker.js +1 -1
  7. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js +15 -4
  8. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
  9. package/dist/es5/i3s-converter/helpers/feature-attributes.js +60 -0
  10. package/dist/es5/i3s-converter/helpers/feature-attributes.js.map +1 -0
  11. package/dist/es5/i3s-converter/helpers/geometry-attributes.js +39 -7
  12. package/dist/es5/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  13. package/dist/es5/i3s-converter/helpers/geometry-converter.js +161 -49
  14. package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
  15. package/dist/es5/i3s-converter/helpers/node-pages.js +102 -46
  16. package/dist/es5/i3s-converter/helpers/node-pages.js.map +1 -1
  17. package/dist/es5/i3s-converter/i3s-converter.js +235 -141
  18. package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
  19. package/dist/es5/lib/utils/write-queue.js +66 -28
  20. package/dist/es5/lib/utils/write-queue.js.map +1 -1
  21. package/dist/es5/pgm-loader.js +1 -1
  22. package/dist/esm/3d-tiles-attributes-worker.js +1 -1
  23. package/dist/esm/i3s-attributes-worker.js +1 -1
  24. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js +15 -4
  25. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
  26. package/dist/esm/i3s-converter/helpers/feature-attributes.js +34 -0
  27. package/dist/esm/i3s-converter/helpers/feature-attributes.js.map +1 -0
  28. package/dist/esm/i3s-converter/helpers/geometry-attributes.js +23 -7
  29. package/dist/esm/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  30. package/dist/esm/i3s-converter/helpers/geometry-converter.js +132 -30
  31. package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
  32. package/dist/esm/i3s-converter/helpers/node-pages.js +3 -3
  33. package/dist/esm/i3s-converter/helpers/node-pages.js.map +1 -1
  34. package/dist/esm/i3s-converter/i3s-converter.js +32 -42
  35. package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
  36. package/dist/esm/lib/utils/write-queue.js +10 -0
  37. package/dist/esm/lib/utils/write-queue.js.map +1 -1
  38. package/dist/esm/pgm-loader.js +1 -1
  39. package/dist/i3s-attributes-worker.js +3 -3
  40. package/dist/i3s-attributes-worker.js.map +2 -2
  41. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts.map +1 -1
  42. package/dist/i3s-converter/helpers/batch-ids-extensions.js +12 -1
  43. package/dist/i3s-converter/helpers/feature-attributes.d.ts +24 -0
  44. package/dist/i3s-converter/helpers/feature-attributes.d.ts.map +1 -0
  45. package/dist/i3s-converter/helpers/feature-attributes.js +55 -0
  46. package/dist/i3s-converter/helpers/geometry-attributes.js +26 -7
  47. package/dist/i3s-converter/helpers/geometry-converter.d.ts +9 -2
  48. package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -1
  49. package/dist/i3s-converter/helpers/geometry-converter.js +124 -33
  50. package/dist/i3s-converter/helpers/node-pages.js +3 -3
  51. package/dist/i3s-converter/i3s-converter.d.ts +7 -14
  52. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
  53. package/dist/i3s-converter/i3s-converter.js +56 -50
  54. package/dist/i3s-converter/types.d.ts +0 -48
  55. package/dist/i3s-converter/types.d.ts.map +1 -1
  56. package/dist/lib/utils/write-queue.d.ts +1 -0
  57. package/dist/lib/utils/write-queue.d.ts.map +1 -1
  58. package/dist/lib/utils/write-queue.js +13 -0
  59. package/package.json +15 -15
  60. package/src/i3s-converter/helpers/batch-ids-extensions.ts +22 -5
  61. package/src/i3s-converter/helpers/feature-attributes.ts +65 -0
  62. package/src/i3s-converter/helpers/geometry-attributes.ts +30 -7
  63. package/src/i3s-converter/helpers/geometry-converter.ts +161 -37
  64. package/src/i3s-converter/helpers/node-pages.ts +3 -3
  65. package/src/i3s-converter/i3s-converter.ts +41 -51
  66. package/src/i3s-converter/types.ts +0 -51
  67. package/src/lib/utils/write-queue.ts +12 -0
@@ -1,4 +1,23 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
2
21
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
22
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
23
  };
@@ -15,7 +34,7 @@ const node_pages_1 = __importDefault(require("./helpers/node-pages"));
15
34
  const file_utils_1 = require("../lib/utils/file-utils");
16
35
  const compress_util_1 = require("../lib/utils/compress-util");
17
36
  const statistic_utills_1 = require("../lib/utils/statistic-utills");
18
- const geometry_converter_1 = __importDefault(require("./helpers/geometry-converter"));
37
+ const geometry_converter_1 = __importStar(require("./helpers/geometry-converter"));
19
38
  const coordinate_converter_1 = require("./helpers/coordinate-converter");
20
39
  const create_scene_server_path_1 = require("./helpers/create-scene-server-path");
21
40
  const lod_conversion_utils_1 = require("../lib/utils/lod-conversion-utils");
@@ -240,13 +259,13 @@ class I3SConverter {
240
259
  const [child] = await this._createNode(root0, sourceRootTile, parentId, 0);
241
260
  const childPath = (0, path_1.join)(this.layers0Path, 'nodes', child.path);
242
261
  if (this.options.slpk) {
243
- this.writeQueue.enqueue({
262
+ await this.writeQueue.enqueue({
244
263
  archiveKey: 'nodes/1/3dNodeIndexDocument.json.gz',
245
264
  writePromise: (0, file_utils_1.writeFileForSlpk)(childPath, JSON.stringify(child), '3dNodeIndexDocument.json')
246
265
  });
247
266
  }
248
267
  else {
249
- this.writeQueue.enqueue({ writePromise: (0, file_utils_1.writeFile)(childPath, JSON.stringify(child)) });
268
+ await this.writeQueue.enqueue({ writePromise: (0, file_utils_1.writeFile)(childPath, JSON.stringify(child)) });
250
269
  }
251
270
  }
252
271
  else {
@@ -264,13 +283,13 @@ class I3SConverter {
264
283
  */
265
284
  async _writeLayers0() {
266
285
  if (this.options.slpk) {
267
- this.writeQueue.enqueue({
286
+ await this.writeQueue.enqueue({
268
287
  archiveKey: '3dSceneLayer.json.gz',
269
288
  writePromise: (0, file_utils_1.writeFileForSlpk)(this.layers0Path, JSON.stringify(this.layers0), '3dSceneLayer.json')
270
289
  });
271
290
  }
272
291
  else {
273
- this.writeQueue.enqueue({
292
+ await this.writeQueue.enqueue({
274
293
  writePromise: (0, file_utils_1.writeFile)(this.layers0Path, JSON.stringify(this.layers0))
275
294
  });
276
295
  }
@@ -280,13 +299,13 @@ class I3SConverter {
280
299
  */
281
300
  async _writeNodeIndexDocument(root0, nodePath, rootPath) {
282
301
  if (this.options.slpk) {
283
- this.writeQueue.enqueue({
302
+ await this.writeQueue.enqueue({
284
303
  archiveKey: `nodes/${nodePath}/3dNodeIndexDocument.json.gz`,
285
304
  writePromise: (0, file_utils_1.writeFileForSlpk)(rootPath, JSON.stringify(root0), '3dNodeIndexDocument.json')
286
305
  });
287
306
  }
288
307
  else {
289
- this.writeQueue.enqueue({ writePromise: (0, file_utils_1.writeFile)(rootPath, JSON.stringify(root0)) });
308
+ await this.writeQueue.enqueue({ writePromise: (0, file_utils_1.writeFile)(rootPath, JSON.stringify(root0)) });
290
309
  }
291
310
  }
292
311
  /**
@@ -426,11 +445,11 @@ class I3SConverter {
426
445
  await this._updateTilesetOptions();
427
446
  await this.sourceTileset._loadTile(sourceTile);
428
447
  let boundingVolumes = (0, coordinate_converter_1.createBoundingVolumes)(sourceTile, this.geoidHeightModel);
429
- const batchTable = sourceTile?.content?.batchTableJson;
430
- if (batchTable) {
431
- this._convertAttributeStorageInfo(sourceTile.content);
448
+ const propertyTable = (0, geometry_converter_1.getPropertyTable)(sourceTile);
449
+ if (propertyTable && !this.layers0?.attributeStorageInfo?.length) {
450
+ this._convertPropertyTableToNodeAttributes(propertyTable);
432
451
  }
433
- const resourcesData = await this._convertResources(sourceTile);
452
+ const resourcesData = await this._convertResources(sourceTile, propertyTable);
434
453
  const nodes = [];
435
454
  const nodesInPage = [];
436
455
  const emptyResources = {
@@ -474,19 +493,6 @@ class I3SConverter {
474
493
  });
475
494
  return nodes;
476
495
  }
477
- /**
478
- * Convert attributesStorageInfo https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md
479
- * from B3DM batch table
480
- * @param sourceTileContent - tile content of 3DTile
481
- * @return {void}
482
- */
483
- _convertAttributeStorageInfo(sourceTileContent) {
484
- // In legacy b3dm files sometimes sourceTileContent is null.
485
- const batchTable = sourceTileContent && sourceTileContent.batchTableJson;
486
- if (batchTable && !this.layers0?.attributeStorageInfo?.length) {
487
- this._convertBatchTableInfoToNodeAttributes(batchTable);
488
- }
489
- }
490
496
  /**
491
497
  * Convert tile to one or more I3S nodes
492
498
  * @param sourceTile - source tile (3DTile)
@@ -499,11 +505,11 @@ class I3SConverter {
499
505
  * result.attributes - feature attributes
500
506
  * result.featureCount - number of features
501
507
  */
502
- async _convertResources(sourceTile) {
508
+ async _convertResources(sourceTile, propertyTable) {
503
509
  if (!this.isContentSupported(sourceTile)) {
504
510
  return null;
505
511
  }
506
- const resourcesData = await (0, geometry_converter_1.default)(sourceTile.content, Number(this.nodePages.nodesCounter), this.featuresHashArray, this.layers0?.attributeStorageInfo, this.options.draco, this.generateBoundingVolumes, this.geoidHeightModel, this.workerSource);
512
+ const resourcesData = await (0, geometry_converter_1.default)(sourceTile.content, Number(this.nodePages.nodesCounter), propertyTable, this.featuresHashArray, this.layers0?.attributeStorageInfo, this.options.draco, this.generateBoundingVolumes, this.geoidHeightModel, this.workerSource);
507
513
  return resourcesData;
508
514
  }
509
515
  /**
@@ -636,28 +642,28 @@ class I3SConverter {
636
642
  async _writeGeometries(geometryBuffer, compressedGeometry, childPath, slpkChildPath) {
637
643
  if (this.options.slpk) {
638
644
  const slpkGeometryPath = (0, path_1.join)(childPath, 'geometries');
639
- this.writeQueue.enqueue({
645
+ await this.writeQueue.enqueue({
640
646
  archiveKey: `${slpkChildPath}/geometries/0.bin.gz`,
641
647
  writePromise: (0, file_utils_1.writeFileForSlpk)(slpkGeometryPath, geometryBuffer, '0.bin')
642
648
  });
643
649
  }
644
650
  else {
645
651
  const geometryPath = (0, path_1.join)(childPath, 'geometries/0/');
646
- this.writeQueue.enqueue({
652
+ await this.writeQueue.enqueue({
647
653
  writePromise: (0, file_utils_1.writeFile)(geometryPath, geometryBuffer, 'index.bin')
648
654
  });
649
655
  }
650
656
  if (this.options.draco) {
651
657
  if (this.options.slpk) {
652
658
  const slpkCompressedGeometryPath = (0, path_1.join)(childPath, 'geometries');
653
- this.writeQueue.enqueue({
659
+ await this.writeQueue.enqueue({
654
660
  archiveKey: `${slpkChildPath}/geometries/1.bin.gz`,
655
661
  writePromise: (0, file_utils_1.writeFileForSlpk)(slpkCompressedGeometryPath, compressedGeometry, '1.bin')
656
662
  });
657
663
  }
658
664
  else {
659
665
  const compressedGeometryPath = (0, path_1.join)(childPath, 'geometries/1/');
660
- this.writeQueue.enqueue({
666
+ await this.writeQueue.enqueue({
661
667
  writePromise: (0, file_utils_1.writeFile)(compressedGeometryPath, compressedGeometry, 'index.bin')
662
668
  });
663
669
  }
@@ -679,14 +685,14 @@ class I3SConverter {
679
685
  const sharedDataStr = JSON.stringify(sharedData);
680
686
  if (this.options.slpk) {
681
687
  const slpkSharedPath = (0, path_1.join)(childPath, 'shared');
682
- this.writeQueue.enqueue({
688
+ await this.writeQueue.enqueue({
683
689
  archiveKey: `${slpkChildPath}/shared/sharedResource.json.gz`,
684
690
  writePromise: (0, file_utils_1.writeFileForSlpk)(slpkSharedPath, sharedDataStr, 'sharedResource.json')
685
691
  });
686
692
  }
687
693
  else {
688
694
  const sharedPath = (0, path_1.join)(childPath, 'shared/');
689
- this.writeQueue.enqueue({ writePromise: (0, file_utils_1.writeFile)(sharedPath, sharedDataStr) });
695
+ await this.writeQueue.enqueue({ writePromise: (0, file_utils_1.writeFile)(sharedPath, sharedDataStr) });
690
696
  }
691
697
  }
692
698
  /**
@@ -747,14 +753,14 @@ class I3SConverter {
747
753
  if (this.options.slpk) {
748
754
  const slpkTexturePath = (0, path_1.join)(childPath, 'textures');
749
755
  const compress = false;
750
- this.writeQueue.enqueue({
756
+ await this.writeQueue.enqueue({
751
757
  archiveKey: `${slpkChildPath}/textures/${name}.${format}`,
752
758
  writePromise: (0, file_utils_1.writeFileForSlpk)(slpkTexturePath, textureData, `${name}.${format}`, compress)
753
759
  });
754
760
  }
755
761
  else {
756
762
  const texturePath = (0, path_1.join)(childPath, `textures/${name}/`);
757
- this.writeQueue.enqueue({
763
+ await this.writeQueue.enqueue({
758
764
  writePromise: (0, file_utils_1.writeFile)(texturePath, textureData, `index.${format}`)
759
765
  });
760
766
  }
@@ -772,14 +778,14 @@ class I3SConverter {
772
778
  const fileBuffer = new Uint8Array(attributes[index]);
773
779
  if (this.options.slpk) {
774
780
  const slpkAttributesPath = (0, path_1.join)(childPath, 'attributes', folderName);
775
- this.writeQueue.enqueue({
781
+ await this.writeQueue.enqueue({
776
782
  archiveKey: `${slpkChildPath}/attributes/${folderName}.bin.gz`,
777
783
  writePromise: (0, file_utils_1.writeFileForSlpk)(slpkAttributesPath, fileBuffer, '0.bin')
778
784
  });
779
785
  }
780
786
  else {
781
787
  const attributesPath = (0, path_1.join)(childPath, `attributes/${folderName}/0`);
782
- this.writeQueue.enqueue({
788
+ await this.writeQueue.enqueue({
783
789
  writePromise: (0, file_utils_1.writeFile)(attributesPath, fileBuffer, 'index.bin')
784
790
  });
785
791
  }
@@ -819,7 +825,7 @@ class I3SConverter {
819
825
  /**
820
826
  * Generate storage attribute for map segmentation.
821
827
  * @param attributeIndex - order index of attribute (f_0, f_1 ...).
822
- * @param key - attribute key from batch table.\
828
+ * @param key - attribute key from propertyTable.
823
829
  * @param attributeType - attribute type.
824
830
  * @return Updated storageAttribute.
825
831
  */
@@ -851,7 +857,7 @@ class I3SConverter {
851
857
  /**
852
858
  * Get the attribute type for attributeStorageInfo https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md
853
859
  * @param key - attribute's key
854
- * @param attribute - attribute's type in batchTable
860
+ * @param attribute - attribute's type in propertyTable
855
861
  */
856
862
  getAttributeType(key, attribute) {
857
863
  if (key === OBJECT_ID_TYPE) {
@@ -915,22 +921,22 @@ class I3SConverter {
915
921
  };
916
922
  }
917
923
  /**
918
- * Do conversion of 3DTiles batch table to I3s node attributes.
919
- * @param batchTable - Table with layer meta data.
924
+ * Do conversion of 3DTiles property table to I3s node attributes.
925
+ * @param propertyTable - Table with layer meta data.
920
926
  */
921
- _convertBatchTableInfoToNodeAttributes(batchTable) {
927
+ _convertPropertyTableToNodeAttributes(propertyTable) {
922
928
  let attributeIndex = 0;
923
- const batchTableWithObjectId = {
929
+ const propertyTableWithObjectId = {
924
930
  OBJECTID: [0],
925
- ...batchTable
931
+ ...propertyTable
926
932
  };
927
- for (const key in batchTableWithObjectId) {
928
- const firstAttribute = batchTableWithObjectId[key][0];
933
+ for (const key in propertyTableWithObjectId) {
934
+ const firstAttribute = propertyTableWithObjectId[key][0];
929
935
  const attributeType = this.getAttributeType(key, firstAttribute);
930
936
  const storageAttribute = this._createdStorageAttribute(attributeIndex, key, attributeType);
931
937
  const fieldAttributeType = this._getFieldAttributeType(attributeType);
932
938
  const fieldAttribute = this._createFieldAttribute(key, fieldAttributeType);
933
- const popupInfo = this._createPopupInfo(batchTableWithObjectId);
939
+ const popupInfo = this._createPopupInfo(propertyTableWithObjectId);
934
940
  this.layers0.attributeStorageInfo.push(storageAttribute);
935
941
  this.layers0.fields.push(fieldAttribute);
936
942
  this.layers0.popupInfo = popupInfo;
@@ -939,7 +945,7 @@ class I3SConverter {
939
945
  }
940
946
  }
941
947
  /**
942
- * Find and return attribute type based on key form Batch table.
948
+ * Find and return attribute type based on key form propertyTable.
943
949
  * @param attributeType
944
950
  */
945
951
  _getFieldAttributeType(attributeType) {
@@ -958,16 +964,16 @@ class I3SConverter {
958
964
  }
959
965
  /**
960
966
  * Generate popup info to show metadata on the map.
961
- * @param batchTable - Batch table data with OBJECTID.
967
+ * @param propertyTable - table data with OBJECTID.
962
968
  * @return data for correct rendering of popup.
963
969
  */
964
- _createPopupInfo(batchTable) {
970
+ _createPopupInfo(propertyTable) {
965
971
  const title = '{OBJECTID}';
966
972
  const mediaInfos = [];
967
973
  const fieldInfos = [];
968
974
  const popupElements = [];
969
975
  const expressionInfos = [];
970
- for (const key in batchTable) {
976
+ for (const key in propertyTable) {
971
977
  fieldInfos.push({
972
978
  fieldName: key,
973
979
  visible: true,
@@ -111,52 +111,4 @@ export declare type I3SMaterialWithTexture = {
111
111
  /** Texture content (image) */
112
112
  texture?: ImageDataType;
113
113
  };
114
- /**
115
- * 3DTilesNext EXT_feature_metadata extension
116
- * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata
117
- */
118
- export declare type ExtFeatureMetadata = {
119
- /** Feature ids definition in attributes */
120
- featureIdAttributes?: ExtFeatureMetadataAttribute[];
121
- /** Feature ids definition in textures */
122
- featureIdTextures?: ExtFeatureMetadataAttribute[];
123
- };
124
- /**
125
- * Attribute which described featureIds definition.
126
- */
127
- export declare type ExtFeatureMetadataAttribute = {
128
- /** Name of feature table */
129
- featureTable: string;
130
- /** Described how feature ids are defined */
131
- featureIds: ExtFeatureMetadataFeatureIds;
132
- };
133
- /**
134
- * Defining featureIds by attributes or implicitly.
135
- */
136
- declare type ExtFeatureMetadataFeatureIds = {
137
- /** Name of attribute where featureIds are defined */
138
- attribute?: string;
139
- /** Sets a constant feature ID for each vertex. The default is 0. */
140
- constant?: number;
141
- /** Sets the rate at which feature IDs increment.
142
- * If divisor is zero then constant is used.
143
- * If divisor is greater than zero the feature ID increments once per divisor sets of vertices, starting at constant.
144
- * The default is 0
145
- */
146
- divisor?: number;
147
- /** gLTF textureInfo object - https://github.com/CesiumGS/glTF/blob/3d-tiles-next/specification/2.0/schema/textureInfo.schema.json */
148
- texture?: ExtFeatureMetadataTexture;
149
- /** Must be a single channel ("r", "g", "b", or "a") */
150
- channels?: 'r' | 'g' | 'b' | 'a';
151
- };
152
- /**
153
- * Reference to a texture.
154
- */
155
- declare type ExtFeatureMetadataTexture = {
156
- /** The set index of texture's TEXCOORD attribute used for texture coordinate mapping.*/
157
- texCoord: number;
158
- /** The index of the texture. */
159
- index: number;
160
- };
161
- export {};
162
114
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/i3s-converter/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/i3s-converter/types.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAEjD,4CAA4C;AAC5C,oBAAY,qBAAqB,GAAG;IAClC;;;OAGG;IACH,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7B;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;IACjD;;OAEG;IACH,OAAO,EAAE,GAAG,GAAG,IAAI,CAAC;IACpB;;OAEG;IACH,eAAe,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC9C;;OAEG;IACH,YAAY,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC5C;;OAEG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;OAEG;IACH,UAAU,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IACjC;;OAEG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;OAEG;IACH,eAAe,EAAE,eAAe,GAAG,IAAI,CAAC;CACzC,CAAC;AAEF;;GAEG;AACH,oBAAY,mBAAmB,GAAG;IAChC,+BAA+B;IAC/B,SAAS,EAAE,YAAY,CAAC;IACxB,6BAA6B;IAC7B,OAAO,EAAE,YAAY,CAAC;IACtB,iCAAiC;IACjC,SAAS,EAAE,YAAY,CAAC;IACxB,8BAA8B;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB;;OAEG;IACH,oBAAoB,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;IAClC,iDAAiD;IACjD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB;;OAEG;IACH,eAAe,EAAE,IAAI,GAAG,eAAe,CAAC;CACzC,CAAC;AAEF;;GAEG;AACH,oBAAY,kBAAkB,GAAG;IAC/B,+BAA+B;IAC/B,SAAS,EAAE,YAAY,CAAC;IACxB,6BAA6B;IAC7B,OAAO,EAAE,YAAY,CAAC;IACtB,iCAAiC;IACjC,SAAS,EAAE,YAAY,CAAC;IACxB,8BAA8B;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB,kCAAkC;IAClC,SAAS,EAAE,WAAW,CAAC;IACvB,kCAAkC;IAClC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,qCAAqC;IACrC,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,8DAA8D;AAC9D,oBAAY,4BAA4B,GAAG;IACzC,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,SAAS,EAAE,YAAY,CAAC;IACxB,6BAA6B;IAC7B,OAAO,EAAE,YAAY,CAAC;IACtB,8BAA8B;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB,iCAAiC;IACjC,SAAS,EAAE,YAAY,CAAC;CACzB,CAAC;AAEF,+CAA+C;AAC/C,oBAAY,qBAAqB,GAAG;IAClC,oHAAoH;IACpH,uBAAuB,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACnD,kHAAkH;IAClH,sBAAsB,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACjD,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,2EAA2E;AAC3E,oBAAY,sBAAsB,GAAG;IACnC,2GAA2G;IAC3G,QAAQ,EAAE,qBAAqB,CAAC;IAChC,8BAA8B;IAC9B,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB,CAAC"}
@@ -12,6 +12,7 @@ export default class WriteQueue<T extends WriteQueueItem> extends Queue<T> {
12
12
  listeningInterval: number;
13
13
  writeConcurrency: number;
14
14
  constructor(listeningInterval?: number, writeConcurrency?: number);
15
+ enqueue(val: T): Promise<void>;
15
16
  startListening(): void;
16
17
  stopListening(): void;
17
18
  startWrite(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"write-queue.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/write-queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,SAAS,CAAC;AAE9B,oBAAY,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,UAAU,CAAC,CAAC,SAAS,cAAc,CAAE,SAAQ,KAAK,CAAC,CAAC,CAAC;IACxE,OAAO,CAAC,UAAU,CAAC,CAAiB;IAC7B,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAQ;IAC1C,OAAO,EAAE;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAC,CAAM;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;gBAEpB,iBAAiB,GAAE,MAAa,EAAE,gBAAgB,GAAE,MAAY;IAM5E,cAAc;IAId,aAAa;IAMP,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAKjB,OAAO;IAmBrB,OAAO,CAAC,aAAa;CAWtB"}
1
+ {"version":3,"file":"write-queue.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/write-queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,SAAS,CAAC;AAM9B,oBAAY,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,UAAU,CAAC,CAAC,SAAS,cAAc,CAAE,SAAQ,KAAK,CAAC,CAAC,CAAC;IACxE,OAAO,CAAC,UAAU,CAAC,CAAiB;IAC7B,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAQ;IAC1C,OAAO,EAAE;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAC,CAAM;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;gBAEpB,iBAAiB,GAAE,MAAa,EAAE,gBAAgB,GAAE,MAAY;IAMtE,OAAO,CAAC,GAAG,EAAE,CAAC;IAQpB,cAAc;IAId,aAAa;IAMP,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAKjB,OAAO;IAmBrB,OAAO,CAAC,aAAa;CAWtB"}
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  const queue_1 = require("./queue");
7
+ const process_1 = __importDefault(require("process"));
8
+ /** Memory limit size is based on testing */
9
+ const MEMORY_LIMIT = 4 * 1024 * 1024 * 1024; // 4GB
4
10
  class WriteQueue extends queue_1.Queue {
5
11
  constructor(listeningInterval = 2000, writeConcurrency = 400) {
6
12
  super();
@@ -9,6 +15,13 @@ class WriteQueue extends queue_1.Queue {
9
15
  this.listeningInterval = listeningInterval;
10
16
  this.writeConcurrency = writeConcurrency;
11
17
  }
18
+ async enqueue(val) {
19
+ super.enqueue(val);
20
+ /** https://nodejs.org/docs/latest-v14.x/api/process.html#process_process_memoryusage */
21
+ if (process_1.default.memoryUsage().rss > MEMORY_LIMIT) {
22
+ await this.startWrite();
23
+ }
24
+ }
12
25
  startListening() {
13
26
  this.intervalId = setInterval(this.startWrite.bind(this), this.listeningInterval);
14
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loaders.gl/tile-converter",
3
- "version": "3.3.0-alpha.1",
3
+ "version": "3.3.0-alpha.2",
4
4
  "description": "Converter",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -43,19 +43,19 @@
43
43
  "build-3d-tiles-attributes-worker": "esbuild src/workers/3d-tiles-attributes-worker.ts --outfile=dist/3d-tiles-attributes-worker.js --platform=node --target=esnext,node12 --minify --bundle --sourcemap --define:__VERSION__=\\\"$npm_package_version\\\""
44
44
  },
45
45
  "dependencies": {
46
- "@loaders.gl/3d-tiles": "3.3.0-alpha.1",
47
- "@loaders.gl/crypto": "3.3.0-alpha.1",
48
- "@loaders.gl/draco": "3.3.0-alpha.1",
49
- "@loaders.gl/gltf": "3.3.0-alpha.1",
50
- "@loaders.gl/i3s": "3.3.0-alpha.1",
51
- "@loaders.gl/images": "3.3.0-alpha.1",
52
- "@loaders.gl/loader-utils": "3.3.0-alpha.1",
53
- "@loaders.gl/polyfills": "3.3.0-alpha.1",
54
- "@loaders.gl/schema": "3.3.0-alpha.1",
55
- "@loaders.gl/textures": "3.3.0-alpha.1",
56
- "@loaders.gl/tiles": "3.3.0-alpha.1",
57
- "@loaders.gl/worker-utils": "3.3.0-alpha.1",
58
- "@loaders.gl/zip": "3.3.0-alpha.1",
46
+ "@loaders.gl/3d-tiles": "3.3.0-alpha.2",
47
+ "@loaders.gl/crypto": "3.3.0-alpha.2",
48
+ "@loaders.gl/draco": "3.3.0-alpha.2",
49
+ "@loaders.gl/gltf": "3.3.0-alpha.2",
50
+ "@loaders.gl/i3s": "3.3.0-alpha.2",
51
+ "@loaders.gl/images": "3.3.0-alpha.2",
52
+ "@loaders.gl/loader-utils": "3.3.0-alpha.2",
53
+ "@loaders.gl/polyfills": "3.3.0-alpha.2",
54
+ "@loaders.gl/schema": "3.3.0-alpha.2",
55
+ "@loaders.gl/textures": "3.3.0-alpha.2",
56
+ "@loaders.gl/tiles": "3.3.0-alpha.2",
57
+ "@loaders.gl/worker-utils": "3.3.0-alpha.2",
58
+ "@loaders.gl/zip": "3.3.0-alpha.2",
59
59
  "@luma.gl/engine": "^8.5.4",
60
60
  "@math.gl/core": "^3.5.1",
61
61
  "@math.gl/culling": "^3.5.1",
@@ -75,5 +75,5 @@
75
75
  "peerDependencies": {
76
76
  "@loaders.gl/core": "^3.2.0"
77
77
  },
78
- "gitHead": "85ed2df7d17dd0d204c8bd8feb44779f70bc693b"
78
+ "gitHead": "628f1f0eed0f14b50ccff4c561023acf6e0657e6"
79
79
  }
@@ -1,6 +1,9 @@
1
1
  import type {GLTFAccessorPostprocessed} from 'modules/gltf/src/lib/types/gltf-types';
2
2
  import type {Image, MeshPrimitive} from 'modules/gltf/src/lib/types/gltf-postprocessed-schema';
3
- import type {ExtFeatureMetadata, ExtFeatureMetadataAttribute} from '../types';
3
+ import type {
4
+ GLTF_EXT_feature_metadata_attribute,
5
+ GLTF_EXT_feature_metadata_primitive
6
+ } from 'modules/gltf/src/lib/types/gltf-json-schema';
4
7
 
5
8
  const EXT_MESH_FEATURES = 'EXT_mesh_features';
6
9
  const EXT_FEATURE_METADATA = 'EXT_feature_metadata';
@@ -29,7 +32,7 @@ export function handleBatchIdsExtensions(
29
32
  case EXT_FEATURE_METADATA:
30
33
  return handleExtFeatureMetadataExtension(
31
34
  attributes,
32
- extensionData as ExtFeatureMetadata,
35
+ extensionData as GLTF_EXT_feature_metadata_primitive,
33
36
  images
34
37
  );
35
38
  case EXT_MESH_FEATURES:
@@ -54,7 +57,7 @@ function handleExtFeatureMetadataExtension(
54
57
  attributes: {
55
58
  [key: string]: GLTFAccessorPostprocessed;
56
59
  },
57
- extFeatureMetadata: ExtFeatureMetadata,
60
+ extFeatureMetadata: GLTF_EXT_feature_metadata_primitive,
58
61
  images: Image[]
59
62
  ): number[] {
60
63
  // Take only first extension object to get batchIds attribute name.
@@ -82,10 +85,24 @@ function handleExtFeatureMetadataExtension(
82
85
  extFeatureMetadata?.featureIdTextures && extFeatureMetadata?.featureIdTextures[0];
83
86
 
84
87
  if (featureIdTexture) {
85
- const textureCoordinates = attributes.TEXCOORD_0.value;
88
+ const textureAttributeIndex = featureIdTexture?.featureIds?.texture?.texCoord || 0;
89
+ const textCoordAttribute = `TEXCOORD_${textureAttributeIndex}`;
90
+ const textureCoordinates = attributes[textCoordAttribute].value;
86
91
  return generateBatchIdsFromTexture(featureIdTexture, textureCoordinates, images);
87
92
  }
88
93
 
94
+ // Take only first extension texture to get batchIds from the root EXT_feature_metadata object.
95
+ const featureTexture =
96
+ extFeatureMetadata?.featureTextures && extFeatureMetadata?.featureTextures[0];
97
+
98
+ /**
99
+ * TODO need to get batchIds from root extension
100
+ */
101
+ if (featureTexture) {
102
+ console.warn("EXT_feature_metadata doesn't yet support featureTextures in primitive");
103
+ return [];
104
+ }
105
+
89
106
  return [];
90
107
  }
91
108
 
@@ -130,7 +147,7 @@ function generateImplicitFeatureIds(
130
147
  * @param featureIdTextures
131
148
  */
132
149
  function generateBatchIdsFromTexture(
133
- featureIdTexture: ExtFeatureMetadataAttribute,
150
+ featureIdTexture: GLTF_EXT_feature_metadata_attribute,
134
151
  textureCoordinates: Float32Array,
135
152
  images: Image[]
136
153
  ) {
@@ -0,0 +1,65 @@
1
+ import type {FeatureTableJson} from '@loaders.gl/3d-tiles';
2
+
3
+ /**
4
+ * Takes attributes from property table based on featureIds.
5
+ * If there is no property value for particular featureId (index) the property will be null.
6
+ * Example:
7
+ * Initial data:
8
+ * OBJECTID: [0, 1, 5]
9
+ * component: ['Windows', 'Frames', 'Wall', 'Roof', 'Skylight']
10
+ * Result:
11
+ * OBJECTID: [0, 1, 5]
12
+ * component: ['Windows', 'Frames', 'null']
13
+ * @param featureIds
14
+ * @param propertyTable
15
+ */
16
+ export function flattenPropertyTableByFeatureIds(
17
+ featureIds: number[],
18
+ propertyTable: FeatureTableJson
19
+ ): FeatureTableJson {
20
+ const resultPropertyTable: FeatureTableJson = {};
21
+ for (const propertyName in propertyTable) {
22
+ const properties = propertyTable[propertyName];
23
+ resultPropertyTable[propertyName] = getPropertiesByFeatureIds(properties, featureIds);
24
+ }
25
+
26
+ return resultPropertyTable;
27
+ }
28
+
29
+ /**
30
+ * Getting properties by featureId index
31
+ * @param properties
32
+ * @param featureIds
33
+ */
34
+ function getPropertiesByFeatureIds(properties: any[], featureIds: number[]): any[] {
35
+ const resultProperties: any = [];
36
+
37
+ for (const featureId of featureIds) {
38
+ const property = properties[featureId] || null;
39
+ resultProperties.push(property);
40
+ }
41
+
42
+ return resultProperties;
43
+ }
44
+
45
+ /**
46
+ * Check that all attributes in propertyTable have the same length as FeatureIds.
47
+ * If there are differencies between lengths we should flatten property table based on exiesting featureIds.
48
+ * @param featureIds
49
+ * @param propertyTable
50
+ * @returns
51
+ */
52
+ export function checkPropertiesLength(
53
+ featureIds: number[],
54
+ propertyTable: FeatureTableJson
55
+ ): boolean {
56
+ let needFlatten = false;
57
+
58
+ for (const attribute of Object.values(propertyTable)) {
59
+ if (featureIds.length !== attribute.length) {
60
+ needFlatten = true;
61
+ }
62
+ }
63
+
64
+ return needFlatten;
65
+ }
@@ -47,7 +47,7 @@ function calculateFaceRangesAndFeaturesCount(featureIndices: number[]): {
47
47
  } {
48
48
  let rangeIndex = 1;
49
49
  let featureIndex = 1;
50
- let currentFeatureId = featureIndices[0];
50
+ let currentFeatureId = getFrequentValue(featureIndices.slice(0, VALUES_PER_VERTEX));
51
51
  const faceRangeList: any[] = [];
52
52
  const featureIds: any[] = [];
53
53
  const uniqueFeatureIds = [currentFeatureId];
@@ -55,20 +55,21 @@ function calculateFaceRangesAndFeaturesCount(featureIndices: number[]): {
55
55
  faceRangeList[0] = 0;
56
56
  featureIds[0] = currentFeatureId;
57
57
 
58
- for (let index = 1; index < featureIndices.length; index++) {
59
- if (currentFeatureId !== featureIndices[index]) {
58
+ for (let index = VALUES_PER_VERTEX; index < featureIndices.length; index += VALUES_PER_VERTEX) {
59
+ const newFeatureId = getFrequentValue(featureIndices.slice(index, index + VALUES_PER_VERTEX));
60
+ if (currentFeatureId !== newFeatureId) {
60
61
  faceRangeList[rangeIndex] = index / VALUES_PER_VERTEX - 1;
61
62
  faceRangeList[rangeIndex + 1] = index / VALUES_PER_VERTEX;
62
- featureIds[featureIndex] = featureIndices[index];
63
+ featureIds[featureIndex] = newFeatureId;
63
64
 
64
- if (!uniqueFeatureIds.includes(featureIndices[index])) {
65
- uniqueFeatureIds.push(featureIndices[index]);
65
+ if (!uniqueFeatureIds.includes(newFeatureId)) {
66
+ uniqueFeatureIds.push(newFeatureId);
66
67
  }
67
68
 
68
69
  rangeIndex += 2;
69
70
  featureIndex += 1;
70
71
  }
71
- currentFeatureId = featureIndices[index];
72
+ currentFeatureId = newFeatureId;
72
73
  }
73
74
 
74
75
  faceRangeList[rangeIndex] = featureIndices.length / VALUES_PER_VERTEX - 1;
@@ -79,6 +80,28 @@ function calculateFaceRangesAndFeaturesCount(featureIndices: number[]): {
79
80
  return {faceRange, featureCount, featureIds};
80
81
  }
81
82
 
83
+ /**
84
+ * Find most frequent value to avoid situation where one vertex can be part of multiple features (objects).
85
+ * @param values
86
+ */
87
+ function getFrequentValue(values: number[]): number {
88
+ const map: {[key: number]: number} = {};
89
+
90
+ let mostFrequentValue = values[0];
91
+ let maxCount = 1;
92
+
93
+ for (const value of values) {
94
+ // Save item and it's frequency count to the map.
95
+ map[value] = (map[value] || 0) + 1;
96
+ // Find max count of frequency.
97
+ maxCount = maxCount > map[value] ? maxCount : map[value];
98
+ // Find the most frequent value.
99
+ mostFrequentValue = maxCount > map[value] ? mostFrequentValue : value;
100
+ }
101
+
102
+ return mostFrequentValue;
103
+ }
104
+
82
105
  /**
83
106
  * Generate list of attribute object grouped by feature ids.
84
107
  * @param attributes