@loaders.gl/tile-converter 4.1.1 → 4.2.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 (55) hide show
  1. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts +11 -0
  2. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts.map +1 -1
  3. package/dist/3d-tiles-converter/3d-tiles-converter.js +77 -27
  4. package/dist/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  5. package/dist/3d-tiles-converter/helpers/load-i3s.d.ts +22 -1
  6. package/dist/3d-tiles-converter/helpers/load-i3s.d.ts.map +1 -1
  7. package/dist/3d-tiles-converter/helpers/load-i3s.js +49 -4
  8. package/dist/3d-tiles-converter/helpers/load-i3s.js.map +1 -1
  9. package/dist/converter-cli.js +2 -1
  10. package/dist/converter-cli.js.map +1 -1
  11. package/dist/converter.min.cjs +137 -130
  12. package/dist/deps-installer/deps-installer.js +1 -1
  13. package/dist/deps-installer/deps-installer.js.map +1 -1
  14. package/dist/i3s-converter/helpers/attribute-metadata-info.d.ts +10 -0
  15. package/dist/i3s-converter/helpers/attribute-metadata-info.d.ts.map +1 -1
  16. package/dist/i3s-converter/helpers/attribute-metadata-info.js +5 -0
  17. package/dist/i3s-converter/helpers/attribute-metadata-info.js.map +1 -1
  18. package/dist/i3s-converter/helpers/load-3d-tiles.d.ts.map +1 -1
  19. package/dist/i3s-converter/helpers/load-3d-tiles.js +22 -2
  20. package/dist/i3s-converter/helpers/load-3d-tiles.js.map +1 -1
  21. package/dist/i3s-converter/helpers/node-index-document.d.ts +2 -1
  22. package/dist/i3s-converter/helpers/node-index-document.d.ts.map +1 -1
  23. package/dist/i3s-converter/helpers/node-index-document.js +6 -8
  24. package/dist/i3s-converter/helpers/node-index-document.js.map +1 -1
  25. package/dist/i3s-converter/i3s-converter.d.ts +18 -0
  26. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
  27. package/dist/i3s-converter/i3s-converter.js +121 -24
  28. package/dist/i3s-converter/i3s-converter.js.map +1 -1
  29. package/dist/i3s-server/bin/i3s-server.min.cjs +86 -86
  30. package/dist/index.cjs +792 -101
  31. package/dist/lib/json-schemas/conversion-dump-json-schema.d.ts +463 -0
  32. package/dist/lib/json-schemas/conversion-dump-json-schema.d.ts.map +1 -0
  33. package/dist/lib/json-schemas/conversion-dump-json-schema.js +463 -0
  34. package/dist/lib/json-schemas/conversion-dump-json-schema.js.map +1 -0
  35. package/dist/lib/utils/conversion-dump.d.ts +65 -8
  36. package/dist/lib/utils/conversion-dump.d.ts.map +1 -1
  37. package/dist/lib/utils/conversion-dump.js +98 -18
  38. package/dist/lib/utils/conversion-dump.js.map +1 -1
  39. package/dist/lib/utils/file-utils.d.ts +6 -0
  40. package/dist/lib/utils/file-utils.d.ts.map +1 -1
  41. package/dist/lib/utils/file-utils.js +7 -0
  42. package/dist/lib/utils/file-utils.js.map +1 -1
  43. package/dist/pgm-loader.js +1 -1
  44. package/dist/pgm-loader.js.map +1 -1
  45. package/package.json +15 -14
  46. package/src/3d-tiles-converter/3d-tiles-converter.ts +104 -31
  47. package/src/3d-tiles-converter/helpers/load-i3s.ts +86 -7
  48. package/src/converter-cli.ts +2 -1
  49. package/src/i3s-converter/helpers/attribute-metadata-info.ts +16 -0
  50. package/src/i3s-converter/helpers/load-3d-tiles.ts +52 -2
  51. package/src/i3s-converter/helpers/node-index-document.ts +18 -8
  52. package/src/i3s-converter/i3s-converter.ts +198 -41
  53. package/src/lib/json-schemas/conversion-dump-json-schema.ts +285 -0
  54. package/src/lib/utils/conversion-dump.ts +200 -26
  55. package/src/lib/utils/file-utils.ts +13 -0
package/dist/index.cjs CHANGED
@@ -115,6 +115,15 @@ var AttributeMetadataInfo = class {
115
115
  this._popupInfo = this.createPopupInfo(attributeNames);
116
116
  }
117
117
  }
118
+ /**
119
+ * Set AttributeMetadataInfo from object
120
+ * @param object - object with AttributeMetadataInfo props
121
+ */
122
+ fromObject(object) {
123
+ this._attributeStorageInfo = object.attributeStorageInfo;
124
+ this._fields = object.fields;
125
+ this._popupInfo = object.popupInfo;
126
+ }
118
127
  /**
119
128
  * Generates storage attribute for map segmentation.
120
129
  * @param attributeIndex - order index of attribute (f_0, f_1 ...).
@@ -252,7 +261,7 @@ var import_core9 = require("@loaders.gl/core");
252
261
  var import_d_tiles2 = require("@loaders.gl/3d-tiles");
253
262
  var import_path7 = require("path");
254
263
  var import_uuid4 = require("uuid");
255
- var import_process3 = __toESM(require("process"), 1);
264
+ var import_process4 = __toESM(require("process"), 1);
256
265
  var import_json_map_transform8 = __toESM(require("json-map-transform"), 1);
257
266
  var import_md52 = __toESM(require("md5"), 1);
258
267
 
@@ -384,6 +393,13 @@ function removeFile(path) {
384
393
  function getAbsoluteFilePath(filePath) {
385
394
  return (0, import_path.isAbsolute)(filePath) ? filePath : (0, import_path.join)(process.cwd(), filePath);
386
395
  }
396
+ async function renameFile(oldPath, newPath) {
397
+ try {
398
+ await import_fs2.promises.rename(oldPath, newPath);
399
+ } catch (err) {
400
+ console.log("Can't rename file", err);
401
+ }
402
+ }
387
403
 
388
404
  // src/i3s-converter/helpers/node-pages.ts
389
405
  var NodePages = class {
@@ -3508,8 +3524,7 @@ var NodeIndexDocument = class {
3508
3524
  * @return 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md object
3509
3525
  */
