@loaders.gl/tile-converter 4.1.0 → 4.2.0-alpha.1
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.
- package/dist/converter.min.cjs +82 -82
- package/dist/deps-installer/deps-installer.js +1 -1
- package/dist/deps-installer/deps-installer.js.map +1 -1
- package/dist/i3s-converter/helpers/attribute-metadata-info.d.ts +10 -0
- package/dist/i3s-converter/helpers/attribute-metadata-info.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/attribute-metadata-info.js +5 -0
- package/dist/i3s-converter/helpers/attribute-metadata-info.js.map +1 -1
- package/dist/i3s-converter/helpers/node-index-document.d.ts +2 -1
- package/dist/i3s-converter/helpers/node-index-document.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/node-index-document.js +6 -8
- package/dist/i3s-converter/helpers/node-index-document.js.map +1 -1
- package/dist/i3s-converter/i3s-converter.d.ts +18 -0
- package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
- package/dist/i3s-converter/i3s-converter.js +121 -24
- package/dist/i3s-converter/i3s-converter.js.map +1 -1
- package/dist/index.cjs +283 -56
- package/dist/lib/utils/conversion-dump.d.ts +55 -5
- package/dist/lib/utils/conversion-dump.d.ts.map +1 -1
- package/dist/lib/utils/conversion-dump.js +77 -17
- package/dist/lib/utils/conversion-dump.js.map +1 -1
- package/dist/pgm-loader.js +1 -1
- package/dist/pgm-loader.js.map +1 -1
- package/package.json +14 -14
- package/src/i3s-converter/helpers/attribute-metadata-info.ts +16 -0
- package/src/i3s-converter/helpers/node-index-document.ts +18 -8
- package/src/i3s-converter/i3s-converter.ts +198 -41
- package/src/lib/utils/conversion-dump.ts +143 -21
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 ...).
|
|
@@ -3508,8 +3517,7 @@ var NodeIndexDocument = class {
|
|
|
3508
3517
|
* @return 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md object
|
|
3509
3518
|
*/
|
|
3510
3519
|
static async createNodeIndexDocument(parentNode, boundingVolumes, lodSelection, nodeInPage, resources) {
|
|
3511
|
-
var _a2, _b;
|
|
3512
|
-
const { texture, attributes } = resources;
|
|
3520
|
+
var _a2, _b, _c, _d, _e;
|
|
3513
3521
|
const nodeId = nodeInPage.index;
|
|
3514
3522
|
const parentNodeData = await parentNode.load();
|
|
3515
3523
|
const nodeData = {
|
|
@@ -3531,12 +3539,13 @@ var NodeIndexDocument = class {
|
|
|
3531
3539
|
if (nodeInPage.mesh) {
|
|
3532
3540
|
node.geometryData = [{ href: "./geometries/0" }];
|
|
3533
3541
|
node.sharedResource = { href: "./shared" };
|
|
3534
|
-
if (texture) {
|
|
3542
|
+
if ("texture" in resources && resources.texture || "texelCountHint" in resources && resources.texelCountHint) {
|
|
3535
3543
|
node.textureData = [{ href: "./textures/0" }, { href: "./textures/1" }];
|
|
3536
3544
|
}
|
|
3537
|
-
if (attributes && attributes.length && ((_b = (_a2 = parentNode.converter.layers0) == null ? void 0 : _a2.attributeStorageInfo) == null ? void 0 : _b.length)) {
|
|
3545
|
+
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)) {
|
|
3546
|
+
const attributesLength = ("attributes" in resources ? (_e = resources.attributes) == null ? void 0 : _e.length : resources.attributesCount) || 0;
|
|
3538
3547
|
node.attributeData = [];
|
|
3539
|
-
const minimumLength =
|
|
3548
|
+
const minimumLength = attributesLength < parentNode.converter.layers0.attributeStorageInfo.length ? attributesLength : parentNode.converter.layers0.attributeStorageInfo.length;
|
|
3540
3549
|
for (let index = 0; index < minimumLength; index++) {
|
|
3541
3550
|
const folderName = parentNode.converter.layers0.attributeStorageInfo[index].key;
|
|
3542
3551
|
node.attributeData.push({ href: `./attributes/${folderName}/0` });
|
|
@@ -3869,16 +3878,21 @@ var Progress = class {
|
|
|
3869
3878
|
var import_zip = require("@loaders.gl/zip");
|
|
3870
3879
|
|
|
3871
3880
|
// src/lib/utils/conversion-dump.ts
|
|
3881
|
+
var import_util = require("util");
|
|
3872
3882
|
var import_path6 = require("path");
|
|
3873
3883
|
var ConversionDump = class {
|
|
3874
3884
|
constructor() {
|
|
3885
|
+
/**Restored/resumed dump indicator */
|
|
3886
|
+
this.restored = false;
|
|
3887
|
+
/** Array of materials definitions */
|
|
3888
|
+
this.materialDefinitions = [];
|
|
3875
3889
|
this.tilesConverted = {};
|
|
3876
3890
|
}
|
|
3877
3891
|
/**
|
|
3878
|
-
* Create a dump
|
|
3879
|
-
* @param
|
|
3892
|
+
* Create a dump with convertion options
|
|
3893
|
+
* @param currentOptions - converter options
|
|
3880
3894
|
*/
|
|
3881
|
-
async
|
|
3895
|
+
async createDump(currentOptions) {
|
|
3882
3896
|
const {
|
|
3883
3897
|
tilesetName,
|
|
3884
3898
|
slpk,
|
|
@@ -3893,7 +3907,7 @@ var ConversionDump = class {
|
|
|
3893
3907
|
mergeMaterials: mergeMaterials2 = true,
|
|
3894
3908
|
metadataClass,
|
|
3895
3909
|
analyze = false
|
|
3896
|
-
} =
|
|
3910
|
+
} = currentOptions;
|
|
3897
3911
|
this.options = {
|
|
3898
3912
|
tilesetName,
|
|
3899
3913
|
slpk,
|
|
@@ -3909,14 +3923,47 @@ var ConversionDump = class {
|
|
|
3909
3923
|
metadataClass,
|
|
3910
3924
|
analyze
|
|
3911
3925
|
};
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3926
|
+
const dumpFilename = (0, import_path6.join)(
|
|
3927
|
+
this.options.outputPath,
|
|
3928
|
+
this.options.tilesetName,
|
|
3929
|
+
`${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
|
|
3930
|
+
);
|
|
3931
|
+
if (await isFileExists(dumpFilename)) {
|
|
3932
|
+
const {
|
|
3933
|
+
options,
|
|
3934
|
+
tilesConverted,
|
|
3935
|
+
textureSetDefinitions,
|
|
3936
|
+
attributeMetadataInfo,
|
|
3937
|
+
materialDefinitions
|
|
3938
|
+
} = await openJson(
|
|
3939
|
+
(0, import_path6.join)(this.options.outputPath, this.options.tilesetName),
|
|
3940
|
+
`${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
|
|
3917
3941
|
);
|
|
3918
|
-
|
|
3919
|
-
|
|
3942
|
+
if ((0, import_util.isDeepStrictEqual)(options, JSON.parse(JSON.stringify(this.options)))) {
|
|
3943
|
+
this.tilesConverted = tilesConverted;
|
|
3944
|
+
this.textureSetDefinitions = textureSetDefinitions;
|
|
3945
|
+
this.attributeMetadataInfo = attributeMetadataInfo;
|
|
3946
|
+
this.materialDefinitions = materialDefinitions;
|
|
3947
|
+
this.restored = true;
|
|
3948
|
+
return;
|
|
3949
|
+
}
|
|
3950
|
+
}
|
|
3951
|
+
await this.deleteDumpFile();
|
|
3952
|
+
}
|
|
3953
|
+
/**
|
|
3954
|
+
* Reset a dump
|
|
3955
|
+
*/
|
|
3956
|
+
reset() {
|
|
3957
|
+
this.restored = false;
|
|
3958
|
+
this.tilesConverted = {};
|
|
3959
|
+
if (this.textureSetDefinitions) {
|
|
3960
|
+
delete this.textureSetDefinitions;
|
|
3961
|
+
}
|
|
3962
|
+
if (this.attributeMetadataInfo) {
|
|
3963
|
+
delete this.attributeMetadataInfo;
|
|
3964
|
+
}
|
|
3965
|
+
if (this.materialDefinitions.length > 0) {
|
|
3966
|
+
this.materialDefinitions = [];
|
|
3920
3967
|
}
|
|
3921
3968
|
}
|
|
3922
3969
|
/**
|
|
@@ -3927,10 +3974,13 @@ var ConversionDump = class {
|
|
|
3927
3974
|
if (((_a2 = this.options) == null ? void 0 : _a2.outputPath) && this.options.tilesetName) {
|
|
3928
3975
|
try {
|
|
3929
3976
|
await writeFile(
|
|
3930
|
-
this.options.outputPath,
|
|
3977
|
+
(0, import_path6.join)(this.options.outputPath, this.options.tilesetName),
|
|
3931
3978
|
JSON.stringify({
|
|
3932
3979
|
options: this.options,
|
|
3933
|
-
tilesConverted: this.tilesConverted
|
|
3980
|
+
tilesConverted: this.tilesConverted,
|
|
3981
|
+
textureSetDefinitions: this.textureSetDefinitions,
|
|
3982
|
+
attributeMetadataInfo: this.attributeMetadataInfo,
|
|
3983
|
+
materialDefinitions: this.materialDefinitions
|
|
3934
3984
|
}),
|
|
3935
3985
|
`${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
|
|
3936
3986
|
);
|
|
@@ -3944,9 +3994,19 @@ var ConversionDump = class {
|
|
|
3944
3994
|
*/
|
|
3945
3995
|
async deleteDumpFile() {
|
|
3946
3996
|
var _a2;
|
|
3947
|
-
if (((_a2 = this.options) == null ? void 0 : _a2.outputPath) && this.options.tilesetName
|
|
3997
|
+
if (((_a2 = this.options) == null ? void 0 : _a2.outputPath) && this.options.tilesetName && await isFileExists(
|
|
3998
|
+
(0, import_path6.join)(
|
|
3999
|
+
this.options.outputPath,
|
|
4000
|
+
this.options.tilesetName,
|
|
4001
|
+
`${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
|
|
4002
|
+
)
|
|
4003
|
+
)) {
|
|
3948
4004
|
await removeFile(
|
|
3949
|
-
(0, import_path6.join)(
|
|
4005
|
+
(0, import_path6.join)(
|
|
4006
|
+
this.options.outputPath,
|
|
4007
|
+
this.options.tilesetName,
|
|
4008
|
+
`${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
|
|
4009
|
+
)
|
|
3950
4010
|
);
|
|
3951
4011
|
}
|
|
3952
4012
|
}
|
|
@@ -3971,14 +4031,28 @@ var ConversionDump = class {
|
|
|
3971
4031
|
* @param fileName - source filename
|
|
3972
4032
|
* @param nodeId - nodeId of the node
|
|
3973
4033
|
*/
|
|
3974
|
-
async addNode(filename, nodeId) {
|
|
4034
|
+
async addNode(filename, nodeId, dumpMetadata) {
|
|
3975
4035
|
const { nodes } = this.getRecord(filename) || { nodes: [] };
|
|
3976
|
-
nodes.push({ nodeId, done: false, progress: {} });
|
|
4036
|
+
nodes.push({ nodeId, done: false, progress: {}, dumpMetadata });
|
|
3977
4037
|
if (nodes.length === 1) {
|
|
3978
4038
|
this.setRecord(filename, { nodes });
|
|
3979
4039
|
}
|
|
3980
4040
|
await this.updateDumpFile();
|
|
3981
4041
|
}
|
|
4042
|
+
/**
|
|
4043
|
+
* Clear dump record got the source filename
|
|
4044
|
+
* @param fileName - source filename
|
|
4045
|
+
*/
|
|
4046
|
+
clearDumpRecord(filename) {
|
|
4047
|
+
this.setRecord(filename, { nodes: [] });
|
|
4048
|
+
}
|
|
4049
|
+
/**
|
|
4050
|
+
* Add textures definitions into the dump file
|
|
4051
|
+
* @param textureDefinitions - textures definitions array
|
|
4052
|
+
*/
|
|
4053
|
+
addTexturesDefinitions(textureDefinitions) {
|
|
4054
|
+
this.textureSetDefinitions = textureDefinitions;
|
|
4055
|
+
}
|
|
3982
4056
|
/**
|
|
3983
4057
|
* Update done status object for the writing resources
|
|
3984
4058
|
* @param fileName - key - source filename
|
|
@@ -3992,6 +4066,9 @@ var ConversionDump = class {
|
|
|
3992
4066
|
(element) => element.nodeId === nodeId
|
|
3993
4067
|
);
|
|
3994
4068
|
if (nodeDump) {
|
|
4069
|
+
if (!nodeDump.progress) {
|
|
4070
|
+
nodeDump.progress = {};
|
|
4071
|
+
}
|
|
3995
4072
|
nodeDump.progress[resourceType] = value;
|
|
3996
4073
|
if (!value) {
|
|
3997
4074
|
nodeDump.done = false;
|
|
@@ -4010,7 +4087,7 @@ var ConversionDump = class {
|
|
|
4010
4087
|
if (!sourceId || !resourceType || !outputId)
|
|
4011
4088
|
continue;
|
|
4012
4089
|
for (const node of this.tilesConverted[sourceId].nodes) {
|
|
4013
|
-
if (node.nodeId === outputId) {
|
|
4090
|
+
if (node.nodeId === outputId && node.progress) {
|
|
4014
4091
|
node.progress[resourceType] = true;
|
|
4015
4092
|
let done = false;
|
|
4016
4093
|
for (const key in node.progress) {
|
|
@@ -4020,7 +4097,7 @@ var ConversionDump = class {
|
|
|
4020
4097
|
}
|
|
4021
4098
|
node.done = done;
|
|
4022
4099
|
if (node.done) {
|
|
4023
|
-
node.progress
|
|
4100
|
+
delete node.progress;
|
|
4024
4101
|
}
|
|
4025
4102
|
break;
|
|
4026
4103
|
}
|
|
@@ -4029,6 +4106,29 @@ var ConversionDump = class {
|
|
|
4029
4106
|
}
|
|
4030
4107
|
await this.updateDumpFile();
|
|
4031
4108
|
}
|
|
4109
|
+
/**
|
|
4110
|
+
* Check is source file conversion complete
|
|
4111
|
+
* @param filename - source filename
|
|
4112
|
+
* @returns true if source file conversion complete
|
|
4113
|
+
*/
|
|
4114
|
+
isFileConversionComplete(filename) {
|
|
4115
|
+
var _a2, _b, _c;
|
|
4116
|
+
let result = true;
|
|
4117
|
+
for (const node of ((_a2 = this.tilesConverted[filename]) == null ? void 0 : _a2.nodes) || []) {
|
|
4118
|
+
if (!node.done) {
|
|
4119
|
+
result = false;
|
|
4120
|
+
break;
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
return result && ((_c = (_b = this.tilesConverted[filename]) == null ? void 0 : _b.nodes) == null ? void 0 : _c.length) > 0;
|
|
4124
|
+
}
|
|
4125
|
+
/**
|
|
4126
|
+
* Set materialDefinitions into a dump
|
|
4127
|
+
* @param materialDefinitions - Array materialDefinitions
|
|
4128
|
+
*/
|
|
4129
|
+
setMaterialsDefinitions(materialDefinitions) {
|
|
4130
|
+
this.materialDefinitions = materialDefinitions;
|
|
4131
|
+
}
|
|
4032
4132
|
};
|
|
4033
4133
|
|
|
4034
4134
|
// src/i3s-converter/i3s-converter.ts
|
|
@@ -4163,7 +4263,6 @@ var I3SConverter = class {
|
|
|
4163
4263
|
if (slpk) {
|
|
4164
4264
|
this.nodePages.useWriteFunction(writeFileForSlpk);
|
|
4165
4265
|
}
|
|
4166
|
-
await this.conversionDump.createDumpFile(options);
|
|
4167
4266
|
try {
|
|
4168
4267
|
const preloadOptions = await this._fetchPreloadOptions();
|
|
4169
4268
|
let tilesetUrl = inputUrl;
|
|
@@ -4298,13 +4397,37 @@ var I3SConverter = class {
|
|
|
4298
4397
|
async _createAndSaveTileset(outputPath, tilesetName) {
|
|
4299
4398
|
var _a2, _b, _c;
|
|
4300
4399
|
const tilesetPath = (0, import_path7.join)(`${outputPath}`, `${tilesetName}`);
|
|
4400
|
+
await this.conversionDump.createDump(this.options);
|
|
4401
|
+
if (this.conversionDump.restored && this.options.inquirer) {
|
|
4402
|
+
const result = await this.options.inquirer.prompt([
|
|
4403
|
+
{
|
|
4404
|
+
name: "resumeConversion",
|
|
4405
|
+
type: "confirm",
|
|
4406
|
+
message: "Dump file of the previous conversion exists, do you want to resume that conversion?"
|
|
4407
|
+
}
|
|
4408
|
+
]);
|
|
4409
|
+
if (!result.resumeConversion) {
|
|
4410
|
+
this.conversionDump.reset();
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4413
|
+
this.layers0Path = (0, import_path7.join)(tilesetPath, "SceneServer", "layers", "0");
|
|
4414
|
+
const removePath = this.conversionDump.restored ? (0, import_path7.join)(this.layers0Path, "nodepages") : tilesetPath;
|
|
4301
4415
|
try {
|
|
4302
|
-
await removeDir(
|
|
4416
|
+
await removeDir(removePath);
|
|
4303
4417
|
} catch (e) {
|
|
4304
4418
|
}
|
|
4305
|
-
this.
|
|
4419
|
+
if (this.conversionDump.restored && this.conversionDump.attributeMetadataInfo) {
|
|
4420
|
+
this.attributeMetadataInfo.fromObject(this.conversionDump.attributeMetadataInfo);
|
|
4421
|
+
}
|
|
4306
4422
|
this.materialDefinitions = [];
|
|
4307
4423
|
this.materialMap = /* @__PURE__ */ new Map();
|
|
4424
|
+
if (this.conversionDump.restored && this.conversionDump.materialDefinitions) {
|
|
4425
|
+
for (let i = 0; i < this.conversionDump.materialDefinitions.length; i++) {
|
|
4426
|
+
const hash = (0, import_md52.default)(JSON.stringify(this.conversionDump.materialDefinitions[i]));
|
|
4427
|
+
this.materialMap.set(hash, i);
|
|
4428
|
+
}
|
|
4429
|
+
this.materialDefinitions = this.conversionDump.materialDefinitions;
|
|
4430
|
+
}
|
|
4308
4431
|
const sourceRootTile = this.sourceTileset.root;
|
|
4309
4432
|
const sourceBoundingVolume = (0, import_tiles.createBoundingVolume)(
|
|
4310
4433
|
sourceRootTile.boundingVolume,
|
|
@@ -4343,6 +4466,9 @@ var I3SConverter = class {
|
|
|
4343
4466
|
if (this.attributeMetadataInfo.attributeStorageInfo.length) {
|
|
4344
4467
|
this.layers0.layerType = _3D_OBJECT_LAYER_TYPE;
|
|
4345
4468
|
}
|
|
4469
|
+
if (this.conversionDump.restored && this.conversionDump.textureSetDefinitions) {
|
|
4470
|
+
this.layers0.textureSetDefinitions = this.conversionDump.textureSetDefinitions;
|
|
4471
|
+
}
|
|
4346
4472
|
this.layers0.materialDefinitions = this.materialDefinitions;
|
|
4347
4473
|
this.layers0.geometryDefinitions = (0, import_json_map_transform8.default)(
|
|
4348
4474
|
this.geometryConfigs.map((config) => ({
|
|
@@ -4460,7 +4586,13 @@ var I3SConverter = class {
|
|
|
4460
4586
|
transformationMatrix = transformationMatrix.multiplyRight(sourceTile.transform);
|
|
4461
4587
|
}
|
|
4462
4588
|
const parentNode = parentNodes[0];
|
|
4463
|
-
const
|
|
4589
|
+
const restoreResult = await this._restoreNode(parentNode, sourceTile, transformationMatrix);
|
|
4590
|
+
let childNodes;
|
|
4591
|
+
if (restoreResult === null) {
|
|
4592
|
+
childNodes = await this._createNode(parentNode, sourceTile, transformationMatrix);
|
|
4593
|
+
} else {
|
|
4594
|
+
childNodes = restoreResult;
|
|
4595
|
+
}
|
|
4464
4596
|
await parentNode.addChildren(childNodes);
|
|
4465
4597
|
const newTraversalProps = {
|
|
4466
4598
|
transform: transformationMatrix,
|
|
@@ -4494,6 +4626,88 @@ var I3SConverter = class {
|
|
|
4494
4626
|
await node.save();
|
|
4495
4627
|
}
|
|
4496
4628
|
}
|
|
4629
|
+
/**
|
|
4630
|
+
* Generate NodeIndexDocument
|
|
4631
|
+
* @param boundingVolumes - Bounding volumes
|
|
4632
|
+
* @param resources - converted or dumped node resources data
|
|
4633
|
+
* @param parentNode - 3DNodeIndexDocument of parent node
|
|
4634
|
+
* @param sourceTile - source 3DTile data
|
|
4635
|
+
* @param isDumped - indicator if the node is dumped
|
|
4636
|
+
* @return NodeIndexDocument, nodeInPage and node data
|
|
4637
|
+
*/
|
|
4638
|
+
async _generateNodeIndexDocument(boundingVolumes, resources, parentNode, sourceTile, isDumped) {
|
|
4639
|
+
this.layersHasTexture = this.layersHasTexture || Boolean(
|
|
4640
|
+
"texture" in resources && resources.texture || "texelCountHint" in resources && resources.texelCountHint
|
|
4641
|
+
);
|
|
4642
|
+
if (this.generateBoundingVolumes && resources.boundingVolumes) {
|
|
4643
|
+
boundingVolumes = resources.boundingVolumes;
|
|
4644
|
+
}
|
|
4645
|
+
const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);
|
|
4646
|
+
const maxScreenThresholdSQ = lodSelection.find(
|
|
4647
|
+
(val) => val.metricType === "maxScreenThresholdSQ"
|
|
4648
|
+
) || { maxError: 0 };
|
|
4649
|
+
if (isDumped) {
|
|
4650
|
+
const draftObb = {
|
|
4651
|
+
center: [],
|
|
4652
|
+
halfSize: [],
|
|
4653
|
+
quaternion: []
|
|
4654
|
+
};
|
|
4655
|
+
await this.nodePages.push({ index: 0, obb: draftObb }, parentNode.inPageId);
|
|
4656
|
+
}
|
|
4657
|
+
const nodeInPage = await this._updateNodeInNodePages(
|
|
4658
|
+
maxScreenThresholdSQ,
|
|
4659
|
+
boundingVolumes,
|
|
4660
|
+
sourceTile,
|
|
4661
|
+
parentNode.inPageId,
|
|
4662
|
+
resources
|
|
4663
|
+
);
|
|
4664
|
+
const nodeData = await NodeIndexDocument.createNodeIndexDocument(
|
|
4665
|
+
parentNode,
|
|
4666
|
+
boundingVolumes,
|
|
4667
|
+
lodSelection,
|
|
4668
|
+
nodeInPage,
|
|
4669
|
+
resources
|
|
4670
|
+
);
|
|
4671
|
+
const node = await new NodeIndexDocument(nodeInPage.index, this).addData(nodeData);
|
|
4672
|
+
return { node, nodeInPage, nodeData };
|
|
4673
|
+
}
|
|
4674
|
+
/**
|
|
4675
|
+
* Restore 3DNodeIndexDocument from a comversion dump file
|
|
4676
|
+
* @param parentNode - 3DNodeIndexDocument of parent node
|
|
4677
|
+
* @param sourceTile - source 3DTile data
|
|
4678
|
+
* @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying
|
|
4679
|
+
* transform of all parent tiles and transform of the current tile
|
|
4680
|
+
*/
|
|
4681
|
+
async _restoreNode(parentNode, sourceTile, transformationMatrix) {
|
|
4682
|
+
this._checkAddRefinementTypeForTile(sourceTile);
|
|
4683
|
+
await this._updateTilesetOptions();
|
|
4684
|
+
if (this.conversionDump.restored && sourceTile.id && this.conversionDump.isFileConversionComplete(sourceTile.id)) {
|
|
4685
|
+
const sourceBoundingVolume = (0, import_tiles.createBoundingVolume)(
|
|
4686
|
+
sourceTile.boundingVolume,
|
|
4687
|
+
transformationMatrix,
|
|
4688
|
+
null
|
|
4689
|
+
);
|
|
4690
|
+
let boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);
|
|
4691
|
+
const nodes = [];
|
|
4692
|
+
for (const convertedNode of this.conversionDump.tilesConverted[sourceTile.id].nodes) {
|
|
4693
|
+
const { node } = await this._generateNodeIndexDocument(
|
|
4694
|
+
boundingVolumes,
|
|
4695
|
+
{
|
|
4696
|
+
...convertedNode.dumpMetadata,
|
|
4697
|
+
nodeId: convertedNode.nodeId
|
|
4698
|
+
},
|
|
4699
|
+
parentNode,
|
|
4700
|
+
sourceTile,
|
|
4701
|
+
true
|
|
4702
|
+
);
|
|
4703
|
+
nodes.push(node);
|
|
4704
|
+
}
|
|
4705
|
+
return nodes;
|
|
4706
|
+
} else if (this.conversionDump.restored && sourceTile.id) {
|
|
4707
|
+
this.conversionDump.clearDumpRecord(sourceTile.id);
|
|
4708
|
+
}
|
|
4709
|
+
return null;
|
|
4710
|
+
}
|
|
4497
4711
|
/**
|
|
4498
4712
|
* Convert tile to one or more I3S nodes
|
|
4499
4713
|
* @param parentNode - 3DNodeIndexDocument of parent node
|
|
@@ -4503,6 +4717,7 @@ var I3SConverter = class {
|
|
|
4503
4717
|
* @param level - tree level
|
|
4504
4718
|
*/
|
|
4505
4719
|
async _createNode(parentNode, sourceTile, transformationMatrix) {
|
|
4720
|
+
var _a2;
|
|
4506
4721
|
this._checkAddRefinementTypeForTile(sourceTile);
|
|
4507
4722
|
await this._updateTilesetOptions();
|
|
4508
4723
|
let tileContent = null;
|
|
@@ -4519,6 +4734,11 @@ var I3SConverter = class {
|
|
|
4519
4734
|
let boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);
|
|
4520
4735
|
const propertyTable = getPropertyTable(tileContent, this.options.metadataClass);
|
|
4521
4736
|
this.createAttributeStorageInfo(tileContent, propertyTable);
|
|
4737
|
+
this.conversionDump.attributeMetadataInfo = {
|
|
4738
|
+
attributeStorageInfo: this.attributeMetadataInfo.attributeStorageInfo,
|
|
4739
|
+
fields: this.attributeMetadataInfo.fields,
|
|
4740
|
+
popupInfo: this.attributeMetadataInfo.popupInfo
|
|
4741
|
+
};
|
|
4522
4742
|
const resourcesData = await this._convertResources(
|
|
4523
4743
|
sourceTile,
|
|
4524
4744
|
transformationMatrix,
|
|
@@ -4543,33 +4763,28 @@ var I3SConverter = class {
|
|
|
4543
4763
|
boundingVolumes: null
|
|
4544
4764
|
};
|
|
4545
4765
|
for (const resources of resourcesData || [emptyResources]) {
|
|
4546
|
-
|
|
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,
|
|
4766
|
+
const { node, nodeInPage, nodeData } = await this._generateNodeIndexDocument(
|
|
4556
4767
|
boundingVolumes,
|
|
4557
|
-
|
|
4558
|
-
parentNode.inPageId,
|
|
4559
|
-
resources
|
|
4560
|
-
);
|
|
4561
|
-
const nodeData = await NodeIndexDocument.createNodeIndexDocument(
|
|
4768
|
+
resources,
|
|
4562
4769
|
parentNode,
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
nodeInPage,
|
|
4566
|
-
resources
|
|
4770
|
+
sourceTile,
|
|
4771
|
+
false
|
|
4567
4772
|
);
|
|
4568
|
-
const node = await new NodeIndexDocument(nodeInPage.index, this).addData(nodeData);
|
|
4569
4773
|
nodes.push(node);
|
|
4570
4774
|
if (nodeInPage.mesh) {
|
|
4571
4775
|
if (sourceTile.id) {
|
|
4572
|
-
|
|
4776
|
+
const dumpMetadata = {
|
|
4777
|
+
boundingVolumes: resources.boundingVolumes,
|
|
4778
|
+
attributesCount: (_a2 = resources.attributes) == null ? void 0 : _a2.length,
|
|
4779
|
+
featureCount: resources.featureCount,
|
|
4780
|
+
geometry: Boolean(resources.geometry),
|
|
4781
|
+
hasUvRegions: resources.hasUvRegions,
|
|
4782
|
+
materialId: nodeInPage.mesh.material.definition,
|
|
4783
|
+
texelCountHint: nodeInPage.mesh.material.texelCountHint,
|
|
4784
|
+
vertexCount: resources.vertexCount
|
|
4785
|
+
};
|
|
4786
|
+
this.conversionDump.setMaterialsDefinitions(this.materialDefinitions);
|
|
4787
|
+
await this.conversionDump.addNode(sourceTile.id, nodeInPage.index, dumpMetadata);
|
|
4573
4788
|
}
|
|
4574
4789
|
await this._writeResources(resources, node.id, sourceTile);
|
|
4575
4790
|
}
|
|
@@ -4637,7 +4852,7 @@ var I3SConverter = class {
|
|
|
4637
4852
|
* @return the node object in node pages
|
|
4638
4853
|
*/
|
|
4639
4854
|
async _updateNodeInNodePages(maxScreenThresholdSQ, boundingVolumes, sourceTile, parentId, resources) {
|
|
4640
|
-
const {
|
|
4855
|
+
const { vertexCount, featureCount, geometry, hasUvRegions } = resources;
|
|
4641
4856
|
const nodeInPage = {
|
|
4642
4857
|
index: 0,
|
|
4643
4858
|
lodThreshold: maxScreenThresholdSQ.maxError,
|
|
@@ -4647,7 +4862,12 @@ var I3SConverter = class {
|
|
|
4647
4862
|
if (geometry && this.isContentSupported(sourceTile)) {
|
|
4648
4863
|
nodeInPage.mesh = {
|
|
4649
4864
|
geometry: {
|
|
4650
|
-
definition: this.findOrCreateGeometryDefinition(
|
|
4865
|
+
definition: this.findOrCreateGeometryDefinition(
|
|
4866
|
+
Boolean(
|
|
4867
|
+
"texture" in resources && resources.texture || "texelCountHint" in resources && resources.texelCountHint
|
|
4868
|
+
),
|
|
4869
|
+
hasUvRegions
|
|
4870
|
+
),
|
|
4651
4871
|
resource: 0
|
|
4652
4872
|
},
|
|
4653
4873
|
attribute: {
|
|
@@ -4658,7 +4878,7 @@ var I3SConverter = class {
|
|
|
4658
4878
|
}
|
|
4659
4879
|
};
|
|
4660
4880
|
}
|
|
4661
|
-
let nodeId = resources.nodeId;
|
|
4881
|
+
let nodeId = "nodeId" in resources ? resources.nodeId : void 0;
|
|
4662
4882
|
let node;
|
|
4663
4883
|
if (!nodeId) {
|
|
4664
4884
|
node = await this.nodePages.push(nodeInPage, parentId);
|
|
@@ -4669,12 +4889,16 @@ var I3SConverter = class {
|
|
|
4669
4889
|
console.log(`[warning]: node ${node.index} is created with empty content`);
|
|
4670
4890
|
}
|
|
4671
4891
|
NodePages.updateAll(node, nodeInPage);
|
|
4672
|
-
if (meshMaterial) {
|
|
4673
|
-
NodePages.updateMaterialByNodeId(node, this._findOrCreateMaterial(meshMaterial));
|
|
4892
|
+
if ("meshMaterial" in resources && resources.meshMaterial) {
|
|
4893
|
+
NodePages.updateMaterialByNodeId(node, this._findOrCreateMaterial(resources.meshMaterial));
|
|
4894
|
+
} else if ("materialId" in resources && resources.materialId !== null) {
|
|
4895
|
+
NodePages.updateMaterialByNodeId(node, resources.materialId);
|
|
4674
4896
|
}
|
|
4675
|
-
if (texture) {
|
|
4676
|
-
const texelCountHint = texture.image.height * texture.image.width;
|
|
4897
|
+
if ("texture" in resources && resources.texture) {
|
|
4898
|
+
const texelCountHint = resources.texture.image.height * resources.texture.image.width;
|
|
4677
4899
|
NodePages.updateTexelCountHintByNodeId(node, texelCountHint);
|
|
4900
|
+
} else if ("texelCountHint" in resources && resources.texelCountHint) {
|
|
4901
|
+
NodePages.updateTexelCountHintByNodeId(node, resources.texelCountHint);
|
|
4678
4902
|
}
|
|
4679
4903
|
if (vertexCount) {
|
|
4680
4904
|
this.vertexCounter += vertexCount;
|
|
@@ -4937,6 +5161,9 @@ var I3SConverter = class {
|
|
|
4937
5161
|
if (!this.layers0.textureSetDefinitions.length) {
|
|
4938
5162
|
this.layers0.textureSetDefinitions.push({ formats });
|
|
4939
5163
|
this.layers0.textureSetDefinitions.push({ formats, atlas: true });
|
|
5164
|
+
if (this.layers0.textureSetDefinitions) {
|
|
5165
|
+
this.conversionDump.addTexturesDefinitions(this.layers0.textureSetDefinitions);
|
|
5166
|
+
}
|
|
4940
5167
|
}
|
|
4941
5168
|
}
|
|
4942
5169
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { BoundingVolumes, I3SMaterialDefinition, TextureSetDefinitionFormats } from '@loaders.gl/i3s';
|
|
2
|
+
import { AttributeMetadataInfoObject } from '../../i3s-converter/helpers/attribute-metadata-info';
|
|
1
3
|
export type ConversionDumpOptions = {
|
|
2
4
|
inputUrl: string;
|
|
3
5
|
outputPath: string;
|
|
@@ -16,22 +18,49 @@ export type ConversionDumpOptions = {
|
|
|
16
18
|
type NodeDoneStatus = {
|
|
17
19
|
nodeId: number;
|
|
18
20
|
done: boolean;
|
|
19
|
-
progress
|
|
21
|
+
progress?: Record<string, boolean>;
|
|
22
|
+
dumpMetadata?: DumpMetadata;
|
|
20
23
|
};
|
|
21
24
|
type TilesConverted = {
|
|
22
25
|
nodes: NodeDoneStatus[];
|
|
23
26
|
};
|
|
27
|
+
export type DumpMetadata = {
|
|
28
|
+
boundingVolumes: BoundingVolumes | null;
|
|
29
|
+
attributesCount?: number;
|
|
30
|
+
featureCount: number | null;
|
|
31
|
+
geometry: boolean;
|
|
32
|
+
hasUvRegions: boolean;
|
|
33
|
+
materialId: number | null;
|
|
34
|
+
texelCountHint?: number;
|
|
35
|
+
vertexCount: number | null;
|
|
36
|
+
};
|
|
37
|
+
export type TextureSetDefinition = {
|
|
38
|
+
formats: TextureSetDefinitionFormats;
|
|
39
|
+
atlas?: boolean;
|
|
40
|
+
};
|
|
24
41
|
export declare class ConversionDump {
|
|
42
|
+
/**Restored/resumed dump indicator */
|
|
43
|
+
restored: boolean;
|
|
25
44
|
/** Conversion options */
|
|
26
45
|
private options?;
|
|
27
46
|
/** Tiles conversion progress status map */
|
|
28
47
|
tilesConverted: Record<string, TilesConverted>;
|
|
48
|
+
/** Textures formats definitions */
|
|
49
|
+
textureSetDefinitions?: TextureSetDefinition[];
|
|
50
|
+
/** Attributes Metadata */
|
|
51
|
+
attributeMetadataInfo?: AttributeMetadataInfoObject;
|
|
52
|
+
/** Array of materials definitions */
|
|
53
|
+
materialDefinitions: I3SMaterialDefinition[];
|
|
29
54
|
constructor();
|
|
30
55
|
/**
|
|
31
|
-
* Create a dump
|
|
32
|
-
* @param
|
|
56
|
+
* Create a dump with convertion options
|
|
57
|
+
* @param currentOptions - converter options
|
|
58
|
+
*/
|
|
59
|
+
createDump(currentOptions: ConversionDumpOptions): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Reset a dump
|
|
33
62
|
*/
|
|
34
|
-
|
|
63
|
+
reset(): void;
|
|
35
64
|
/**
|
|
36
65
|
* Update conversion status in the dump file
|
|
37
66
|
*/
|
|
@@ -57,7 +86,17 @@ export declare class ConversionDump {
|
|
|
57
86
|
* @param fileName - source filename
|
|
58
87
|
* @param nodeId - nodeId of the node
|
|
59
88
|
*/
|
|
60
|
-
addNode(filename: string, nodeId: number): Promise<void>;
|
|
89
|
+
addNode(filename: string, nodeId: number, dumpMetadata: DumpMetadata): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Clear dump record got the source filename
|
|
92
|
+
* @param fileName - source filename
|
|
93
|
+
*/
|
|
94
|
+
clearDumpRecord(filename: string): void;
|
|
95
|
+
/**
|
|
96
|
+
* Add textures definitions into the dump file
|
|
97
|
+
* @param textureDefinitions - textures definitions array
|
|
98
|
+
*/
|
|
99
|
+
addTexturesDefinitions(textureDefinitions: TextureSetDefinition[]): void;
|
|
61
100
|
/**
|
|
62
101
|
* Update done status object for the writing resources
|
|
63
102
|
* @param fileName - key - source filename
|
|
@@ -76,6 +115,17 @@ export declare class ConversionDump {
|
|
|
76
115
|
sourceId?: string;
|
|
77
116
|
resourceType?: string;
|
|
78
117
|
}[], writeResults: PromiseSettledResult<string | null>[]): Promise<void>;
|
|
118
|
+
/**
|
|
119
|
+
* Check is source file conversion complete
|
|
120
|
+
* @param filename - source filename
|
|
121
|
+
* @returns true if source file conversion complete
|
|
122
|
+
*/
|
|
123
|
+
isFileConversionComplete(filename: string): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Set materialDefinitions into a dump
|
|
126
|
+
* @param materialDefinitions - Array materialDefinitions
|
|
127
|
+
*/
|
|
128
|
+
setMaterialsDefinitions(materialDefinitions: I3SMaterialDefinition[]): void;
|
|
79
129
|
}
|
|
80
130
|
export {};
|
|
81
131
|
//# sourceMappingURL=conversion-dump.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversion-dump.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/conversion-dump.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,uBAAuB,EAAE,OAAO,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"conversion-dump.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/conversion-dump.ts"],"names":[],"mappings":"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"}
|