@loaders.gl/tile-converter 4.0.2 → 4.0.3
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 +98 -98
- package/dist/deps-installer/deps-installer.js +1 -1
- package/dist/deps-installer/deps-installer.js.map +1 -1
- package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/geometry-converter.js.map +1 -1
- package/dist/i3s-converter/helpers/progress.d.ts +90 -0
- package/dist/i3s-converter/helpers/progress.d.ts.map +1 -0
- package/dist/i3s-converter/helpers/progress.js +92 -0
- package/dist/i3s-converter/helpers/progress.js.map +1 -0
- package/dist/i3s-converter/i3s-converter.d.ts +2 -9
- package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
- package/dist/i3s-converter/i3s-converter.js +19 -13
- package/dist/i3s-converter/i3s-converter.js.map +1 -1
- package/dist/index.cjs +198 -46
- package/dist/lib/utils/statistic-utills.d.ts +6 -1
- package/dist/lib/utils/statistic-utills.d.ts.map +1 -1
- package/dist/lib/utils/statistic-utills.js +13 -3
- package/dist/lib/utils/statistic-utills.js.map +1 -1
- package/package.json +14 -14
- package/src/deps-installer/deps-installer.ts +1 -1
- package/src/i3s-converter/helpers/geometry-converter.ts +19 -14
- package/src/i3s-converter/helpers/progress.ts +166 -0
- package/src/i3s-converter/i3s-converter.ts +23 -25
- package/src/lib/utils/statistic-utills.ts +22 -4
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import process from 'process';
|
|
2
|
+
import {timeConverter} from '../../lib/utils/statistic-utills';
|
|
3
|
+
|
|
4
|
+
/** Defines a threshold that is used to check if the process velocity can be consifered trust. */
|
|
5
|
+
const THRESHOLD_DEFAULT = 0.2;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Implements methods to keep track on the progress of a long process.
|
|
9
|
+
*/
|
|
10
|
+
export class Progress {
|
|
11
|
+
/** Total amount of work, e.g. number of files to save or number of bytes to send */
|
|
12
|
+
private _stepsTotal: number = 0;
|
|
13
|
+
/** Amount of work already done */
|
|
14
|
+
private _stepsDone: number = 0;
|
|
15
|
+
/** Time in milli-seconds when the process started */
|
|
16
|
+
private startTime: number = 0;
|
|
17
|
+
/** Time in milli-seconds when the process stopped */
|
|
18
|
+
private stopTime: number = 0;
|
|
19
|
+
/** Time in milli-seconds when stepsDone was updated */
|
|
20
|
+
private timeOfUpdatingStepsDone: number = 0;
|
|
21
|
+
/** Time in milli-seconds spent for performing one step*/
|
|
22
|
+
private milliSecForOneStep: number = 0;
|
|
23
|
+
private trust: boolean = false;
|
|
24
|
+
/**
|
|
25
|
+
* The number of digits to appear after decimal point in the string representation of the count of steps already done.
|
|
26
|
+
* It's calculated based on the total count of steps.
|
|
27
|
+
*/
|
|
28
|
+
private numberOfDigitsInPercentage: number = 0;
|
|
29
|
+
/** Defines a threshold that is used to check if the process velocity can be consifered trust. */
|
|
30
|
+
private threshold: number;
|
|
31
|
+
/** Function that is used to get the time stamp */
|
|
32
|
+
private getTime: () => bigint;
|
|
33
|
+
|
|
34
|
+
constructor(options: {threshold?: number; getTime?: () => bigint} = {}) {
|
|
35
|
+
this.getTime = options.getTime || process.hrtime.bigint;
|
|
36
|
+
this.threshold = options.threshold || THRESHOLD_DEFAULT;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Total amount of work, e.g. number of files to save or number of bytes to send */
|
|
40
|
+
get stepsTotal() {
|
|
41
|
+
return this._stepsTotal;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
set stepsTotal(stepsTotal) {
|
|
45
|
+
this._stepsTotal = stepsTotal;
|
|
46
|
+
this.numberOfDigitsInPercentage =
|
|
47
|
+
this.stepsTotal > 100 ? Math.ceil(Math.log10(this.stepsTotal)) - 2 : 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Amount of work already done */
|
|
51
|
+
get stepsDone() {
|
|
52
|
+
return this._stepsDone;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
set stepsDone(stepsDone) {
|
|
56
|
+
this._stepsDone = stepsDone;
|
|
57
|
+
this.timeOfUpdatingStepsDone = this.getCurrentTimeInMilliSeconds();
|
|
58
|
+
if (this._stepsDone) {
|
|
59
|
+
const diff = this.timeOfUpdatingStepsDone - this.startTime;
|
|
60
|
+
const milliSecForOneStep = diff / this._stepsDone;
|
|
61
|
+
|
|
62
|
+
this.trust = this.isVelocityTrust(milliSecForOneStep, this.milliSecForOneStep);
|
|
63
|
+
this.milliSecForOneStep = milliSecForOneStep;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Saves the current time as we start monitoring the process.
|
|
69
|
+
*/
|
|
70
|
+
startMonitoring() {
|
|
71
|
+
this.startTime = this.getCurrentTimeInMilliSeconds();
|
|
72
|
+
this.milliSecForOneStep = 0;
|
|
73
|
+
this.trust = false;
|
|
74
|
+
this.timeOfUpdatingStepsDone = 0;
|
|
75
|
+
this.stopTime = 0;
|
|
76
|
+
this.stepsDone = 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Saves the current time as we stop monitoring the process.
|
|
81
|
+
*/
|
|
82
|
+
stopMonitoring() {
|
|
83
|
+
this.stopTime = this.getCurrentTimeInMilliSeconds();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Gets percentage of the work already done.
|
|
88
|
+
* @returns percentage of the work already done.
|
|
89
|
+
*/
|
|
90
|
+
getPercent(): number | null {
|
|
91
|
+
if (!this._stepsTotal) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const percent = (this._stepsDone / this._stepsTotal) * 100.0;
|
|
95
|
+
return percent;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Gets string representation of percentage of the work already done.
|
|
100
|
+
* @returns string representation of percentage or an empty string if the percetage value cannot be calculated.
|
|
101
|
+
*/
|
|
102
|
+
getPercentString() {
|
|
103
|
+
const percent = this.getPercent();
|
|
104
|
+
return percent !== null ? percent.toFixed(this.numberOfDigitsInPercentage) : '';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Gets the time elapsed since the monitoring started
|
|
109
|
+
* @returns Number of milliseconds elapsed
|
|
110
|
+
*/
|
|
111
|
+
getTimeCurrentlyElapsed(): number {
|
|
112
|
+
const currentTime = this.stopTime ? this.stopTime : this.getCurrentTimeInMilliSeconds();
|
|
113
|
+
const diff = currentTime - this.startTime;
|
|
114
|
+
return diff;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Gets the time remaining (expected at the moment of updating 'stepsDone') to complete the work.
|
|
119
|
+
* @returns Number of milliseconds remaining
|
|
120
|
+
*/
|
|
121
|
+
getTimeRemaining(): {timeRemaining: number; trust: boolean} | null {
|
|
122
|
+
if (!this._stepsDone || !this.startTime) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const timeRemainingInMilliSeconds =
|
|
127
|
+
(this._stepsTotal - this._stepsDone) * this.milliSecForOneStep;
|
|
128
|
+
return {timeRemaining: timeRemainingInMilliSeconds, trust: this.trust};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Gets the string representation of the time remaining (expected at the moment of updating 'stepsDone') to complete the work.
|
|
133
|
+
* @returns string representation of the time remaining.
|
|
134
|
+
* It's an empty string if the time cannot be pedicted or it's still being calculated.
|
|
135
|
+
*/
|
|
136
|
+
getTimeRemainingString(): string {
|
|
137
|
+
const timeRemainingObject = this.getTimeRemaining();
|
|
138
|
+
return timeRemainingObject?.trust ? timeConverter(timeRemainingObject.timeRemaining) : '';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Check if the computed velociy of the process can be considered trust.
|
|
143
|
+
* At the beginning of the process the number of samples collected ('time necessary to perform one step' averaged) is too small,
|
|
144
|
+
* which results in huge deviation of the cumputed velocity of the process.
|
|
145
|
+
* It makes sense to perform the check before reporting the time remainig so the end user is not confused.
|
|
146
|
+
* @param current - current value
|
|
147
|
+
* @param previous - previous value
|
|
148
|
+
* @returns true if the computed velociy can be considered trust, or false otherwise
|
|
149
|
+
*/
|
|
150
|
+
private isVelocityTrust(current: number, previous: number): boolean {
|
|
151
|
+
if (previous) {
|
|
152
|
+
const dev = Math.abs((current - previous) / previous);
|
|
153
|
+
return dev < this.threshold;
|
|
154
|
+
}
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Gets current time in milliseconds.
|
|
160
|
+
* @returns current time in milliseconds.
|
|
161
|
+
*/
|
|
162
|
+
private getCurrentTimeInMilliSeconds(): number {
|
|
163
|
+
// process.hrtime.bigint() returns the time in nanoseconds. We need the time in milliseconds.
|
|
164
|
+
return Number(this.getTime() / BigInt(1e6));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -79,6 +79,7 @@ import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
|
|
|
79
79
|
import {createBoundingVolume} from '@loaders.gl/tiles';
|
|
80
80
|
import {TraversalConversionProps, traverseDatasetWith} from './helpers/tileset-traversal';
|
|
81
81
|
import {analyzeTileContent, mergePreprocessData} from './helpers/preprocess-3d-tiles';
|
|
82
|
+
import {Progress} from './helpers/progress';
|
|
82
83
|
|
|
83
84
|
const ION_DEFAULT_TOKEN = process.env?.IonToken;
|
|
84
85
|
const HARDCODED_NODES_PER_PAGE = 64;
|
|
@@ -87,6 +88,7 @@ const _3D_OBJECT_LAYER_TYPE = '3DObject';
|
|
|
87
88
|
const REFRESH_TOKEN_TIMEOUT = 1800; // 30 minutes in seconds
|
|
88
89
|
const CESIUM_DATASET_PREFIX = 'https://';
|
|
89
90
|
// const FS_FILE_TOO_LARGE = 'ERR_FS_FILE_TOO_LARGE';
|
|
91
|
+
const PROGRESS_PHASE1_COUNT = 'phase1-count';
|
|
90
92
|
|
|
91
93
|
/**
|
|
92
94
|
* Converter from 3d-tiles tileset to i3s layer
|
|
@@ -138,15 +140,7 @@ export default class I3SConverter {
|
|
|
138
140
|
meshTopologyTypes: new Set(),
|
|
139
141
|
metadataClasses: new Set()
|
|
140
142
|
};
|
|
141
|
-
|
|
142
|
-
tileCountTotal: number = 0;
|
|
143
|
-
/** Count of tiles already converted plus one (refers to the tile currently being converted) */
|
|
144
|
-
tileCountCurrentlyConverting: number = 0;
|
|
145
|
-
/**
|
|
146
|
-
* The number of digits to appear after decimal point in the string representation of the tile count.
|
|
147
|
-
* It's calculated based on the total count of tiles.
|
|
148
|
-
*/
|
|
149
|
-
numberOfDigitsInPercentage: number = 0;
|
|
143
|
+
progresses: Record<string, Progress> = {};
|
|
150
144
|
|
|
151
145
|
constructor() {
|
|
152
146
|
this.attributeMetadataInfo = new AttributeMetadataInfo();
|
|
@@ -244,6 +238,7 @@ export default class I3SConverter {
|
|
|
244
238
|
inquirer,
|
|
245
239
|
metadataClass
|
|
246
240
|
};
|
|
241
|
+
this.progresses[PROGRESS_PHASE1_COUNT] = new Progress();
|
|
247
242
|
this.compressList = (this.options.instantNodeWriting && []) || null;
|
|
248
243
|
this.validate = Boolean(validate);
|
|
249
244
|
this.Loader = inputUrl.indexOf(CESIUM_DATASET_PREFIX) !== -1 ? CesiumIonLoader : Tiles3DLoader;
|
|
@@ -310,12 +305,9 @@ export default class I3SConverter {
|
|
|
310
305
|
);
|
|
311
306
|
const {meshTopologyTypes, metadataClasses} = this.preprocessData;
|
|
312
307
|
|
|
313
|
-
this.numberOfDigitsInPercentage =
|
|
314
|
-
this.tileCountTotal > 100 ? Math.ceil(Math.log10(this.tileCountTotal)) - 2 : 0;
|
|
315
|
-
|
|
316
308
|
console.log(`------------------------------------------------`);
|
|
317
309
|
console.log(`Preprocess results:`);
|
|
318
|
-
console.log(`Tile count: ${this.
|
|
310
|
+
console.log(`Tile count: ${this.progresses[PROGRESS_PHASE1_COUNT].stepsTotal}`);
|
|
319
311
|
console.log(`glTF mesh topology types: ${Array.from(meshTopologyTypes).join(', ')}`);
|
|
320
312
|
|
|
321
313
|
if (metadataClasses.size) {
|
|
@@ -357,7 +349,7 @@ export default class I3SConverter {
|
|
|
357
349
|
return null;
|
|
358
350
|
}
|
|
359
351
|
if (sourceTile.id) {
|
|
360
|
-
this.
|
|
352
|
+
this.progresses[PROGRESS_PHASE1_COUNT].stepsTotal += 1;
|
|
361
353
|
console.log(`[analyze]: ${sourceTile.id}`); // eslint-disable-line
|
|
362
354
|
}
|
|
363
355
|
|
|
@@ -374,7 +366,6 @@ export default class I3SConverter {
|
|
|
374
366
|
}
|
|
375
367
|
const tilePreprocessData = await analyzeTileContent(tileContent);
|
|
376
368
|
mergePreprocessData(this.preprocessData, tilePreprocessData);
|
|
377
|
-
|
|
378
369
|
return null;
|
|
379
370
|
}
|
|
380
371
|
|
|
@@ -451,7 +442,7 @@ export default class I3SConverter {
|
|
|
451
442
|
obb: boundingVolumes.obb,
|
|
452
443
|
children: []
|
|
453
444
|
});
|
|
454
|
-
|
|
445
|
+
this.progresses[PROGRESS_PHASE1_COUNT].startMonitoring();
|
|
455
446
|
const rootNode = await NodeIndexDocument.createRootNode(boundingVolumes, this);
|
|
456
447
|
await traverseDatasetWith<TraversalConversionProps>(
|
|
457
448
|
sourceRootTile,
|
|
@@ -463,6 +454,7 @@ export default class I3SConverter {
|
|
|
463
454
|
this.finalizeTile.bind(this),
|
|
464
455
|
this.options.maxDepth
|
|
465
456
|
);
|
|
457
|
+
this.progresses[PROGRESS_PHASE1_COUNT].stopMonitoring();
|
|
466
458
|
|
|
467
459
|
this.layers0!.attributeStorageInfo = this.attributeMetadataInfo.attributeStorageInfo;
|
|
468
460
|
this.layers0!.fields = this.attributeMetadataInfo.fields;
|
|
@@ -618,16 +610,8 @@ export default class I3SConverter {
|
|
|
618
610
|
return traversalProps;
|
|
619
611
|
}
|
|
620
612
|
if (sourceTile.id) {
|
|
621
|
-
|
|
622
|
-
this.tileCountCurrentlyConverting++;
|
|
623
|
-
let percentString = '';
|
|
624
|
-
if (this.tileCountTotal) {
|
|
625
|
-
const percent = (this.tileCountCurrentlyConverting / this.tileCountTotal) * 100;
|
|
626
|
-
percentString = ' ' + percent.toFixed(this.numberOfDigitsInPercentage);
|
|
627
|
-
}
|
|
628
|
-
console.log(`[convert${percentString}%]: ${sourceTile.id}`); // eslint-disable-line
|
|
613
|
+
console.log(`[convert]: ${sourceTile.id}`); // eslint-disable-line
|
|
629
614
|
}
|
|
630
|
-
|
|
631
615
|
const {parentNodes, transform} = traversalProps;
|
|
632
616
|
let transformationMatrix: Matrix4 = transform.clone();
|
|
633
617
|
if (sourceTile.transform) {
|
|
@@ -641,6 +625,20 @@ export default class I3SConverter {
|
|
|
641
625
|
transform: transformationMatrix,
|
|
642
626
|
parentNodes: childNodes
|
|
643
627
|
};
|
|
628
|
+
|
|
629
|
+
if (sourceTile.id) {
|
|
630
|
+
this.progresses[PROGRESS_PHASE1_COUNT].stepsDone += 1;
|
|
631
|
+
|
|
632
|
+
let timeRemainingString = 'Calculating time left...';
|
|
633
|
+
const timeRemainingStringBasedOnCount =
|
|
634
|
+
this.progresses[PROGRESS_PHASE1_COUNT].getTimeRemainingString();
|
|
635
|
+
if (timeRemainingStringBasedOnCount) {
|
|
636
|
+
timeRemainingString = `${timeRemainingStringBasedOnCount} left`;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
let percentString = this.progresses[PROGRESS_PHASE1_COUNT].getPercentString();
|
|
640
|
+
console.log(`[converted ${percentString}%, ${timeRemainingString}]: ${sourceTile.id}`); // eslint-disable-line
|
|
641
|
+
}
|
|
644
642
|
return newTraversalProps;
|
|
645
643
|
}
|
|
646
644
|
|
|
@@ -2,15 +2,33 @@ import {join} from 'path';
|
|
|
2
2
|
import {promises as fs} from 'fs';
|
|
3
3
|
import {getAbsoluteFilePath} from './file-utils';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Converts time value to string.
|
|
7
|
+
* @param time - high-resolution real time in a [seconds, nanoseconds] tuple Array, or a value on milliseconds.
|
|
8
|
+
* @returns string representation of the time
|
|
9
|
+
*/
|
|
10
|
+
export function timeConverter(time: number | [number, number]): string {
|
|
11
|
+
if (typeof time === 'number') {
|
|
12
|
+
// time - real time in milli-seconds
|
|
13
|
+
const milliSecondsInSecond = 1e3;
|
|
14
|
+
const timeInSeconds = Math.floor(time / milliSecondsInSecond);
|
|
15
|
+
const milliseconds = time - timeInSeconds * milliSecondsInSecond;
|
|
16
|
+
return timeConverterFromSecondsAndMilliseconds(timeInSeconds, milliseconds);
|
|
17
|
+
} else {
|
|
18
|
+
// time - high-resolution real time in a [seconds, nanoseconds] tuple Array
|
|
19
|
+
const nanoSecondsInMillisecond = 1e6;
|
|
20
|
+
const timeInSeconds = time[0];
|
|
21
|
+
const milliseconds = time[1] / nanoSecondsInMillisecond;
|
|
22
|
+
return timeConverterFromSecondsAndMilliseconds(timeInSeconds, milliseconds);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function timeConverterFromSecondsAndMilliseconds(timeInSeconds: number, milliseconds: number) {
|
|
8
27
|
const hours = Math.floor(timeInSeconds / 3600);
|
|
9
28
|
timeInSeconds = timeInSeconds - hours * 3600;
|
|
10
29
|
const minutes = Math.floor(timeInSeconds / 60);
|
|
11
30
|
timeInSeconds = timeInSeconds - minutes * 60;
|
|
12
31
|
const seconds = Math.floor(timeInSeconds);
|
|
13
|
-
const milliseconds = time[1] / nanoSecondsInMillisecond;
|
|
14
32
|
let result = '';
|
|
15
33
|
|
|
16
34
|
if (hours) {
|