3510
3526
  static async createNodeIndexDocument(parentNode, boundingVolumes, lodSelection, nodeInPage, resources) {
3511
- var _a2, _b;
3512
- const { texture, attributes } = resources;
3527
+ var _a2, _b, _c, _d, _e;
3513
3528
  const nodeId = nodeInPage.index;
3514
3529
  const parentNodeData = await parentNode.load();
3515
3530
  const nodeData = {
@@ -3531,12 +3546,13 @@ var NodeIndexDocument = class {
3531
3546
  if (nodeInPage.mesh) {
3532
3547
  node.geometryData = [{ href: "./geometries/0" }];
3533
3548
  node.sharedResource = { href: "./shared" };
3534
- if (texture) {
3549
+ if ("texture" in resources && resources.texture || "texelCountHint" in resources && resources.texelCountHint) {
3535
3550
  node.textureData = [{ href: "./textures/0" }, { href: "./textures/1" }];
3536
3551
  }
3537
- if (attributes && attributes.length && ((_b = (_a2 = parentNode.converter.layers0) == null ? void 0 : _a2.attributeStorageInfo) == null ? void 0 : _b.length)) {
3552
+ if ("attributes" in resources && resources.attributes && resources.attributes.length && ((_b = (_a2 = parentNode.converter.layers0) == null ? void 0 : _a2.attributeStorageInfo) == null ? void 0 : _b.length) || "attributesCount" in resources && resources.attributesCount && ((_d = (_c = parentNode.converter.layers0) == null ? void 0 : _c.attributeStorageInfo) == null ? void 0 : _d.length)) {
3553
+ const attributesLength = ("attributes" in resources ? (_e = resources.attributes) == null ? void 0 : _e.length : resources.attributesCount) || 0;
3538
3554
  node.attributeData = [];
3539
- const minimumLength = attributes.length < parentNode.converter.layers0.attributeStorageInfo.length ? attributes.length : parentNode.converter.layers0.attributeStorageInfo.length;
3555
+ const minimumLength = attributesLength < parentNode.converter.layers0.attributeStorageInfo.length ? attributesLength : parentNode.converter.layers0.attributeStorageInfo.length;
3540
3556
  for (let index = 0; index < minimumLength; index++) {
3541
3557
  const folderName = parentNode.converter.layers0.attributeStorageInfo[index].key;
3542
3558
  node.attributeData.push({ href: `./attributes/${folderName}/0` });
@@ -3550,6 +3566,8 @@ var NodeIndexDocument = class {
3550
3566
  // src/i3s-converter/helpers/load-3d-tiles.ts
3551
3567
  var import_d_tiles = require("@loaders.gl/3d-tiles");
3552
3568
  var import_core7 = require("@loaders.gl/core");
3569
+ var import_loader_utils4 = require("@loaders.gl/loader-utils");
3570
+ var import_zip = require("@loaders.gl/zip");
3553
3571
  var loadNestedTileset = async (sourceTileset, sourceTile, tilesetLoadOptions) => {
3554
3572
  const isTileset = isNestedTileset(sourceTile);
3555
3573
  if (!sourceTileset || !sourceTile.contentUrl || !isTileset) {
@@ -3607,7 +3625,10 @@ async function loadFromArchive(url, loader, loadOptions) {
3607
3625
  }
3608
3626
  if (filename) {
3609
3627
  const tz3Path = `${tz3UrlParts[0]}.3tz`;
3610
- const fileSystem = new import_d_tiles.Tiles3DArchiveFileSystem(tz3Path);
3628
+ const fileProvider = new import_loader_utils4.FileHandleFile(tz3Path);
3629
+ const hashTable = await loadHashTable(fileProvider);
3630
+ const archive = new import_d_tiles.Tiles3DArchive(fileProvider, hashTable, tz3Path);
3631
+ const fileSystem = new import_zip.ZipFileSystem(archive);
3611
3632
  const content = await (0, import_core7.load)(filename, loader, {
3612
3633
  ...loadOptions,
3613
3634
  fetch: fileSystem.fetch.bind(fileSystem)
@@ -3620,6 +3641,27 @@ async function loadFromArchive(url, loader, loadOptions) {
3620
3641
  function isNestedTileset(tile) {
3621
3642
  return (tile == null ? void 0 : tile.type) === "json" || (tile == null ? void 0 : tile.type) === "3tz";
3622
3643
  }
3644
+ async function loadHashTable(fileProvider) {
3645
+ let hashTable;
3646
+ const hashCDOffset = await (0, import_zip.searchFromTheEnd)(fileProvider, import_zip.CD_HEADER_SIGNATURE);
3647
+ const cdFileHeader = await (0, import_zip.parseZipCDFileHeader)(hashCDOffset, fileProvider);
3648
+ if ((cdFileHeader == null ? void 0 : cdFileHeader.fileName) === "@3dtilesIndex1@") {
3649
+ const localFileHeader = await (0, import_zip.parseZipLocalFileHeader)(
3650
+ cdFileHeader.localHeaderOffset,
3651
+ fileProvider
3652
+ );
3653
+ if (!localFileHeader) {
3654
+ throw new Error("corrupted 3tz");
3655
+ }
3656
+ const fileDataOffset = localFileHeader.fileDataOffset;
3657
+ const hashFile = await fileProvider.slice(
3658
+ fileDataOffset,
3659
+ fileDataOffset + localFileHeader.compressedSize
3660
+ );
3661
+ hashTable = (0, import_zip.parseHashTable)(hashFile);
3662
+ }
3663
+ return hashTable;
3664
+ }
3623
3665
 
3624
3666
  // src/i3s-converter/i3s-converter.ts
3625
3667
  var import_core10 = require("@math.gl/core");
@@ -3866,19 +3908,313 @@ var Progress = class {
3866
3908
  };
3867
3909
 
3868
3910
  // src/i3s-converter/i3s-converter.ts
3869
- var import_zip = require("@loaders.gl/zip");
3911
+ var import_zip2 = require("@loaders.gl/zip");
3870
3912
 
3871
3913
  // src/lib/utils/conversion-dump.ts
3914
+ var import_util = require("util");
3872
3915
  var import_path6 = require("path");
3916
+ var import_process3 = __toESM(require("process"), 1);
3917
+ var import_ajv = __toESM(require("ajv"), 1);
3918
+
3919
+ // src/lib/json-schemas/conversion-dump-json-schema.ts
3920
+ var dumpJsonSchema = {
3921
+ type: "object",
3922
+ properties: {
3923
+ options: {
3924
+ type: "object",
3925
+ properties: {
3926
+ inputUrl: { type: "string" },
3927
+ outputPath: { type: "string" },
3928
+ tilesetName: { type: "string" },
3929
+ maxDepth: { type: "number" },
3930
+ slpk: { type: "boolean" },
3931
+ egmFilePath: { type: "string" },
3932
+ token: { type: "string" },
3933
+ draco: { type: "boolean" },
3934
+ mergeMaterials: { type: "boolean" },
3935
+ generateTextures: { type: "boolean" },
3936
+ generateBoundingVolumes: { type: "boolean" },
3937
+ metadataClass: { type: "string" },
3938
+ analyze: { type: "boolean" }
3939
+ },
3940
+ required: ["inputUrl", "outputPath", "tilesetName"]
3941
+ },
3942
+ tilesConverted: {
3943
+ type: "object",
3944
+ patternProperties: {
3945
+ ".*": {
3946
+ type: "object",
3947
+ properties: {
3948
+ nodes: {
3949
+ type: "array",
3950
+ items: {
3951
+ type: "object",
3952
+ properties: {
3953
+ nodeId: { type: ["number", "string"] },
3954
+ done: { type: "boolean" },
3955
+ progress: { type: "object", patternProperties: { ".*": { type: "boolean" } } },
3956
+ dumpMetadata: {
3957
+ type: "object",
3958
+ properties: {
3959
+ boundingVolumes: {
3960
+ type: ["object", "null"],
3961
+ properties: {
3962
+ mbs: {
3963
+ type: "array",
3964
+ minItems: 4,
3965
+ maxItems: 4,
3966
+ items: { type: "number" }
3967
+ },
3968
+ obb: {
3969
+ type: "object",
3970
+ properties: {
3971
+ center: {
3972
+ type: "array",
3973
+ minItems: 3,
3974
+ maxItems: 3,
3975
+ items: { type: "number" }
3976
+ },
3977
+ halfSize: {
3978
+ type: "array",
3979
+ minItems: 3,
3980
+ maxItems: 3,
3981
+ items: { type: "number" }
3982
+ },
3983
+ quaternion: {
3984
+ type: "array",
3985
+ minItems: 4,
3986
+ maxItems: 4,
3987
+ items: { type: "number" }
3988
+ }
3989
+ },
3990
+ required: ["center", "halfSize", "quaternion"]
3991
+ }
3992
+ },
3993
+ required: ["mbs", "obb"]
3994
+ },
3995
+ attributesCount: { type: "number" },
3996
+ featureCount: { type: "number" },
3997
+ geometry: { type: "boolean" },
3998
+ hasUvRegions: { type: "boolean" },
3999
+ materialId: { type: "number" },
4000
+ texelCountHint: { type: "number" },
4001
+ vertexCount: { type: "number" }
4002
+ },
4003
+ required: [
4004
+ "boundingVolumes",
4005
+ "featureCount",
4006
+ "geometry",
4007
+ "hasUvRegions",
4008
+ "materialId",
4009
+ "vertexCount"
4010
+ ]
4011
+ }
4012
+ },
4013
+ required: ["nodeId", "done"]
4014
+ }
4015
+ }
4016
+ },
4017
+ required: ["nodes"]
4018
+ }
4019
+ }
4020
+ },
4021
+ textureSetDefinitions: {
4022
+ type: "array",
4023
+ items: {
4024
+ type: "object",
4025
+ properties: {
4026
+ formats: {
4027
+ type: "array",
4028
+ items: {
4029
+ type: "object",
4030
+ properties: {
4031
+ name: { type: "string" },
4032
+ format: { enum: ["jpg", "png", "ktx-etc2", "dds", "ktx2"] }
4033
+ },
4034
+ required: ["name", "format"]
4035
+ }
4036
+ },
4037
+ atlas: { type: "boolean" }
4038
+ },
4039
+ required: ["formats"]
4040
+ }
4041
+ },
4042
+ attributeMetadataInfo: {
4043
+ type: "object",
4044
+ properties: {
4045
+ attributeStorageInfo: {
4046
+ type: "array",
4047
+ items: {
4048
+ type: "object",
4049
+ properties: {
4050
+ key: { type: "string" },
4051
+ name: { type: "string" },
4052
+ header: {
4053
+ type: "array",
4054
+ items: {
4055
+ type: "object",
4056
+ properties: { property: { type: "string" }, valueType: { type: "string" } },
4057
+ required: ["property", "valueType"]
4058
+ }
4059
+ },
4060
+ ordering: { type: "array", items: { type: "string" } },
4061
+ attributeValues: { $ref: "#/$defs/AttributeValue" },
4062
+ attributeByteCounts: { $ref: "#/$defs/AttributeValue" },
4063
+ objectIds: { $ref: "#/$defs/AttributeValue" }
4064
+ },
4065
+ required: ["key", "name", "header"]
4066
+ }
4067
+ },
4068
+ fields: {
4069
+ type: "array",
4070
+ items: {
4071
+ type: "object",
4072
+ properties: {
4073
+ name: { type: "string" },
4074
+ type: { $ref: "#/$defs/ESRIField" },
4075
+ alias: { type: "string" },
4076
+ domain: { $ref: "#/$defs/Domain" }
4077
+ },
4078
+ required: ["name", "type"]
4079
+ }
4080
+ },
4081
+ popupInfo: {
4082
+ type: "object",
4083
+ properties: {
4084
+ title: { type: "string" },
4085
+ description: { type: "string" },
4086
+ expressionInfos: { type: "array", items: {} },
4087
+ fieldInfos: { type: "array", items: { $ref: "#/$defs/FieldInfo" } },
4088
+ mediaInfos: { type: "array", items: {} },
4089
+ popupElements: {
4090
+ type: "array",
4091
+ items: {
4092
+ type: "object",
4093
+ properties: {
4094
+ text: { type: "string" },
4095
+ type: { type: "string" },
4096
+ fieldInfos: { type: "array", items: { $ref: "#/$defs/FieldInfo" } }
4097
+ }
4098
+ }
4099
+ }
4100
+ }
4101
+ }
4102
+ },
4103
+ required: ["attributeStorageInfo", "fields"]
4104
+ },
4105
+ materialDefinitions: {
4106
+ type: "array",
4107
+ items: {
4108
+ type: "object",
4109
+ properties: {
4110
+ pbrMetallicRoughness: {
4111
+ type: "object",
4112
+ properties: {
4113
+ baseColorFactor: {
4114
+ type: "array",
4115
+ minItems: 4,
4116
+ maxItems: 4,
4117
+ items: { type: "number" }
4118
+ },
4119
+ baseColorTexture: { $ref: "#/$defs/I3SMaterialTexture" },
4120
+ metallicFactor: { type: "number" },
4121
+ roughnessFactor: { type: "number" },
4122
+ metallicRoughnessTexture: { $ref: "#/$defs/I3SMaterialTexture" }
4123
+ },
4124
+ required: ["metallicFactor", "roughnessFactor"]
4125
+ },
4126
+ normalTexture: { $ref: "#/$defs/I3SMaterialTexture" },
4127
+ occlusionTexture: { $ref: "#/$defs/I3SMaterialTexture" },
4128
+ emissiveTexture: { $ref: "#/$defs/I3SMaterialTexture" },
4129
+ emissiveFactor: { type: "array", minItems: 3, maxItems: 3, items: { type: "number" } },
4130
+ alphaMode: { enum: ["opaque", "mask", "blend"] },
4131
+ alphaCutoff: { type: "number" },
4132
+ doubleSided: { type: "boolean" },
4133
+ cullFace: { enum: ["none", "front", "back"] }
4134
+ },
4135
+ required: ["pbrMetallicRoughness", "alphaMode"]
4136
+ }
4137
+ }
4138
+ },
4139
+ required: ["options", "tilesConverted"],
4140
+ $defs: {
4141
+ AttributeValue: {
4142
+ type: "object",
4143
+ properties: {
4144
+ valueType: { type: "string" },
4145
+ encoding: { type: "string" },
4146
+ valuesPerElement: { type: "number" }
4147
+ },
4148
+ required: ["valueType"]
4149
+ },
4150
+ ESRIField: {
4151
+ enum: [
4152
+ "esriFieldTypeDate",
4153
+ "esriFieldTypeSingle",
4154
+ "esriFieldTypeDouble",
4155
+ "esriFieldTypeGUID",
4156
+ "esriFieldTypeGlobalID",
4157
+ "esriFieldTypeInteger",
4158
+ "esriFieldTypeOID",
4159
+ "esriFieldTypeSmallInteger",
4160
+ "esriFieldTypeString"
4161
+ ]
4162
+ },
4163
+ Domain: {
4164
+ type: "object",
4165
+ properties: {
4166
+ type: { type: "string" },
4167
+ name: { type: "string" },
4168
+ description: { type: "string" },
4169
+ fieldType: { type: "string" },
4170
+ range: { type: "array", items: { type: "number" } },
4171
+ codedValues: {
4172
+ type: "array",
4173
+ items: {
4174
+ type: "object",
4175
+ properties: { name: { type: "string" }, code: { type: ["string", "number"] } },
4176
+ required: ["name", "code"]
4177
+ }
4178
+ },
4179
+ mergePolicy: { type: "string" },
4180
+ splitPolicy: { type: "string" }
4181
+ },
4182
+ required: ["type", "name"]
4183
+ },
4184
+ FieldInfo: {
4185
+ type: "object",
4186
+ properties: {
4187
+ fieldName: { type: "string" },
4188
+ visible: { type: "boolean" },
4189
+ isEditable: { type: "boolean" },
4190
+ label: { type: "string" }
4191
+ },
4192
+ required: ["fieldName", "visible", "isEditable", "label"]
4193
+ },
4194
+ I3SMaterialTexture: {
4195
+ type: "object",
4196
+ properties: {
4197
+ textureSetDefinitionId: { type: "number" },
4198
+ texCoord: { type: "number" },
4199
+ factor: { type: "number" }
4200
+ },
4201
+ required: ["textureSetDefinitionId"]
4202
+ }
4203
+ }
4204
+ };
4205
+
4206
+ // src/lib/utils/conversion-dump.ts
3873
4207
  var ConversionDump = class {
3874
4208
  constructor() {
4209
+ /**Restored/resumed dump indicator */
4210
+ this.restored = false;
3875
4211
  this.tilesConverted = {};
3876
4212
  }
3877
4213
  /**
3878
- * Create a dump file with convertion options
3879
- * @param options - converter options
4214
+ * Create a dump with convertion options
4215
+ * @param currentOptions - converter options
3880
4216
  */
3881
- async createDumpFile(options) {
4217
+ async createDump(currentOptions) {
3882
4218
  const {
3883
4219
  tilesetName,
3884
4220
  slpk,
@@ -3893,7 +4229,7 @@ var ConversionDump = class {
3893
4229
  mergeMaterials: mergeMaterials2 = true,
3894
4230
  metadataClass,
3895
4231
  analyze = false
3896
- } = options;
4232
+ } = currentOptions;
3897
4233
  this.options = {
3898
4234
  tilesetName,
3899
4235
  slpk,
@@ -3909,14 +4245,55 @@ var ConversionDump = class {
3909
4245
  metadataClass,
3910
4246
  analyze
3911
4247
  };
3912
- try {
3913
- await writeFile(
3914
- options.outputPath,
3915
- JSON.stringify({ options: this.options }),
3916
- `${options.tilesetName}${DUMP_FILE_SUFFIX}`
3917
- );
3918
- } catch (error) {
3919
- console.log("Can't create dump file", error);
4248
+ const dumpFilename = (0, import_path6.join)(
4249
+ this.options.outputPath,
4250
+ this.options.tilesetName,
4251
+ `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
4252
+ );
4253
+ if (await isFileExists(dumpFilename)) {
4254
+ try {
4255
+ const dump = await openJson(
4256
+ (0, import_path6.join)(this.options.outputPath, this.options.tilesetName),
4257
+ `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
4258
+ );
4259
+ const {
4260
+ options,
4261
+ tilesConverted,
4262
+ textureSetDefinitions,
4263
+ attributeMetadataInfo,
4264
+ materialDefinitions
4265
+ } = dump;
4266
+ const ajv = new import_ajv.default();
4267
+ const dumpJsonValidate = ajv.compile(dumpJsonSchema);
4268
+ const isDumpValid = dumpJsonValidate(dump);
4269
+ if (isDumpValid && (0, import_util.isDeepStrictEqual)(options, JSON.parse(JSON.stringify(this.options)))) {
4270
+ this.tilesConverted = tilesConverted;
4271
+ this.textureSetDefinitions = textureSetDefinitions;
4272
+ this.attributeMetadataInfo = attributeMetadataInfo;
4273
+ this.materialDefinitions = materialDefinitions;
4274
+ this.restored = true;
4275
+ return;
4276
+ }
4277
+ } catch (error) {
4278
+ console.log("Can't open dump file", error);
4279
+ }
4280
+ }
4281
+ await this.deleteDumpFile();
4282
+ }
4283
+ /**
4284
+ * Reset a dump
4285
+ */
4286
+ reset() {
4287
+ this.restored = false;
4288
+ this.tilesConverted = {};
4289
+ if (this.textureSetDefinitions) {
4290
+ delete this.textureSetDefinitions;
4291
+ }
4292
+ if (this.attributeMetadataInfo) {
4293
+ delete this.attributeMetadataInfo;
4294
+ }
4295
+ if (this.materialDefinitions) {
4296
+ delete this.materialDefinitions;
3920
4297
  }
3921
4298
  }
3922
4299
  /**
@@ -3926,13 +4303,29 @@ var ConversionDump = class {
3926
4303
  var _a2;
3927
4304
  if (((_a2 = this.options) == null ? void 0 : _a2.outputPath) && this.options.tilesetName) {
3928
4305
  try {
4306
+ const time = import_process3.default.hrtime();
3929
4307
  await writeFile(
3930
- this.options.outputPath,
4308
+ (0, import_path6.join)(this.options.outputPath, this.options.tilesetName),
3931
4309
  JSON.stringify({
3932
4310
  options: this.options,
3933
- tilesConverted: this.tilesConverted
4311
+ tilesConverted: this.tilesConverted,
4312
+ textureSetDefinitions: this.textureSetDefinitions,
4313
+ attributeMetadataInfo: this.attributeMetadataInfo,
4314
+ materialDefinitions: this.materialDefinitions
3934
4315
  }),
3935
- `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
4316
+ `${this.options.tilesetName}${DUMP_FILE_SUFFIX}.${time[0]}.${time[1]}`
4317
+ );
4318
+ await renameFile(
4319
+ (0, import_path6.join)(
4320
+ this.options.outputPath,
4321
+ this.options.tilesetName,
4322
+ `${this.options.tilesetName}${DUMP_FILE_SUFFIX}.${time[0]}.${time[1]}`
4323
+ ),
4324
+ (0, import_path6.join)(
4325
+ this.options.outputPath,
4326
+ this.options.tilesetName,
4327
+ `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
4328
+ )
3936
4329
  );
3937
4330
  } catch (error) {
3938
4331
  console.log("Can't update dump file", error);
@@ -3944,9 +4337,19 @@ var ConversionDump = class {
3944
4337
  */
3945
4338
  async deleteDumpFile() {
3946
4339
  var _a2;
3947
- if (((_a2 = this.options) == null ? void 0 : _a2.outputPath) && this.options.tilesetName) {
4340
+ if (((_a2 = this.options) == null ? void 0 : _a2.outputPath) && this.options.tilesetName && await isFileExists(
4341
+ (0, import_path6.join)(
4342
+ this.options.outputPath,
4343
+ this.options.tilesetName,
4344
+ `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
4345
+ )
4346
+ )) {
3948
4347
  await removeFile(
3949
- (0, import_path6.join)(this.options.outputPath, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`)
4348
+ (0, import_path6.join)(
4349
+ this.options.outputPath,
4350
+ this.options.tilesetName,
4351
+ `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
4352
+ )
3950
4353
  );
3951
4354
  }
3952
4355
  }
@@ -3971,14 +4374,28 @@ var ConversionDump = class {
3971
4374
  * @param fileName - source filename
3972
4375
  * @param nodeId - nodeId of the node
3973
4376
  */
3974
- async addNode(filename, nodeId) {
4377
+ async addNode(filename, nodeId, dumpMetadata) {
3975
4378
  const { nodes } = this.getRecord(filename) || { nodes: [] };
3976
- nodes.push({ nodeId, done: false, progress: {} });
4379
+ nodes.push({ nodeId, done: false, dumpMetadata });
3977
4380
  if (nodes.length === 1) {
3978
4381
  this.setRecord(filename, { nodes });
3979
4382
  }
3980
4383
  await this.updateDumpFile();
3981
4384
  }
4385
+ /**
4386
+ * Clear dump record got the source filename
4387
+ * @param fileName - source filename
4388
+ */
4389
+ clearDumpRecord(filename) {
4390
+ this.setRecord(filename, { nodes: [] });
4391
+ }
4392
+ /**
4393
+ * Add textures definitions into the dump file
4394
+ * @param textureDefinitions - textures definitions array
4395
+ */
4396
+ addTexturesDefinitions(textureDefinitions) {
4397
+ this.textureSetDefinitions = textureDefinitions;
4398
+ }
3982
4399
  /**
3983
4400
  * Update done status object for the writing resources
3984
4401
  * @param fileName - key - source filename
@@ -3992,6 +4409,9 @@ var ConversionDump = class {
3992
4409
  (element) => element.nodeId === nodeId
3993
4410
  );
3994
4411
  if (nodeDump) {
4412
+ if (!nodeDump.progress) {
4413
+ nodeDump.progress = {};
4414
+ }
3995
4415
  nodeDump.progress[resourceType] = value;
3996
4416
  if (!value) {
3997
4417
  nodeDump.done = false;
@@ -4010,7 +4430,7 @@ var ConversionDump = class {
4010
4430
  if (!sourceId || !resourceType || !outputId)
4011
4431
  continue;
4012
4432
  for (const node of this.tilesConverted[sourceId].nodes) {
4013
- if (node.nodeId === outputId) {
4433
+ if (node.nodeId === outputId && node.progress) {
4014
4434
  node.progress[resourceType] = true;
4015
4435
  let done = false;
4016
4436
  for (const key in node.progress) {
@@ -4020,7 +4440,7 @@ var ConversionDump = class {
4020
4440
  }
4021
4441
  node.done = done;
4022
4442
  if (node.done) {
4023
- node.progress = {};
4443
+ delete node.progress;
4024
4444
  }
4025
4445
  break;
4026
4446
  }
@@ -4029,11 +4449,50 @@ var ConversionDump = class {
4029
4449
  }
4030
4450
  await this.updateDumpFile();
4031
4451
  }
4452
+ /**
4453
+ * Update 3d-tiles-converter dump file
4454
+ * @param filename - source filename
4455
+ * @param nodeId - nodeId
4456
+ * @param done - conversion status
4457
+ */
4458
+ async updateConvertedNodesDumpFile(filename, nodeId, done) {
4459
+ var _a2;
4460
+ const nodeDump = (_a2 = this.tilesConverted[filename]) == null ? void 0 : _a2.nodes.find(
4461
+ (element) => element.nodeId === nodeId
4462
+ );
4463
+ if (nodeDump) {
4464
+ nodeDump.done = done;
4465
+ await this.updateDumpFile();
4466
+ }
4467
+ }
4468
+ /**
4469
+ * Check is source file conversion complete
4470
+ * @param filename - source filename
4471
+ * @returns true if source file conversion complete
4472
+ */
4473
+ isFileConversionComplete(filename) {
4474
+ var _a2, _b, _c;
4475
+ let result = true;
4476
+ for (const node of ((_a2 = this.tilesConverted[filename]) == null ? void 0 : _a2.nodes) || []) {
4477
+ if (!node.done) {
4478
+ result = false;
4479
+ break;
4480
+ }
4481
+ }
4482
+ return result && ((_c = (_b = this.tilesConverted[filename]) == null ? void 0 : _b.nodes) == null ? void 0 : _c.length) > 0;
4483
+ }
4484
+ /**
4485
+ * Set materialDefinitions into a dump
4486
+ * @param materialDefinitions - Array materialDefinitions
4487
+ */
4488
+ setMaterialsDefinitions(materialDefinitions) {
4489
+ this.materialDefinitions = materialDefinitions;
4490
+ }
4032
4491
  };
4033
4492
 
4034
4493
  // src/i3s-converter/i3s-converter.ts
4035
4494
  var _a;
4036
- var ION_DEFAULT_TOKEN = (_a = import_process3.default.env) == null ? void 0 : _a.IonToken;
4495
+ var ION_DEFAULT_TOKEN = (_a = import_process4.default.env) == null ? void 0 : _a.IonToken;
4037
4496
  var HARDCODED_NODES_PER_PAGE = 64;
4038
4497
  var _3D_TILES = "3DTILES";
4039
4498
  var _3D_OBJECT_LAYER_TYPE = "3DObject";
@@ -4114,7 +4573,7 @@ var I3SConverter = class {
4114
4573
  console.log(BROWSER_ERROR_MESSAGE);
4115
4574
  return BROWSER_ERROR_MESSAGE;
4116
4575
  }
4117
- this.conversionStartTime = import_process3.default.hrtime();
4576
+ this.conversionStartTime = import_process4.default.hrtime();
4118
4577
  const {
4119
4578
  tilesetName,
4120
4579
  slpk,
@@ -4163,7 +4622,6 @@ var I3SConverter = class {
4163
4622
  if (slpk) {
4164
4623
  this.nodePages.useWriteFunction(writeFileForSlpk);
4165
4624
  }
4166
- await this.conversionDump.createDumpFile(options);
4167
4625
  try {
4168
4626
  const preloadOptions = await this._fetchPreloadOptions();
4169
4627
  let tilesetUrl = inputUrl;
@@ -4298,13 +4756,37 @@ var I3SConverter = class {
4298
4756
  async _createAndSaveTileset(outputPath, tilesetName) {
4299
4757
  var _a2, _b, _c;
4300
4758
  const tilesetPath = (0, import_path7.join)(`${outputPath}`, `${tilesetName}`);
4759
+ await this.conversionDump.createDump(this.options);
4760
+ if (this.conversionDump.restored && this.options.inquirer) {
4761
+ const result = await this.options.inquirer.prompt([
4762
+ {
4763
+ name: "resumeConversion",
4764
+ type: "confirm",
4765
+ message: "Dump file of the previous conversion exists, do you want to resume that conversion?"
4766
+ }
4767
+ ]);
4768
+ if (!result.resumeConversion) {
4769
+ this.conversionDump.reset();
4770
+ }
4771
+ }
4772
+ this.layers0Path = (0, import_path7.join)(tilesetPath, "SceneServer", "layers", "0");
4773
+ const removePath = this.conversionDump.restored ? (0, import_path7.join)(this.layers0Path, "nodepages") : tilesetPath;
4301
4774
  try {
4302
- await removeDir(tilesetPath);
4775
+ await removeDir(removePath);
4303
4776
  } catch (e) {
4304
4777
  }
4305
- this.layers0Path = (0, import_path7.join)(tilesetPath, "SceneServer", "layers", "0");
4778
+ if (this.conversionDump.restored && this.conversionDump.attributeMetadataInfo) {
4779
+ this.attributeMetadataInfo.fromObject(this.conversionDump.attributeMetadataInfo);
4780
+ }
4306
4781
  this.materialDefinitions = [];
4307
4782
  this.materialMap = /* @__PURE__ */ new Map();
4783
+ if (this.conversionDump.restored && this.conversionDump.materialDefinitions) {
4784
+ for (let i = 0; i < this.conversionDump.materialDefinitions.length; i++) {
4785
+ const hash = (0, import_md52.default)(JSON.stringify(this.conversionDump.materialDefinitions[i]));
4786
+ this.materialMap.set(hash, i);
4787
+ }
4788
+ this.materialDefinitions = this.conversionDump.materialDefinitions;
4789
+ }
4308
4790
  const sourceRootTile = this.sourceTileset.root;
4309
4791
  const sourceBoundingVolume = (0, import_tiles.createBoundingVolume)(
4310
4792
  sourceRootTile.boundingVolume,
@@ -4343,6 +4825,9 @@ var I3SConverter = class {
4343
4825
  if (this.attributeMetadataInfo.attributeStorageInfo.length) {
4344
4826
  this.layers0.layerType = _3D_OBJECT_LAYER_TYPE;
4345
4827
  }
4828
+ if (this.conversionDump.restored && this.conversionDump.textureSetDefinitions) {
4829
+ this.layers0.textureSetDefinitions = this.conversionDump.textureSetDefinitions;
4830
+ }
4346
4831
  this.layers0.materialDefinitions = this.materialDefinitions;
4347
4832
  this.layers0.geometryDefinitions = (0, import_json_map_transform8.default)(
4348
4833
  this.geometryConfigs.map((config) => ({
@@ -4423,9 +4908,9 @@ var I3SConverter = class {
4423
4908
  if (this.options.slpk) {
4424
4909
  const slpkTilesetPath = (0, import_path7.join)(tilesetPath, "SceneServer", "layers", "0");
4425
4910
  const slpkFileName = `${tilesetPath}.slpk`;
4426
- await (0, import_zip.createZip)(slpkTilesetPath, slpkFileName, async (fileList) => ({
4911
+ await (0, import_zip2.createZip)(slpkTilesetPath, slpkFileName, async (fileList) => ({
4427
4912
  path: "@specialIndexFileHASH128@",
4428
- file: await (0, import_zip.composeHashFile)(fileList)
4913
+ file: await (0, import_zip2.composeHashFile)(fileList)
4429
4914
  }));
4430
4915
  try {
4431
4916
  await removeDir(tilesetPath);
@@ -4460,7 +4945,13 @@ var I3SConverter = class {
4460
4945
  transformationMatrix = transformationMatrix.multiplyRight(sourceTile.transform);
4461
4946
  }
4462
4947
  const parentNode = parentNodes[0];
4463
- const childNodes = await this._createNode(parentNode, sourceTile, transformationMatrix);
4948
+ const restoreResult = await this._restoreNode(parentNode, sourceTile, transformationMatrix);
4949
+ let childNodes;
4950
+ if (restoreResult === null) {
4951
+ childNodes = await this._createNode(parentNode, sourceTile, transformationMatrix);
4952
+ } else {
4953
+ childNodes = restoreResult;
4954
+ }
4464
4955
  await parentNode.addChildren(childNodes);
4465
4956
  const newTraversalProps = {
4466
4957
  transform: transformationMatrix,
@@ -4494,6 +4985,88 @@ var I3SConverter = class {
4494
4985
  await node.save();
4495
4986
  }
4496
4987
  }
4988
+ /**
4989
+ * Generate NodeIndexDocument
4990
+ * @param boundingVolumes - Bounding volumes
4991
+ * @param resources - converted or dumped node resources data
4992
+ * @param parentNode - 3DNodeIndexDocument of parent node
4993
+ * @param sourceTile - source 3DTile data
4994
+ * @param isDumped - indicator if the node is dumped
4995
+ * @return NodeIndexDocument, nodeInPage and node data
4996
+ */
4997
+ async _generateNodeIndexDocument(boundingVolumes, resources, parentNode, sourceTile, isDumped) {
4998
+ this.layersHasTexture = this.layersHasTexture || Boolean(
4999
+ "texture" in resources && resources.texture || "texelCountHint" in resources && resources.texelCountHint
5000
+ );
5001
+ if (this.generateBoundingVolumes && resources.boundingVolumes) {
5002
+ boundingVolumes = resources.boundingVolumes;
5003
+ }
5004
+ const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);
5005
+ const maxScreenThresholdSQ = lodSelection.find(
5006
+ (val) => val.metricType === "maxScreenThresholdSQ"
5007
+ ) || { maxError: 0 };
5008
+ if (isDumped) {
5009
+ const draftObb = {
5010
+ center: [],
5011
+ halfSize: [],
5012
+ quaternion: []
5013
+ };
5014
+ await this.nodePages.push({ index: 0, obb: draftObb }, parentNode.inPageId);
5015
+ }
5016
+ const nodeInPage = await this._updateNodeInNodePages(
5017
+ maxScreenThresholdSQ,
5018
+ boundingVolumes,
5019
+ sourceTile,
5020
+ parentNode.inPageId,
5021
+ resources
5022
+ );
5023
+ const nodeData = await NodeIndexDocument.createNodeIndexDocument(
5024
+ parentNode,
5025
+ boundingVolumes,
5026
+ lodSelection,
5027
+ nodeInPage,
5028
+ resources
5029
+ );
5030
+ const node = await new NodeIndexDocument(nodeInPage.index, this).addData(nodeData);
5031
+ return { node, nodeInPage, nodeData };
5032
+ }
5033
+ /**
5034
+ * Restore 3DNodeIndexDocument from a comversion dump file
5035
+ * @param parentNode - 3DNodeIndexDocument of parent node
5036
+ * @param sourceTile - source 3DTile data
5037
+ * @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying
5038
+ * transform of all parent tiles and transform of the current tile
5039
+ */
5040
+ async _restoreNode(parentNode, sourceTile, transformationMatrix) {
5041
+ this._checkAddRefinementTypeForTile(sourceTile);
5042
+ await this._updateTilesetOptions();
5043
+ if (this.conversionDump.restored && sourceTile.id && this.conversionDump.isFileConversionComplete(sourceTile.id)) {
5044
+ const sourceBoundingVolume = (0, import_tiles.createBoundingVolume)(
5045
+ sourceTile.boundingVolume,
5046
+ transformationMatrix,
5047
+ null
5048
+ );
5049
+ let boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);
5050
+ const nodes = [];
5051
+ for (const convertedNode of this.conversionDump.tilesConverted[sourceTile.id].nodes) {
5052
+ const { node } = await this._generateNodeIndexDocument(
5053
+ boundingVolumes,
5054
+ {
5055
+ ...convertedNode.dumpMetadata,
5056
+ nodeId: convertedNode.nodeId
5057
+ },
5058
+ parentNode,
5059
+ sourceTile,
5060
+ true
5061
+ );
5062
+ nodes.push(node);
5063
+ }
5064
+ return nodes;
5065
+ } else if (this.conversionDump.restored && sourceTile.id) {
5066
+ this.conversionDump.clearDumpRecord(sourceTile.id);
5067
+ }
5068
+ return null;
5069
+ }
4497
5070
  /**
4498
5071
  * Convert tile to one or more I3S nodes
4499
5072
  * @param parentNode - 3DNodeIndexDocument of parent node
@@ -4503,6 +5076,7 @@ var I3SConverter = class {
4503
5076
  * @param level - tree level
4504
5077
  */
4505
5078
  async _createNode(parentNode, sourceTile, transformationMatrix) {
5079
+ var _a2;
4506
5080
  this._checkAddRefinementTypeForTile(sourceTile);
4507
5081
  await this._updateTilesetOptions();
4508
5082
  let tileContent = null;
@@ -4519,6 +5093,11 @@ var I3SConverter = class {
4519
5093
  let boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);
4520
5094
  const propertyTable = getPropertyTable(tileContent, this.options.metadataClass);
4521
5095
  this.createAttributeStorageInfo(tileContent, propertyTable);
5096
+ this.conversionDump.attributeMetadataInfo = {
5097
+ attributeStorageInfo: this.attributeMetadataInfo.attributeStorageInfo,
5098
+ fields: this.attributeMetadataInfo.fields,
5099
+ popupInfo: this.attributeMetadataInfo.popupInfo
5100
+ };
4522
5101
  const resourcesData = await this._convertResources(
4523
5102
  sourceTile,
4524
5103
  transformationMatrix,
@@ -4543,33 +5122,28 @@ var I3SConverter = class {
4543
5122
  boundingVolumes: null
4544
5123
  };
4545
5124
  for (const resources of resourcesData || [emptyResources]) {
4546
- this.layersHasTexture = this.layersHasTexture || Boolean(resources.texture);
4547
- if (this.generateBoundingVolumes && resources.boundingVolumes) {
4548
- boundingVolumes = resources.boundingVolumes;
4549
- }
4550
- const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);
4551
- const maxScreenThresholdSQ = lodSelection.find(
4552
- (val) => val.metricType === "maxScreenThresholdSQ"
4553
- ) || { maxError: 0 };
4554
- const nodeInPage = await this._updateNodeInNodePages(
4555
- maxScreenThresholdSQ,
5125
+ const { node, nodeInPage, nodeData } = await this._generateNodeIndexDocument(
4556
5126
  boundingVolumes,
4557
- sourceTile,
4558
- parentNode.inPageId,
4559
- resources
4560
- );
4561
- const nodeData = await NodeIndexDocument.createNodeIndexDocument(
5127
+ resources,
4562
5128
  parentNode,
4563
- boundingVolumes,
4564
- lodSelection,
4565
- nodeInPage,
4566
- resources
5129
+ sourceTile,
5130
+ false
4567
5131
  );
4568
- const node = await new NodeIndexDocument(nodeInPage.index, this).addData(nodeData);
4569
5132
  nodes.push(node);
4570
5133
  if (nodeInPage.mesh) {
4571
5134
  if (sourceTile.id) {
4572
- await this.conversionDump.addNode(sourceTile.id, nodeInPage.index);
5135
+ const dumpMetadata = {
5136
+ boundingVolumes: resources.boundingVolumes,
5137
+ attributesCount: (_a2 = resources.attributes) == null ? void 0 : _a2.length,
5138
+ featureCount: resources.featureCount,
5139
+ geometry: Boolean(resources.geometry),
5140
+ hasUvRegions: resources.hasUvRegions,
5141
+ materialId: nodeInPage.mesh.material.definition,
5142
+ texelCountHint: nodeInPage.mesh.material.texelCountHint,
5143
+ vertexCount: resources.vertexCount
5144
+ };
5145
+ this.conversionDump.setMaterialsDefinitions(this.materialDefinitions);
5146
+ await this.conversionDump.addNode(sourceTile.id, nodeInPage.index, dumpMetadata);
4573
5147
  }
4574
5148
  await this._writeResources(resources, node.id, sourceTile);
4575
5149
  }
@@ -4637,7 +5211,7 @@ var I3SConverter = class {
4637
5211
  * @return the node object in node pages
4638
5212
  */
4639
5213
  async _updateNodeInNodePages(maxScreenThresholdSQ, boundingVolumes, sourceTile, parentId, resources) {
4640
- const { meshMaterial, texture, vertexCount, featureCount, geometry, hasUvRegions } = resources;
5214
+ const { vertexCount, featureCount, geometry, hasUvRegions } = resources;
4641
5215
  const nodeInPage = {
4642
5216
  index: 0,
4643
5217
  lodThreshold: maxScreenThresholdSQ.maxError,
@@ -4647,7 +5221,12 @@ var I3SConverter = class {
4647
5221
  if (geometry && this.isContentSupported(sourceTile)) {
4648
5222
  nodeInPage.mesh = {
4649
5223
  geometry: {
4650
- definition: this.findOrCreateGeometryDefinition(Boolean(texture), hasUvRegions),
5224
+ definition: this.findOrCreateGeometryDefinition(
5225
+ Boolean(
5226
+ "texture" in resources && resources.texture || "texelCountHint" in resources && resources.texelCountHint
5227
+ ),
5228
+ hasUvRegions
5229
+ ),
4651
5230
  resource: 0
4652
5231
  },
4653
5232
  attribute: {
@@ -4658,7 +5237,7 @@ var I3SConverter = class {
4658
5237
  }
4659
5238
  };
4660
5239
  }
4661
- let nodeId = resources.nodeId;
5240
+ let nodeId = "nodeId" in resources ? resources.nodeId : void 0;
4662
5241
  let node;
4663
5242
  if (!nodeId) {
4664
5243
  node = await this.nodePages.push(nodeInPage, parentId);
@@ -4669,12 +5248,16 @@ var I3SConverter = class {
4669
5248
  console.log(`[warning]: node ${node.index} is created with empty content`);
4670
5249
  }
4671
5250
  NodePages.updateAll(node, nodeInPage);
4672
- if (meshMaterial) {
4673
- NodePages.updateMaterialByNodeId(node, this._findOrCreateMaterial(meshMaterial));
5251
+ if ("meshMaterial" in resources && resources.meshMaterial) {
5252
+ NodePages.updateMaterialByNodeId(node, this._findOrCreateMaterial(resources.meshMaterial));
5253
+ } else if ("materialId" in resources && resources.materialId !== null) {
5254
+ NodePages.updateMaterialByNodeId(node, resources.materialId);
4674
5255
  }
4675
- if (texture) {
4676
- const texelCountHint = texture.image.height * texture.image.width;
5256
+ if ("texture" in resources && resources.texture) {
5257
+ const texelCountHint = resources.texture.image.height * resources.texture.image.width;
4677
5258
  NodePages.updateTexelCountHintByNodeId(node, texelCountHint);
5259
+ } else if ("texelCountHint" in resources && resources.texelCountHint) {
5260
+ NodePages.updateTexelCountHintByNodeId(node, resources.texelCountHint);
4678
5261
  }
4679
5262
  if (vertexCount) {
4680
5263
  this.vertexCounter += vertexCount;
@@ -4937,6 +5520,9 @@ var I3SConverter = class {
4937
5520
  if (!this.layers0.textureSetDefinitions.length) {
4938
5521
  this.layers0.textureSetDefinitions.push({ formats });
4939
5522
  this.layers0.textureSetDefinitions.push({ formats, atlas: true });
5523
+ if (this.layers0.textureSetDefinitions) {
5524
+ this.conversionDump.addTexturesDefinitions(this.layers0.textureSetDefinitions);
5525
+ }
4940
5526
  }
4941
5527
  }
4942
5528
  }
@@ -5088,7 +5674,7 @@ var I3SConverter = class {
5088
5674
  const { tilesCount, tilesWithAddRefineCount } = this.refinementCounter;
5089
5675
  const addRefinementPercentage = tilesWithAddRefineCount ? tilesWithAddRefineCount / tilesCount * 100 : 0;
5090
5676
  const filesSize = await calculateFilesSize(params);
5091
- const diff = import_process3.default.hrtime(this.conversionStartTime);
5677
+ const diff = import_process4.default.hrtime(this.conversionStartTime);
5092
5678
  const conversionTime = timeConverter(diff);
5093
5679
  console.log(`------------------------------------------------`);
5094
5680
  console.log(`Finishing conversion of ${_3D_TILES}`);
@@ -5109,18 +5695,18 @@ var I3SConverter = class {
5109
5695
  "cesium-ion": { accessToken: this.options.token || ION_DEFAULT_TOKEN }
5110
5696
  };
5111
5697
  const preloadOptions = await this.Loader.preload(this.options.inputUrl, options);
5112
- this.refreshTokenTime = import_process3.default.hrtime();
5698
+ this.refreshTokenTime = import_process4.default.hrtime();
5113
5699
  return { ...options, ...preloadOptions };
5114
5700
  }
5115
5701
  /**
5116
5702
  * Update options of source tileset
5117
5703
  */
5118
5704
  async _updateTilesetOptions() {
5119
- const diff = import_process3.default.hrtime(this.refreshTokenTime);
5705
+ const diff = import_process4.default.hrtime(this.refreshTokenTime);
5120
5706
  if (diff[0] < REFRESH_TOKEN_TIMEOUT) {
5121
5707
  return;
5122
5708
  }
5123
- this.refreshTokenTime = import_process3.default.hrtime();
5709
+ this.refreshTokenTime = import_process4.default.hrtime();
5124
5710
  const preloadOptions = await this._fetchPreloadOptions();
5125
5711
  if (preloadOptions.headers) {
5126
5712
  this.loadOptions.fetch = {
@@ -5153,7 +5739,7 @@ var I3SConverter = class {
5153
5739
 
5154
5740
  // src/3d-tiles-converter/3d-tiles-converter.ts
5155
5741
  var import_path8 = require("path");
5156
- var import_process4 = __toESM(require("process"), 1);
5742
+ var import_process5 = __toESM(require("process"), 1);
5157
5743
  var import_json_map_transform10 = __toESM(require("json-map-transform"), 1);
5158
5744
  var import_core15 = require("@loaders.gl/core");
5159
5745
  var import_i3s2 = require("@loaders.gl/i3s");
@@ -5529,7 +6115,9 @@ var B3dmConverter = class {
5529
6115
  // src/3d-tiles-converter/helpers/load-i3s.ts
5530
6116
  var import_core14 = require("@loaders.gl/core");
5531
6117
  var import_i3s = require("@loaders.gl/i3s");
5532
- var loadI3SContent = async (sourceTileset, sourceTile, tilesetLoadOptions) => {
6118
+ var import_loader_utils5 = require("@loaders.gl/loader-utils");
6119
+ var import_zip3 = require("@loaders.gl/zip");
6120
+ var loadI3SContent = async (sourceTileset, sourceTile, tilesetLoadOptions, slpkFilesystem) => {
5533
6121
  if (!sourceTileset || !sourceTile.contentUrl) {
5534
6122
  return null;
5535
6123
  }
@@ -5537,10 +6125,12 @@ var loadI3SContent = async (sourceTileset, sourceTile, tilesetLoadOptions) => {
5537
6125
  ...tilesetLoadOptions,
5538
6126
  i3s: {
5539
6127
  ...tilesetLoadOptions.i3s,
6128
+ // @ts-expect-error
5540
6129
  isTileset: false,
6130
+ // @ts-expect-error
5541
6131
  isTileHeader: false,
5542
6132
  _tileOptions: {
5543
- attributeUrls: sourceTile.attributeUrls,
6133
+ attributeUrls: sourceTile.attributeUrls || [],
5544
6134
  textureUrl: sourceTile.textureUrl,
5545
6135
  textureFormat: sourceTile.textureFormat,
5546
6136
  textureLoaderOptions: sourceTile.textureLoaderOptions,
@@ -5550,20 +6140,64 @@ var loadI3SContent = async (sourceTileset, sourceTile, tilesetLoadOptions) => {
5550
6140
  },
5551
6141
  _tilesetOptions: {
5552
6142
  store: sourceTileset.store,
6143
+ // @ts-expect-error
5553
6144
  attributeStorageInfo: sourceTileset.attributeStorageInfo,
6145
+ // @ts-expect-error
5554
6146
  fields: sourceTileset.fields
5555
6147
  }
5556
6148
  }
5557
6149
  };
5558
- const tileContent = await (0, import_core14.load)(sourceTile.contentUrl, import_i3s.I3SLoader, loadOptions);
6150
+ const tileContent = await loadFromArchive2(
6151
+ sourceTile.contentUrl,
6152
+ import_i3s.I3SLoader,
6153
+ loadOptions,
6154
+ slpkFilesystem
6155
+ );
5559
6156
  return tileContent;
5560
6157
  };
6158
+ async function openSLPK(url) {
6159
+ const slpkUrlParts = url.split(".slpk");
6160
+ const { slpkFileName } = getSlpkUrlParts(url) || {};
6161
+ if (slpkFileName) {
6162
+ const slpkFileName2 = `${slpkUrlParts[0]}.slpk`;
6163
+ const fileProvider = new import_loader_utils5.FileHandleFile(slpkFileName2);
6164
+ const archive = await (0, import_i3s.parseSLPKArchive)(fileProvider, void 0, slpkFileName2);
6165
+ const fileSystem = new import_zip3.ZipFileSystem(archive);
6166
+ return fileSystem;
6167
+ }
6168
+ return null;
6169
+ }
6170
+ async function loadFromArchive2(url, loader, loadOptions, fileSystem) {
6171
+ const slpkUrlParts = getSlpkUrlParts(url);
6172
+ if (fileSystem !== null && slpkUrlParts !== null) {
6173
+ const { internalFileName } = slpkUrlParts;
6174
+ const content = await (0, import_core14.load)(internalFileName, loader, {
6175
+ ...loadOptions,
6176
+ fetch: fileSystem.fetch.bind(fileSystem)
6177
+ });
6178
+ return content;
6179
+ }
6180
+ return await (0, import_core14.load)(url, loader, loadOptions);
6181
+ }
6182
+ function getSlpkUrlParts(url) {
6183
+ const slpkUrlParts = url.split(".slpk");
6184
+ let result;
6185
+ if (slpkUrlParts.length === 1) {
6186
+ result = null;
6187
+ } else if (slpkUrlParts.length === 2) {
6188
+ result = { slpkFileName: `${slpkUrlParts[0]}.slpk`, internalFileName: slpkUrlParts[1].slice(1) };
6189
+ } else {
6190
+ throw new Error("Unexpected URL format");
6191
+ }
6192
+ return result;
6193
+ }
5561
6194
 
5562
6195
  // src/3d-tiles-converter/3d-tiles-converter.ts
5563
6196
  var I3S = "I3S";
5564
6197
  var Tiles3DConverter = class {
5565
6198
  constructor() {
5566
6199
  this.workerSource = {};
6200
+ this.slpkFilesystem = null;
5567
6201
  this.loaderOptions = {
5568
6202
  _nodeWorkers: true,
5569
6203
  reuseWorkers: true,
@@ -5583,6 +6217,7 @@ var Tiles3DConverter = class {
5583
6217
  this.sourceTileset = null;
5584
6218
  this.attributeStorageInfo = null;
5585
6219
  this.workerSource = {};
6220
+ this.conversionDump = new ConversionDump();
5586
6221
  }
5587
6222
  /**
5588
6223
  * Convert i3s format data to 3dTiles
@@ -5599,13 +6234,23 @@ var Tiles3DConverter = class {
5599
6234
  console.log(BROWSER_ERROR_MESSAGE);
5600
6235
  return BROWSER_ERROR_MESSAGE;
5601
6236
  }
5602
- const { inputUrl, outputPath, tilesetName, maxDepth, egmFilePath } = options;
5603
- this.conversionStartTime = import_process4.default.hrtime();
5604
- this.options = { maxDepth };
6237
+ const { inputUrl, outputPath, tilesetName, maxDepth, egmFilePath, inquirer } = options;
6238
+ this.conversionStartTime = import_process5.default.hrtime();
6239
+ this.options = { maxDepth, inquirer };
5605
6240
  console.log("Loading egm file...");
5606
6241
  this.geoidHeightModel = await (0, import_core15.load)(egmFilePath, PGMLoader);
5607
6242
  console.log("Loading egm file completed!");
5608
- this.sourceTileset = await (0, import_core15.load)(inputUrl, import_i3s2.I3SLoader, this.loaderOptions);
6243
+ this.slpkFilesystem = await openSLPK(inputUrl);
6244
+ this.sourceTileset = await loadFromArchive2(
6245
+ inputUrl,
6246
+ import_i3s2.I3SLoader,
6247
+ {
6248
+ ...this.loaderOptions,
6249
+ // @ts-expect-error `isTileset` can be boolean of 'auto' but TS expects a string
6250
+ i3s: { ...this.loaderOptions.i3s, isTileset: true }
6251
+ },
6252
+ this.slpkFilesystem
6253
+ );
5609
6254
  if (!this.sourceTileset) {
5610
6255
  return;
5611
6256
  }
@@ -5615,9 +6260,24 @@ var Tiles3DConverter = class {
5615
6260
  }
5616
6261
  this.tilesetPath = (0, import_path8.join)(`${outputPath}`, `${tilesetName}`);
5617
6262
  this.attributeStorageInfo = this.sourceTileset.attributeStorageInfo;
5618
- try {
5619
- await removeDir(this.tilesetPath);
5620
- } catch (e) {
6263
+ await this.conversionDump.createDump(options);
6264
+ if (this.conversionDump.restored && this.options.inquirer) {
6265
+ const result = await this.options.inquirer.prompt([
6266
+ {
6267
+ name: "resumeConversion",
6268
+ type: "confirm",
6269
+ message: "Dump file of the previous conversion exists, do you want to resume that conversion?"
6270
+ }
6271
+ ]);
6272
+ if (!result.resumeConversion) {
6273
+ this.conversionDump.reset();
6274
+ }
6275
+ }
6276
+ if (!this.conversionDump.restored) {
6277
+ try {
6278
+ await removeDir(this.tilesetPath);
6279
+ } catch (e) {
6280
+ }
5621
6281
  }
5622
6282
  const rootTile = {
5623
6283
  boundingVolume: {
@@ -5630,7 +6290,11 @@ var Tiles3DConverter = class {
5630
6290
  await this._addChildren(rootNode, rootTile, 1);
5631
6291
  const tileset = (0, import_json_map_transform10.default)({ root: rootTile }, TILESET());
5632
6292
  await writeFile(this.tilesetPath, JSON.stringify(tileset), "tileset.json");
5633
- this._finishConversion({ slpk: false, outputPath, tilesetName });
6293
+ await this.conversionDump.deleteDumpFile();
6294
+ await this._finishConversion({ slpk: false, outputPath, tilesetName });
6295
+ if (this.slpkFilesystem) {
6296
+ this.slpkFilesystem.destroy();
6297
+ }
5634
6298
  const workerFarm = import_worker_utils2.WorkerFarm.getWorkerFarm({});
5635
6299
  workerFarm.destroy();
5636
6300
  }
@@ -5644,7 +6308,18 @@ var Tiles3DConverter = class {
5644
6308
  async convertChildNode(parentSourceNode, parentNode, level, childNodeInfo) {
5645
6309
  const sourceChild = await this._loadChildNode(parentSourceNode, childNodeInfo);
5646
6310
  if (sourceChild.contentUrl) {
5647
- const content = await loadI3SContent(this.sourceTileset, sourceChild, this.loaderOptions);
6311
+ if (this.conversionDump.restored && this.conversionDump.isFileConversionComplete(`${sourceChild.id}.b3dm`) && (sourceChild.obb || sourceChild.mbs)) {
6312
+ const { child: child2 } = this._createChildAndBoundingVolume(sourceChild);
6313
+ parentNode.children.push(child2);
6314
+ await this._addChildren(sourceChild, child2, level + 1);
6315
+ return;
6316
+ }
6317
+ const content = await loadI3SContent(
6318
+ this.sourceTileset,
6319
+ sourceChild,
6320
+ this.loaderOptions,
6321
+ this.slpkFilesystem
6322
+ );
5648
6323
  if (!content) {
5649
6324
  await this._addChildren(sourceChild, parentNode, level + 1);
5650
6325
  return;
@@ -5654,29 +6329,21 @@ var Tiles3DConverter = class {
5654
6329
  if (this.attributeStorageInfo) {
5655
6330
  featureAttributes = await this._loadChildAttributes(sourceChild, this.attributeStorageInfo);
5656
6331
  }
5657
- if (!sourceChild.obb) {
5658
- sourceChild.obb = createObbFromMbs(sourceChild.mbs);
5659
- }
5660
- const boundingVolume = {
5661
- box: i3sObbTo3dTilesObb(sourceChild.obb, this.geoidHeightModel)
5662
- };
5663
- const child = {
5664
- boundingVolume,
5665
- geometricError: convertScreenThresholdToGeometricError(sourceChild),
5666
- children: []
5667
- };
6332
+ const { child, boundingVolume } = this._createChildAndBoundingVolume(sourceChild);
5668
6333
  const i3sAttributesData = {
5669
6334
  tileContent: content,
5670
- box: boundingVolume.box,
6335
+ box: boundingVolume.box || [],
5671
6336
  textureFormat: sourceChild.textureFormat
5672
6337
  };
5673
6338
  const b3dmConverter = new B3dmConverter();
5674
6339
  const b3dm = await b3dmConverter.convert(i3sAttributesData, featureAttributes);
5675
- child.content = {
5676
- uri: `${sourceChild.id}.b3dm`,
5677
- boundingVolume
5678
- };
6340
+ await this.conversionDump.addNode(`${sourceChild.id}.b3dm`, sourceChild.id);
5679
6341
  await writeFile(this.tilesetPath, new Uint8Array(b3dm), `${sourceChild.id}.b3dm`);
6342
+ await this.conversionDump.updateConvertedNodesDumpFile(
6343
+ `${sourceChild.id}.b3dm`,
6344
+ sourceChild.id,
6345
+ true
6346
+ );
5680
6347
  parentNode.children.push(child);
5681
6348
  await this._addChildren(sourceChild, child, level + 1);
5682
6349
  } else {
@@ -5716,15 +6383,39 @@ var Tiles3DConverter = class {
5716
6383
  const options = {
5717
6384
  i3s: {
5718
6385
  ...this.loaderOptions,
6386
+ // @ts-expect-error
5719
6387
  isTileHeader: true,
5720
6388
  loadContent: false
5721
6389
  }
5722
6390
  };
5723
6391
  console.log(`Node conversion: ${nodeUrl}`);
5724
- header = await (0, import_core15.load)(nodeUrl, import_i3s2.I3SLoader, options);
6392
+ header = await loadFromArchive2(nodeUrl, import_i3s2.I3SLoader, options, this.slpkFilesystem);
5725
6393
  }
5726
6394
  return header;
5727
6395
  }
6396
+ /**
6397
+ * Create child and child's boundingVolume for the converted node
6398
+ * @param sourceChild
6399
+ * @returns child and child's boundingVolume
6400
+ */
6401
+ _createChildAndBoundingVolume(sourceChild) {
6402
+ if (!sourceChild.obb) {
6403
+ sourceChild.obb = createObbFromMbs(sourceChild.mbs);
6404
+ }
6405
+ const boundingVolume = {
6406
+ box: i3sObbTo3dTilesObb(sourceChild.obb, this.geoidHeightModel)
6407
+ };
6408
+ const child = {
6409
+ boundingVolume,
6410
+ geometricError: convertScreenThresholdToGeometricError(sourceChild),
6411
+ children: [],
6412
+ content: {
6413
+ uri: `${sourceChild.id}.b3dm`,
6414
+ boundingVolume
6415
+ }
6416
+ };
6417
+ return { boundingVolume, child };
6418
+ }
5728
6419
  /**
5729
6420
  * Make an url of a resource from its relative url having the base url
5730
6421
  * @param baseUrl the base url. A resulting url will be related from this url
@@ -5762,7 +6453,7 @@ var Tiles3DConverter = class {
5762
6453
  attributeName: attribute.name,
5763
6454
  attributeType: this._getAttributeType(attribute)
5764
6455
  };
5765
- promises.push((0, import_core15.load)(inputUrl, import_i3s2.I3SAttributeLoader, options));
6456
+ promises.push(loadFromArchive2(inputUrl, import_i3s2.I3SAttributeLoader, options, this.slpkFilesystem));
5766
6457
  }
5767
6458
  const attributesList = await Promise.all(promises);
5768
6459
  this._replaceNestedArrays(attributesList);
@@ -5801,7 +6492,7 @@ var Tiles3DConverter = class {
5801
6492
  */
5802
6493
  async _finishConversion(params) {
5803
6494
  const filesSize = await calculateFilesSize(params);
5804
- const diff = import_process4.default.hrtime(this.conversionStartTime);
6495
+ const diff = import_process5.default.hrtime(this.conversionStartTime);
5805
6496
  const conversionTime = timeConverter(diff);
5806
6497
  console.log(`------------------------------------------------`);
5807
6498
  console.log(`Finish conversion of ${I3S}`);